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

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

Issue 553223002: Use ScopedEVP_PKEY in keystore_openssl.cc. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 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
« no previous file with comments | « net/android/keystore_openssl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/android/keystore_openssl.h" 5 #include "net/android/keystore_openssl.h"
6 6
7 #include <jni.h> 7 #include <jni.h>
8 #include <openssl/bn.h> 8 #include <openssl/bn.h>
9 #include <openssl/dsa.h> 9 #include <openssl/dsa.h>
10 #include <openssl/ec.h> 10 #include <openssl/ec.h>
11 #include <openssl/engine.h> 11 #include <openssl/engine.h>
12 #include <openssl/err.h> 12 #include <openssl/err.h>
13 #include <openssl/evp.h> 13 #include <openssl/evp.h>
14 #include <openssl/rsa.h> 14 #include <openssl/rsa.h>
15 15
16 #include "base/android/build_info.h" 16 #include "base/android/build_info.h"
17 #include "base/android/jni_android.h" 17 #include "base/android/jni_android.h"
18 #include "base/android/scoped_java_ref.h" 18 #include "base/android/scoped_java_ref.h"
19 #include "base/basictypes.h" 19 #include "base/basictypes.h"
20 #include "base/lazy_instance.h" 20 #include "base/lazy_instance.h"
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "crypto/openssl_util.h" 22 #include "crypto/openssl_util.h"
23 #include "crypto/scoped_openssl_types.h"
24 #include "net/android/keystore.h" 23 #include "net/android/keystore.h"
25 #include "net/android/legacy_openssl.h" 24 #include "net/android/legacy_openssl.h"
26 #include "net/ssl/ssl_client_cert_type.h" 25 #include "net/ssl/ssl_client_cert_type.h"
27 26
28 // IMPORTANT NOTE: The following code will currently only work when used 27 // IMPORTANT NOTE: The following code will currently only work when used
29 // to implement client certificate support with OpenSSL. That's because 28 // to implement client certificate support with OpenSSL. That's because
30 // only the signing operations used in this use case are implemented here. 29 // only the signing operations used in this use case are implemented here.
31 // 30 //
32 // Generally speaking, OpenSSL provides many different ways to sign 31 // Generally speaking, OpenSSL provides many different ways to sign
33 // digests. This code doesn't support all these cases, only the ones that 32 // digests. This code doesn't support all these cases, only the ones that
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 NULL /* bn_mod_exp */, 307 NULL /* bn_mod_exp */,
309 RSA_FLAG_OPAQUE, 308 RSA_FLAG_OPAQUE,
310 NULL /* keygen */, 309 NULL /* keygen */,
311 }; 310 };
312 311
313 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object. 312 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object.
314 // |private_key| is the JNI reference (local or global) to the object. 313 // |private_key| is the JNI reference (local or global) to the object.
315 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object 314 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object
316 // backing |private_key|. This parameter is only used for Android < 4.2 to 315 // backing |private_key|. This parameter is only used for Android < 4.2 to
317 // implement key operations not exposed by the platform. 316 // implement key operations not exposed by the platform.
318 // |pkey| is the EVP_PKEY to setup as a wrapper. 317 // Returns a new EVP_PKEY on success, NULL otherwise.
319 // Returns true on success, false otherwise.
320 // On success, this creates a new global JNI reference to the object 318 // On success, this creates a new global JNI reference to the object
321 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can 319 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can
322 // free |private_key| after the call. 320 // free |private_key| after the call.
323 bool GetRsaPkeyWrapper(jobject private_key, 321 crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key,
324 AndroidRSA* legacy_rsa, 322 AndroidRSA* legacy_rsa) {
325 EVP_PKEY* pkey) {
326 crypto::ScopedRSA rsa( 323 crypto::ScopedRSA rsa(
327 RSA_new_method(global_boringssl_engine.Get().engine())); 324 RSA_new_method(global_boringssl_engine.Get().engine()));
328 325
329 ScopedJavaGlobalRef<jobject> global_key; 326 ScopedJavaGlobalRef<jobject> global_key;
330 global_key.Reset(NULL, private_key); 327 global_key.Reset(NULL, private_key);
331 if (global_key.is_null()) { 328 if (global_key.is_null()) {
332 LOG(ERROR) << "Could not create global JNI reference"; 329 LOG(ERROR) << "Could not create global JNI reference";
333 return false; 330 return crypto::ScopedEVP_PKEY();
334 } 331 }
335 332
336 std::vector<uint8> modulus; 333 std::vector<uint8> modulus;
337 if (!GetRSAKeyModulus(private_key, &modulus)) { 334 if (!GetRSAKeyModulus(private_key, &modulus)) {
338 LOG(ERROR) << "Failed to get private key modulus"; 335 LOG(ERROR) << "Failed to get private key modulus";
339 return false; 336 return crypto::ScopedEVP_PKEY();
340 } 337 }
341 338
342 KeyExData* ex_data = new KeyExData; 339 KeyExData* ex_data = new KeyExData;
343 ex_data->private_key = global_key.Release(); 340 ex_data->private_key = global_key.Release();
344 ex_data->legacy_rsa = legacy_rsa; 341 ex_data->legacy_rsa = legacy_rsa;
345 ex_data->cached_size = VectorBignumSize(modulus); 342 ex_data->cached_size = VectorBignumSize(modulus);
346 RSA_set_ex_data( 343 RSA_set_ex_data(
347 rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), ex_data); 344 rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), ex_data);
348 EVP_PKEY_assign_RSA(pkey, rsa.release()); 345
349 return true; 346 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
347 if (!pkey ||
348 !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) {
davidben 2014/09/09 23:07:19 It doesn't really matter because EVP_PKEY_set1_RSA
349 return crypto::ScopedEVP_PKEY();
350 }
351 return pkey.Pass();
350 } 352 }
351 353
352 // On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not 354 // On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
353 // added to the global engine list. If all references to it are dropped, OpenSSL 355 // added to the global engine list. If all references to it are dropped, OpenSSL
354 // will dlclose the module, leaving a dangling function pointer in the RSA 356 // will dlclose the module, leaving a dangling function pointer in the RSA
355 // CRYPTO_EX_DATA class. To work around this, leak an extra reference to the 357 // CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
356 // ENGINE we extract in GetRsaLegacyKey. 358 // ENGINE we extract in GetRsaLegacyKey.
357 // 359 //
358 // In 4.2, this change avoids the problem: 360 // In 4.2, this change avoids the problem:
359 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d ddbe73ca5cb3d61 361 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d ddbe73ca5cb3d61
(...skipping 23 matching lines...) Expand all
383 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance = 385 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
384 LAZY_INSTANCE_INITIALIZER; 386 LAZY_INSTANCE_INITIALIZER;
385 s_instance.Get().LeakEngine(private_key); 387 s_instance.Get().LeakEngine(private_key);
386 } 388 }
387 389
388 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object 390 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object
389 // for Android 4.0 to 4.1.x. Must only be used on Android < 4.2. 391 // for Android 4.0 to 4.1.x. Must only be used on Android < 4.2.
390 // |private_key| is a JNI reference (local or global) to the object. 392 // |private_key| is a JNI reference (local or global) to the object.
391 // |pkey| is the EVP_PKEY to setup as a wrapper. 393 // |pkey| is the EVP_PKEY to setup as a wrapper.
392 // Returns true on success, false otherwise. 394 // Returns true on success, false otherwise.
393 EVP_PKEY* GetRsaLegacyKey(jobject private_key) { 395 crypto::ScopedEVP_PKEY GetRsaLegacyKey(jobject private_key) {
394 AndroidEVP_PKEY* sys_pkey = 396 AndroidEVP_PKEY* sys_pkey =
395 GetOpenSSLSystemHandleForPrivateKey(private_key); 397 GetOpenSSLSystemHandleForPrivateKey(private_key);
396 if (sys_pkey != NULL) { 398 if (sys_pkey != NULL) {
397 if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) { 399 if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) {
398 LOG(ERROR) << "Private key has wrong type!"; 400 LOG(ERROR) << "Private key has wrong type!";
399 return NULL; 401 return crypto::ScopedEVP_PKEY();
400 } 402 }
401 403
402 AndroidRSA* sys_rsa = sys_pkey->pkey.rsa; 404 AndroidRSA* sys_rsa = sys_pkey->pkey.rsa;
403 if (sys_rsa->engine) { 405 if (sys_rsa->engine) {
404 // |private_key| may not have an engine if the PrivateKey did not come 406 // |private_key| may not have an engine if the PrivateKey did not come
405 // from the key store, such as in unit tests. 407 // from the key store, such as in unit tests.
406 if (strcmp(sys_rsa->engine->id, "keystore") == 0) { 408 if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
407 LeakEngine(private_key); 409 LeakEngine(private_key);
408 } else { 410 } else {
409 NOTREACHED(); 411 NOTREACHED();
410 } 412 }
411 } 413 }
412 414
413 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); 415 return GetRsaPkeyWrapper(private_key, sys_rsa);
414 if (!GetRsaPkeyWrapper(private_key, sys_rsa, pkey.get()))
415 return NULL;
416 return pkey.release();
417 } 416 }
418 417
419 // GetOpenSSLSystemHandleForPrivateKey() will fail on Android 4.0.3 and 418 // GetOpenSSLSystemHandleForPrivateKey() will fail on Android 4.0.3 and
420 // earlier. However, it is possible to get the key content with 419 // earlier. However, it is possible to get the key content with
421 // PrivateKey.getEncoded() on these platforms. Note that this method may 420 // PrivateKey.getEncoded() on these platforms. Note that this method may
422 // return NULL on 4.0.4 and later. 421 // return NULL on 4.0.4 and later.
423 std::vector<uint8> encoded; 422 std::vector<uint8> encoded;
424 if (!GetPrivateKeyEncodedBytes(private_key, &encoded)) { 423 if (!GetPrivateKeyEncodedBytes(private_key, &encoded)) {
425 LOG(ERROR) << "Can't get private key data!"; 424 LOG(ERROR) << "Can't get private key data!";
426 return NULL; 425 return crypto::ScopedEVP_PKEY();
427 } 426 }
428 const unsigned char* p = 427 const unsigned char* p =
429 reinterpret_cast<const unsigned char*>(&encoded[0]); 428 reinterpret_cast<const unsigned char*>(&encoded[0]);
430 int len = static_cast<int>(encoded.size()); 429 int len = static_cast<int>(encoded.size());
431 EVP_PKEY* pkey = d2i_AutoPrivateKey(NULL, &p, len); 430 crypto::ScopedEVP_PKEY pkey(d2i_AutoPrivateKey(NULL, &p, len));
432 if (pkey == NULL) { 431 if (!pkey) {
433 LOG(ERROR) << "Can't convert private key data!"; 432 LOG(ERROR) << "Can't convert private key data!";
434 return NULL; 433 return crypto::ScopedEVP_PKEY();
435 } 434 }
436 return pkey; 435 return pkey.Pass();
437 } 436 }
438 437
439 // Custom ECDSA_METHOD that uses the platform APIs. 438 // Custom ECDSA_METHOD that uses the platform APIs.
440 // Note that for now, only signing through ECDSA_sign() is really supported. 439 // Note that for now, only signing through ECDSA_sign() is really supported.
441 // all other method pointers are either stubs returning errors, or no-ops. 440 // all other method pointers are either stubs returning errors, or no-ops.
442 441
443 jobject EcKeyGetKey(const EC_KEY* ec_key) { 442 jobject EcKeyGetKey(const EC_KEY* ec_key) {
444 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( 443 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
445 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); 444 ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
446 return ex_data->private_key; 445 return ex_data->private_key;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 const uint8_t* sig, 491 const uint8_t* sig,
493 size_t sig_len, 492 size_t sig_len,
494 EC_KEY* ec_key) { 493 EC_KEY* ec_key) {
495 NOTIMPLEMENTED(); 494 NOTIMPLEMENTED();
496 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED); 495 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
497 return 0; 496 return 0;
498 } 497 }
499 498
500 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object. 499 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
501 // |private_key| is the JNI reference (local or global) to the object. 500 // |private_key| is the JNI reference (local or global) to the object.
502 // |pkey| is the EVP_PKEY to setup as a wrapper. 501 // Returns a new EVP_PKEY on success, NULL otherwise.
503 // Returns true on success, false otherwise.
504 // On success, this creates a global JNI reference to the object that 502 // On success, this creates a global JNI reference to the object that
505 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall 503 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
506 // always free |private_key| after the call. 504 // always free |private_key| after the call.
507 bool GetEcdsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) { 505 crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) {
508 crypto::ScopedEC_KEY ec_key( 506 crypto::ScopedEC_KEY ec_key(
509 EC_KEY_new_method(global_boringssl_engine.Get().engine())); 507 EC_KEY_new_method(global_boringssl_engine.Get().engine()));
510 508
511 ScopedJavaGlobalRef<jobject> global_key; 509 ScopedJavaGlobalRef<jobject> global_key;
512 global_key.Reset(NULL, private_key); 510 global_key.Reset(NULL, private_key);
513 if (global_key.is_null()) { 511 if (global_key.is_null()) {
514 LOG(ERROR) << "Can't create global JNI reference"; 512 LOG(ERROR) << "Can't create global JNI reference";
515 return false; 513 return crypto::ScopedEVP_PKEY();
516 } 514 }
517 515
518 std::vector<uint8> order; 516 std::vector<uint8> order;
519 if (!GetECKeyOrder(private_key, &order)) { 517 if (!GetECKeyOrder(private_key, &order)) {
520 LOG(ERROR) << "Can't extract order parameter from EC private key"; 518 LOG(ERROR) << "Can't extract order parameter from EC private key";
521 return false; 519 return crypto::ScopedEVP_PKEY();
522 } 520 }
523 521
524 KeyExData* ex_data = new KeyExData; 522 KeyExData* ex_data = new KeyExData;
525 ex_data->private_key = global_key.Release(); 523 ex_data->private_key = global_key.Release();
526 ex_data->legacy_rsa = NULL; 524 ex_data->legacy_rsa = NULL;
527 ex_data->cached_size = VectorBignumSize(order); 525 ex_data->cached_size = VectorBignumSize(order);
528 526
529 EC_KEY_set_ex_data( 527 EC_KEY_set_ex_data(
530 ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(), ex_data); 528 ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(), ex_data);
531 529
532 EVP_PKEY_assign_EC_KEY(pkey, ec_key.release()); 530 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
533 return true; 531 if (!pkey ||
532 !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) {
533 return crypto::ScopedEVP_PKEY();
534 }
535 return pkey.Pass();
534 } 536 }
535 537
536 const ECDSA_METHOD android_ecdsa_method = { 538 const ECDSA_METHOD android_ecdsa_method = {
537 { 539 {
538 0 /* references */, 540 0 /* references */,
539 1 /* is_static */ 541 1 /* is_static */
540 } /* common */, 542 } /* common */,
541 NULL /* app_data */, 543 NULL /* app_data */,
542 544
543 NULL /* init */, 545 NULL /* init */,
544 NULL /* finish */, 546 NULL /* finish */,
545 EcdsaMethodGroupOrderSize, 547 EcdsaMethodGroupOrderSize,
546 EcdsaMethodSign, 548 EcdsaMethodSign,
547 EcdsaMethodVerify, 549 EcdsaMethodVerify,
548 ECDSA_FLAG_OPAQUE, 550 ECDSA_FLAG_OPAQUE,
549 }; 551 };
550 552
551 } // namespace 553 } // namespace
552 554
553 EVP_PKEY* GetOpenSSLPrivateKeyWrapper(jobject private_key) { 555 crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) {
554 // Create new empty EVP_PKEY instance. 556 const int kAndroid42ApiLevel = 17;
555 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
556 if (!pkey.get())
557 return NULL;
558 557
559 // Create sub key type, depending on private key's algorithm type. 558 // Create sub key type, depending on private key's algorithm type.
560 PrivateKeyType key_type = GetPrivateKeyType(private_key); 559 PrivateKeyType key_type = GetPrivateKeyType(private_key);
561 switch (key_type) { 560 switch (key_type) {
562 case PRIVATE_KEY_TYPE_RSA: 561 case PRIVATE_KEY_TYPE_RSA:
563 { 562 // Route around platform bug: if Android < 4.2, then
564 // Route around platform bug: if Android < 4.2, then 563 // base::android::RawSignDigestWithPrivateKey() cannot work, so
565 // base::android::RawSignDigestWithPrivateKey() cannot work, so 564 // instead, obtain a raw EVP_PKEY* to the system object
566 // instead, obtain a raw EVP_PKEY* to the system object 565 // backing this PrivateKey object.
567 // backing this PrivateKey object. 566 if (base::android::BuildInfo::GetInstance()->sdk_int() <
568 const int kAndroid42ApiLevel = 17; 567 kAndroid42ApiLevel) {
569 if (base::android::BuildInfo::GetInstance()->sdk_int() < 568 return GetRsaLegacyKey(private_key);
570 kAndroid42ApiLevel) { 569 } else {
571 EVP_PKEY* legacy_key = GetRsaLegacyKey(private_key); 570 // Running on Android 4.2.
572 if (legacy_key == NULL) 571 return GetRsaPkeyWrapper(private_key, NULL);
573 return NULL;
574 pkey.reset(legacy_key);
575 } else {
576 // Running on Android 4.2.
577 if (!GetRsaPkeyWrapper(private_key, NULL, pkey.get()))
578 return NULL;
579 }
580 } 572 }
581 break;
582 case PRIVATE_KEY_TYPE_ECDSA: 573 case PRIVATE_KEY_TYPE_ECDSA:
583 if (!GetEcdsaPkeyWrapper(private_key, pkey.get())) 574 return GetEcdsaPkeyWrapper(private_key);
584 return NULL;
585 break;
586 default: 575 default:
587 LOG(WARNING) 576 LOG(WARNING)
588 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type"; 577 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
589 return NULL; 578 return crypto::ScopedEVP_PKEY();
590 } 579 }
591 return pkey.release();
592 } 580 }
593 581
594 } // namespace android 582 } // namespace android
595 } // namespace net 583 } // namespace net
OLDNEW
« no previous file with comments | « net/android/keystore_openssl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698