Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: net/android/keystore_openssl.cc

Issue 11571059: Add net/android/keystore.h (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: addressing ryan's remarks. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/android/keystore_openssl.h"
6
7 #include <jni.h>
8 #include <openssl/bn.h>
9 // This include is required to get the ECDSA_METHOD structure definition
10 // which isn't currently part of the OpenSSL official ABI. This should
11 // not be a concern for Chromium which always links against its own
12 // version of the library on Android.
13 #include <openssl/crypto/ecdsa/ecs_locl.h>
14 // And this one is needed for the EC_GROUP definition.
15 #include <openssl/crypto/ec/ec_lcl.h>
16 #include <openssl/dsa.h>
17 #include <openssl/ec.h>
18 #include <openssl/engine.h>
19 #include <openssl/evp.h>
20 #include <openssl/rsa.h>
21
22 #include "base/android/build_info.h"
23 #include "base/android/jni_android.h"
24 #include "base/android/scoped_java_ref.h"
25 #include "base/basictypes.h"
26 #include "base/lazy_instance.h"
27 #include "base/logging.h"
28 #include "crypto/openssl_util.h"
29 #include "net/android/keystore.h"
30 #include "net/base/ssl_client_cert_type.h"
31
32 // IMPORTANT NOTE: The following code will currently only work when used
33 // to implement client certificate support with OpenSSL. That's because
34 // only the signing operations used in this use case are implemented here.
35 //
36 // Generally speaking, OpenSSL provides many different ways to sign
37 // digests. This code doesn't support all these cases, only the ones that
38 // are required to sign the MAC during the OpenSSL handshake for TLS < 1.2.
39 //
40 // The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
41 // Internally, it can hold a pointer to a RSA, DSA or ECDSA structure,
42 // which model keypair implementations of each respective crypto
43 // algorithm.
44 //
45 // The RSA type has a 'method' field pointer to a vtable-like structure
46 // called a RSA_METHOD. This contains several function pointers that
47 // correspond to operations on RSA keys (e.g. decode/encode with public
48 // key, decode/encode with private key, signing, validation), as well as
49 // a few flags.
50 //
51 // For example, the RSA_sign() function will call "method->rsa_sign()" if
52 // method->rsa_sign is not NULL, otherwise, it will perform a regular
53 // signing operation using the other fields in the RSA structure (which
54 // are used to hold the typical modulus / exponent / parameters for the
55 // key pair).
56 //
57 // This source file thus defines a custom RSA_METHOD structure, which
58 // fields points to static methods used to implement the corresponding
59 // RSA operation using platform Android APIs.
60 //
61 // However, the platform APIs require a jobject JNI reference to work.
62 // It must be stored in the RSA instance, or made accessible when the
63 // custom RSA methods are called. This is done by using RSA_set_app_data()
64 // and RSA_get_app_data().
65 //
66 // One can thus _directly_ create a new EVP_PKEY that uses a custom RSA
67 // object with the following:
68 //
69 // RSA* rsa = RSA_new()
70 // RSA_set_method(&custom_rsa_method);
71 // RSA_set_app_data(rsa, jni_private_key);
72 //
73 // EVP_PKEY* pkey = EVP_PKEY_new();
74 // EVP_PKEY_assign_RSA(pkey, rsa);
75 //
76 // Note that because EVP_PKEY_assign_RSA() is used, instead of
77 // EVP_PKEY_set1_RSA(), the new EVP_PKEY now owns the RSA object, and
78 // will destroy it when it is itself destroyed.
79 //
80 // Unfortunately, such objects cannot be used with RSA_size(), which
81 // totally ignores the RSA_METHOD pointers. Instead, it is necessary
82 // to manually setup the modulus field (n) in the RSA object, with a
83 // value that matches the wrapped PrivateKey object. See GetRsaPkeyWrapper
84 // for full details.
85 //
86 // Similarly, custom DSA_METHOD and ECDSA_METHOD are defined by this source
87 // file, and appropriate field setups are performed to ensure that
88 // DSA_size() and ECDSA_size() work properly with the wrapper EVP_PKEY.
89 //
90 // Note that there is no need to define an OpenSSL ENGINE here. These
91 // are objects that can be used to expose custom methods (i.e. either
92 // RSA_METHOD, DSA_METHOD, ECDSA_METHOD, and a large number of other ones
93 // for types not related to this source file), and make them used by
94 // default for a lot of operations. Very fortunately, this is not needed
95 // here, which saves a lot of complexity.
96
97 using base::android::ScopedJavaGlobalRef;
98
99 namespace {
100
101 typedef crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> ScopedEVP_PKEY;
102 typedef crypto::ScopedOpenSSL<RSA, RSA_free> ScopedRSA;
103 typedef crypto::ScopedOpenSSL<DSA, DSA_free> ScopedDSA;
104 typedef crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ScopedEC_KEY;
105 typedef crypto::ScopedOpenSSL<EC_GROUP, EC_GROUP_free> ScopedEC_GROUP;
106
107 // Custom RSA_METHOD that uses the platform APIs.
108 // Note that for now, only signing through RSA_sign() is really supported.
109 // all other method pointers are either stubs returning errors, or no-ops.
110 // See <openssl/rsa.h> for exact declaration of RSA_METHOD.
111
112 int RsaMethodPubEnc(int flen,
113 const unsigned char* from,
114 unsigned char* to,
115 RSA* rsa,
116 int padding) {
117 NOTIMPLEMENTED();
118 RSAerr(RSA_F_RSA_PUBLIC_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
119 return -1;
120 }
121
122 int RsaMethodPubDec(int flen,
123 const unsigned char* from,
124 unsigned char* to,
125 RSA* rsa,
126 int padding) {
127 NOTIMPLEMENTED();
128 RSAerr(RSA_F_RSA_PUBLIC_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
129 return -1;
130 }
131
132 int RsaMethodPrivEnc(int flen,
133 const unsigned char *from,
134 unsigned char *to,
135 RSA *rsa,
136 int padding) {
137 NOTIMPLEMENTED();
138 RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
139 return -1;
140 }
141
142 int RsaMethodPrivDec(int flen,
143 const unsigned char* from,
144 unsigned char* to,
145 RSA* rsa,
146 int padding) {
147 NOTIMPLEMENTED();
148 RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
149 return -1;
150 }
151
152 int RsaMethodInit(RSA* rsa) {
153 // Required to ensure that RsaMethodSign will be called.
154 rsa->flags |= RSA_FLAG_SIGN_VER;
155 return 0;
156 }
157
158 int RsaMethodFinish(RSA* rsa) {
159 // Ensure the global JNI reference is destroyed with this key.
160 jobject key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
161 if (key != NULL) {
162 RSA_set_app_data(rsa, NULL);
163 JNIEnv* env = base::android::AttachCurrentThread();
164 env->DeleteGlobalRef(key);
165 }
166 // Actual return value is ignored by OpenSSL. There are no docs
167 // explaining what this is supposed to be.
168 return 0;
169 }
170
171 int RsaMethodSign(int type,
172 const unsigned char* message,
173 unsigned int message_len,
174 unsigned char* signature,
175 unsigned int* signature_len,
176 const RSA* rsa) {
177 // This is only used for client certificate support, which
178 // will always pass the NID_md5_sha1 |type| value.
179 DCHECK_EQ(NID_md5_sha1, type);
180 if (type != NID_md5_sha1) {
181 RSAerr(RSA_F_RSA_SIGN, RSA_R_UNKNOWN_ALGORITHM_TYPE);
182 return 0;
183 }
184 // Retrieve private key JNI reference.
185 jobject private_key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
186 if (!private_key) {
187 LOG(WARNING) << "Null JNI reference passed to RsaMethodSign!";
188 return 0;
189 }
190 // Sign message with it through JNI.
191 base::StringPiece message_piece(reinterpret_cast<const char*>(message),
192 static_cast<size_t>(message_len));
193 std::vector<uint8> result;
194
195 if (!net::android::RawSignDigestWithPrivateKey(
196 private_key, message_piece, &result)) {
Ryan Sleevi 2013/02/06 22:48:02 This should be +4 from the ( (!...RawSignDigestWit
digit1 2013/02/07 17:05:51 Ok, I didn't realize line continuation indents acc
197 LOG(WARNING) << "Could not sign message in RsaMethodSign!";
198 return 0;
199 }
200
201 size_t expected_size = static_cast<size_t>(RSA_size(rsa));
202 if (result.size() > expected_size) {
203 LOG(ERROR) << "RSA Signature size mismatch, actual: "
204 << result.size() << ", expected <= " << expected_size;
205 return 0;
206 }
207
208 // Copy result to OpenSSL-provided buffer
209 memcpy(signature, &result[0], result.size());
210 *signature_len = static_cast<unsigned int>(result.size());
211 return 1;
212 }
213
214 const RSA_METHOD android_rsa_method = {
215 /* .name = */ "Android signing-only RSA method",
216 /* .rsa_pub_enc = */ RsaMethodPubEnc,
217 /* .rsa_pub_dec = */ RsaMethodPubDec,
218 /* .rsa_priv_enc = */ RsaMethodPrivEnc,
219 /* .rsa_priv_dec = */ RsaMethodPrivDec,
220 /* .rsa_mod_exp = */ NULL,
221 /* .bn_mod_exp = */ NULL,
222 /* .init = */ RsaMethodInit,
223 /* .finish = */ RsaMethodFinish,
224 /* .flags = */ RSA_FLAG_SIGN_VER, // indicates that rsa_sign is usable.
225 /* .app_data = */ NULL,
226 /* .rsa_sign = */ RsaMethodSign,
227 /* .rsa_verify = */ NULL,
228 /* .rsa_keygen = */ NULL,
229 };
230
231 // Copy the contents of an encoded big integer into an existing BIGNUM.
232 // This function modifies |*num| in-place.
233 // |new_bytes| is the byte encoding of the new value.
234 // |num| points to the BIGNUM which will be assigned with the new value.
235 // Returns true on success, false otherwise. On failure, |*num| is
236 // not modified.
237 bool CopyBigNumFromBytes(const std::vector<uint8>& new_bytes,
238 BIGNUM* num) {
239 BIGNUM* ret = BN_bin2bn(
240 reinterpret_cast<const unsigned char*>(&new_bytes[0]),
241 static_cast<int>(new_bytes.size()),
242 num);
243 return (ret != NULL);
244 }
245
246 // Decode the contents of an encoded big integer and either create a new
247 // BIGNUM object (if |*num_ptr| is NULL on input) or copy it (if
248 // |*num_ptr| is not NULL).
249 // |new_bytes| is the byte encoding of the new value.
250 // |num_ptr| is the address of a BIGNUM pointer. |*num_ptr| can be NULL.
251 // Returns true on success, false otherwise. On failure, |*num_ptr| is
252 // not modified. On success, |*num_ptr| will always be non-NULL and
253 // point to a valid BIGNUM object.
254 bool SwapBigNumPtrFromBytes(const std::vector<uint8>& new_bytes,
255 BIGNUM** num_ptr) {
256 BIGNUM* old_num = *num_ptr;
257 BIGNUM* new_num = BN_bin2bn(
258 reinterpret_cast<const unsigned char*>(&new_bytes[0]),
259 static_cast<int>(new_bytes.size()),
260 old_num);
261 if (new_num == NULL)
262 return false;
263
264 if (old_num == NULL)
265 *num_ptr = new_num;
266 return true;
267 }
268
269 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object.
270 // |private_key| is the JNI reference (local or global) to the object.
271 // |pkey| is the EVP_PKEY to setup as a wrapper.
272 // Returns true on success, false otherwise.
273 // On success, this creates a new global JNI reference to the object
274 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can
275 // free |private_key| after the call.
276 // IMPORTANT: The EVP_PKEY will *only* work on Android >= 4.2. For older
277 // platforms, use GetRsaLegacyKey() instead.
278 bool GetRsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
279 ScopedRSA rsa(RSA_new());
280 RSA_set_method(rsa.get(), &android_rsa_method);
281
282 // HACK: RSA_size() doesn't work with custom RSA_METHODs. To ensure that
283 // it will return the right value, set the 'n' field of the RSA object
284 // to match the private key's modulus.
285 std::vector<uint8> modulus;
286 if (!net::android::GetRSAKeyModulus(private_key, &modulus)) {
287 LOG(ERROR) << "Failed to get private key modulus";
288 return false;
289 }
290 if (!SwapBigNumPtrFromBytes(modulus, &rsa.get()->n)) {
291 LOG(ERROR) << "Failed to decode private key modulus";
292 return false;
293 }
294
295 ScopedJavaGlobalRef<jobject> global_key;
296 global_key.Reset(NULL, private_key);
297 if (global_key.is_null()) {
298 LOG(ERROR) << "Could not create global JNI reference";
299 return false;
300 }
301 RSA_set_app_data(rsa.get(), global_key.Release());
302 EVP_PKEY_assign_RSA(pkey, rsa.release());
303 return true;
304 }
305
306 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object
307 // for Android 4.0 to 4.1.x. Must only be used on Android < 4.2.
308 // |private_key| is a JNI reference (local or global) to the object.
309 // |pkey| is the EVP_PKEY to setup as a wrapper.
310 // Returns true on success, false otherwise.
311 EVP_PKEY* GetRsaLegacyKey(jobject private_key) {
312 EVP_PKEY* sys_pkey =
313 net::android::GetOpenSSLSystemHandleForPrivateKey(private_key);
314 if (sys_pkey != NULL) {
315 CRYPTO_add(&sys_pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
316 } else {
317 // GetOpenSSLSystemHandleForPrivateKey() will fail on Android
318 // 4.0.3 and earlier. However, it is possible to get the key
319 // content with PrivateKey.getEncoded() on these platforms.
320 // Note that this method may return NULL on 4.0.4 and later.
321 std::vector<uint8> encoded;
322 if (!net::android::GetPrivateKeyEncodedBytes(private_key, &encoded)) {
323 LOG(ERROR) << "Can't get private key data!";
324 return NULL;
325 }
326 const unsigned char* p =
327 reinterpret_cast<const unsigned char*>(&encoded[0]);
328 int len = static_cast<int>(encoded.size());
329 sys_pkey = d2i_AutoPrivateKey(NULL, &p, len);
330 if (sys_pkey == NULL) {
331 LOG(ERROR) << "Can't convert private key data!";
332 return NULL;
333 }
334 }
335 return sys_pkey;
336 }
337
338 // Custom DSA_METHOD that uses the platform APIs.
339 // Note that for now, only signing through DSA_sign() is really supported.
340 // all other method pointers are either stubs returning errors, or no-ops.
341 // See <openssl/dsa.h> for exact declaration of DSA_METHOD.
342 //
343 // Note: There is no DSA_set_app_data() and DSA_get_app_data() functions,
344 // but RSA_set_app_data() is defined as a simple macro that calls
345 // RSA_set_ex_data() with a hard-coded index of 0, so this code
346 // does the same thing here.
347
348 DSA_SIG* DsaMethodDoSign(const unsigned char* dgst,
349 int dlen,
350 DSA* dsa) {
351 // Extract the JNI reference to the PrivateKey object.
352 jobject private_key = reinterpret_cast<jobject>(DSA_get_ex_data(dsa, 0));
353 if (private_key == NULL)
354 return NULL;
355
356 // Sign the message with it, calling platform APIs.
357 std::vector<uint8> signature;
358 if (!net::android::RawSignDigestWithPrivateKey(
359 private_key,
360 base::StringPiece(
361 reinterpret_cast<const char*>(dgst),
362 static_cast<size_t>(dlen)),
363 &signature)) {
Ryan Sleevi 2013/02/06 22:48:02 Did you fail to upload that change? I don't see it
digit1 2013/02/07 17:05:51 Done.
364 return NULL;
365 }
366
367 // Note: With DSA, the actual signature might be smaller than DSA_size().
368 size_t max_expected_size = static_cast<size_t>(DSA_size(dsa));
369 if (signature.size() > max_expected_size) {
370 LOG(ERROR) << "DSA Signature size mismatch, actual: "
371 << signature.size() << ", expected <= "
372 << max_expected_size;
373 return NULL;
374 }
375
376 // Convert the signature into a DSA_SIG object.
377 const unsigned char* sigbuf =
378 reinterpret_cast<const unsigned char*>(&signature[0]);
379 int siglen = static_cast<size_t>(signature.size());
380 DSA_SIG* dsa_sig = d2i_DSA_SIG(NULL, &sigbuf, siglen);
381 return dsa_sig;
382 }
383
384 int DsaMethodSignSetup(DSA* dsa,
385 BN_CTX* ctx_in,
386 BIGNUM** kinvp,
387 BIGNUM** rp) {
388 NOTIMPLEMENTED();
389 DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_INVALID_DIGEST_TYPE);
390 return -1;
391 }
392
393 int DsaMethodDoVerify(const unsigned char* dgst,
394 int dgst_len,
395 DSA_SIG* sig,
396 DSA* dsa) {
397 NOTIMPLEMENTED();
398 DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_INVALID_DIGEST_TYPE);
399 return -1;
400 }
401
402 int DsaMethodFinish(DSA* dsa) {
403 // Free the global JNI reference.
404 jobject key = reinterpret_cast<jobject>(DSA_get_ex_data(dsa,0));
405 if (key != NULL) {
406 DSA_set_ex_data(dsa, 0, NULL);
407 JNIEnv* env = base::android::AttachCurrentThread();
408 env->DeleteGlobalRef(key);
409 }
410 // Actual return value is ignored by OpenSSL. There are no docs
411 // explaining what this is supposed to be.
412 return 0;
413 }
414
415 const DSA_METHOD android_dsa_method = {
416 /* .name = */ "Android signing-only DSA method",
417 /* .dsa_do_sign = */ DsaMethodDoSign,
418 /* .dsa_sign_setup = */ DsaMethodSignSetup,
419 /* .dsa_do_verify = */ DsaMethodDoVerify,
420 /* .dsa_mod_exp = */ NULL,
421 /* .bn_mod_exp = */ NULL,
422 /* .init = */ NULL, // nothing to do here.
423 /* .finish = */ DsaMethodFinish,
424 /* .flags = */ 0,
425 /* .app_data = */ NULL,
426 /* .dsa_paramgem = */ NULL,
427 /* .dsa_keygen = */ NULL
428 };
429
430 // Setup an EVP_PKEY to wrap an existing DSA platform PrivateKey object.
431 // |private_key| is a JNI reference (local or global) to the object.
432 // |pkey| is the EVP_PKEY to setup as a wrapper.
433 // Returns true on success, false otherwise.
434 // On success, this creates a global JNI reference to the same object
435 // that will be owned by and destroyed with the EVP_PKEY.
436 bool GetDsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
437 ScopedDSA dsa(DSA_new());
438 DSA_set_method(dsa.get(), &android_dsa_method);
439
440 // DSA_size() doesn't work with custom DSA_METHODs. To ensure it
441 // returns the right value, set the 'q' field in the DSA object to
442 // match the parameter from the platform key.
443 std::vector<uint8> q;
444 if (!net::android::GetDSAKeyParamQ(private_key, &q)) {
445 LOG(ERROR) << "Can't extract Q parameter from DSA private key";
446 return false;
447 }
448 if (!SwapBigNumPtrFromBytes(q, &dsa.get()->q)) {
449 LOG(ERROR) << "Can't decode Q parameter from DSA private key";
450 return false;
451 }
452
453 ScopedJavaGlobalRef<jobject> global_key;
454 global_key.Reset(NULL, private_key);
455 if (global_key.is_null()) {
456 LOG(ERROR) << "Could not create global JNI reference";
457 return false;
458 }
459 DSA_set_ex_data(dsa.get(), 0, global_key.Release());
460 EVP_PKEY_assign_DSA(pkey, dsa.release());
461 return true;
462 }
463
464 // Custom ECDSA_METHOD that uses the platform APIs.
465 // Note that for now, only signing through ECDSA_sign() is really supported.
466 // all other method pointers are either stubs returning errors, or no-ops.
467 //
468 // Note: The ECDSA_METHOD structure doesn't have init/finish
469 // methods. As such, the only way to to ensure the global
470 // JNI reference is properly released when the EVP_PKEY is
471 // destroyed is to use a custom EX_DATA type.
472
473 // Used to ensure that the global JNI reference associated with a
474 // custom EC_KEY + ECDSA_METHOD is released when the key is destroyed.
475 void ExDataFree(void* parent,
476 void* ptr,
477 CRYPTO_EX_DATA* ad,
478 int idx,
479 long argl,
480 void* argp) {
481 jobject private_key = reinterpret_cast<jobject>(ptr);
482 if (private_key == NULL)
483 return;
484
485 CRYPTO_set_ex_data(ad, idx, NULL);
486
487 JNIEnv* env = base::android::AttachCurrentThread();
488 env->DeleteGlobalRef(private_key);
489 }
490
491 int ExDataDup(CRYPTO_EX_DATA* to,
492 CRYPTO_EX_DATA* from,
493 void* from_d,
494 int idx,
495 long argl,
496 void* argp) {
497 // This callback shall never be called with the current OpenSSL
498 // implementation (the library only ever duplicates EX_DATA items
499 // for SSL and BIO objects). But provide this to catch regressions
500 // in the future.
501 CHECK(false) << "ExDataDup was called for ECDSA custom key !?";
502 // Return value is currently ignored by OpenSSL.
503 return 0;
504 }
505
506 class EcdsaExDataIndex {
507 public:
508 int ex_data_index() { return ex_data_index_; }
509
510 EcdsaExDataIndex() {
511 ex_data_index_ = ECDSA_get_ex_new_index(0, // argl
512 NULL, // argp
513 NULL, // new_func
514 ExDataDup, // dup_func
515 ExDataFree); // free_func
516 }
517
518 private:
519 int ex_data_index_;
520 };
521
522 // Returns the index of the custom EX_DATA used to store the JNI reference.
523 int EcdsaGetExDataIndex(void) {
524 // Use a LazyInstance to perform thread-safe lazy initialization.
525 // Use a leaky one, since OpenSSL doesn't provide a way to release
526 // allocated EX_DATA indices.
527 static base::LazyInstance<EcdsaExDataIndex>::Leaky s_instance =
528 LAZY_INSTANCE_INITIALIZER;
529 return s_instance.Get().ex_data_index();
530 }
531
532 ECDSA_SIG* EcdsaMethodDoSign(const unsigned char* dgst,
533 int dgst_len,
534 const BIGNUM* inv,
535 const BIGNUM* rp,
536 EC_KEY* eckey) {
537 // Retrieve private key JNI reference.
538 jobject private_key = reinterpret_cast<jobject>(
539 ECDSA_get_ex_data(eckey, EcdsaGetExDataIndex()));
540 if (!private_key) {
541 LOG(WARNING) << "Null JNI reference passed to EcdsaMethodDoSign!";
542 return NULL;
543 }
544 // Sign message with it through JNI.
545 std::vector<uint8> signature;
546 base::StringPiece digest(
547 reinterpret_cast<const char*>(dgst),
548 static_cast<size_t>(dgst_len));
549 if (!net::android::RawSignDigestWithPrivateKey(
550 private_key, digest, &signature)) {
Ryan Sleevi 2013/02/06 22:48:02 still wrong indent. It should be 4 from the if() i
digit1 2013/02/07 17:05:51 Done.
551 LOG(WARNING) << "Could not sign message in EcdsaMethodDoSign!";
552 return NULL;
553 }
554
555 // Note: With ECDSA, the actual signature may be smaller than
556 // ECDSA_size().
557 size_t max_expected_size = static_cast<size_t>(ECDSA_size(eckey));
558 if (signature.size() > max_expected_size) {
559 LOG(ERROR) << "ECDSA Signature size mismatch, actual: "
560 << signature.size() << ", expected <= "
561 << max_expected_size;
562 return NULL;
563 }
564
565 // Convert signature to ECDSA_SIG object
566 const unsigned char* sigbuf =
567 reinterpret_cast<const unsigned char*>(&signature[0]);
568 long siglen = static_cast<long>(signature.size());
569 return d2i_ECDSA_SIG(NULL, &sigbuf, siglen);
570 }
571
572 int EcdsaMethodSignSetup(EC_KEY* eckey,
573 BN_CTX* ctx,
574 BIGNUM** kinv,
575 BIGNUM** r) {
576 NOTIMPLEMENTED();
577 ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_ERR_EC_LIB);
578 return -1;
579 }
580
581 int EcdsaMethodDoVerify(const unsigned char* dgst,
582 int dgst_len,
583 const ECDSA_SIG* sig,
584 EC_KEY* eckey) {
585 NOTIMPLEMENTED();
586 ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_ERR_EC_LIB);
587 return -1;
588 }
589
590 const ECDSA_METHOD android_ecdsa_method = {
591 /* .name = */ "Android signing-only ECDSA method",
592 /* .ecdsa_do_sign = */ EcdsaMethodDoSign,
593 /* .ecdsa_sign_setup = */ EcdsaMethodSignSetup,
594 /* .ecdsa_do_verify = */ EcdsaMethodDoVerify,
595 /* .flags = */ 0,
596 /* .app_data = */ NULL,
597 };
598
599 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
600 // |private_key| is the JNI reference (local or global) to the object.
601 // |pkey| is the EVP_PKEY to setup as a wrapper.
602 // Returns true on success, false otherwise.
603 // On success, this creates a global JNI reference to the object that
604 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
605 // always free |private_key| after the call.
606 bool GetEcdsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
607 ScopedEC_KEY eckey(EC_KEY_new());
608 ECDSA_set_method(eckey.get(), &android_ecdsa_method);
609
610 // To ensure that ECDSA_size() works properly, craft a custom EC_GROUP
611 // that has the same order than the private key.
612 std::vector<uint8> order;
613 if (!net::android::GetECKeyOrder(private_key, &order)) {
614 LOG(ERROR) << "Can't extract order parameter from EC private key";
615 return false;
616 }
617 ScopedEC_GROUP group(EC_GROUP_new(EC_GFp_nist_method()));
618 if (!group.get()) {
619 LOG(ERROR) << "Can't create new EC_GROUP";
620 return false;
621 }
622 if (!CopyBigNumFromBytes(order, &group.get()->order)) {
623 LOG(ERROR) << "Can't decode order from PrivateKey";
624 return false;
625 }
626 EC_KEY_set_group(eckey.get(), group.release());
627
628 ScopedJavaGlobalRef<jobject> global_key;
629 global_key.Reset(NULL, private_key);
630 if (global_key.is_null()) {
631 LOG(ERROR) << "Can't create global JNI reference";
632 return false;
633 }
634 ECDSA_set_ex_data(eckey.get(),
635 EcdsaGetExDataIndex(),
636 global_key.Release());
637
638 EVP_PKEY_assign_EC_KEY(pkey, eckey.release());
639 return true;
640 }
641
642 } // namespace
643
644
645 namespace net {
646 namespace android {
647
648 EVP_PKEY* GetOpenSSLPrivateKeyWrapper(jobject private_key) {
649 // Create new empty EVP_PKEY instance.
650 ScopedEVP_PKEY pkey(EVP_PKEY_new());
651 if (!pkey.get())
652 return NULL;
653
654 // Create sub key type, depending on private key's algorithm type.
655 PrivateKeyType key_type = GetPrivateKeyType(private_key);
656 switch (key_type) {
657 case PRIVATE_KEY_TYPE_RSA:
658 {
659 // Route around platform bug: if Android < 4.2, then
660 // base::android::RawSignDigestWithPrivateKey() cannot work, so
661 // instead, obtain a raw EVP_PKEY* to the system object
662 // backing this PrivateKey object.
663 const int kAndroid42ApiLevel = 17;
664 if (base::android::BuildInfo::GetInstance()->sdk_int() <
665 kAndroid42ApiLevel) {
666 EVP_PKEY* legacy_key = GetRsaLegacyKey(private_key);
667 if (legacy_key == NULL)
668 return NULL;
669 pkey.reset(legacy_key);
670 } else {
671 // Running on Android 4.2.
672 if (!GetRsaPkeyWrapper(private_key, pkey.get()))
673 return NULL;
674 }
675 }
676 break;
677 case PRIVATE_KEY_TYPE_DSA:
678 if (!GetDsaPkeyWrapper(private_key, pkey.get()))
679 return NULL;
680 break;
681 case PRIVATE_KEY_TYPE_ECDSA:
682 if (!GetEcdsaPkeyWrapper(private_key, pkey.get()))
683 return NULL;
684 break;
685 default:
686 LOG(WARNING)
687 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
688 return NULL;
689 }
690 return pkey.release();
691 }
692
693 } // namespace android
694 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698