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

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

Issue 2301553002: Pass JavaRef to Java methods in net. (Closed)
Patch Set: Created 4 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') | net/android/keystore_unittest.cc » ('j') | 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/ec.h> 9 #include <openssl/ec.h>
10 #include <openssl/engine.h> 10 #include <openssl/engine.h>
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 // 51 //
52 // This source file thus defines a custom RSA_METHOD structure whose 52 // This source file thus defines a custom RSA_METHOD structure whose
53 // fields point to static methods used to implement the corresponding 53 // fields point to static methods used to implement the corresponding
54 // RSA operation using platform Android APIs. 54 // RSA operation using platform Android APIs.
55 // 55 //
56 // However, the platform APIs require a jobject JNI reference to work. It must 56 // However, the platform APIs require a jobject JNI reference to work. It must
57 // be stored in the RSA instance, or made accessible when the custom RSA 57 // be stored in the RSA instance, or made accessible when the custom RSA
58 // methods are called. This is done by storing it in a |KeyExData| structure 58 // methods are called. This is done by storing it in a |KeyExData| structure
59 // that's referenced by the key using |EX_DATA|. 59 // that's referenced by the key using |EX_DATA|.
60 60
61 using base::android::JavaRef;
61 using base::android::ScopedJavaGlobalRef; 62 using base::android::ScopedJavaGlobalRef;
62 using base::android::ScopedJavaLocalRef; 63 using base::android::ScopedJavaLocalRef;
63 64
64 namespace net { 65 namespace net {
65 namespace android { 66 namespace android {
66 67
67 namespace { 68 namespace {
68 69
69 extern const RSA_METHOD android_rsa_method; 70 extern const RSA_METHOD android_rsa_method;
70 extern const ECDSA_METHOD android_ecdsa_method; 71 extern const ECDSA_METHOD android_ecdsa_method;
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 return 0; 223 return 0;
223 } 224 }
224 *out_len = ret; 225 *out_len = ret;
225 return 1; 226 return 1;
226 } 227 }
227 228
228 base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len); 229 base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len);
229 std::vector<uint8_t> result; 230 std::vector<uint8_t> result;
230 // For RSA keys, this function behaves as RSA_private_encrypt with 231 // For RSA keys, this function behaves as RSA_private_encrypt with
231 // PKCS#1 padding. 232 // PKCS#1 padding.
232 if (!RawSignDigestWithPrivateKey(ex_data->private_key.obj(), from_piece, 233 if (!RawSignDigestWithPrivateKey(ex_data->private_key, from_piece, &result)) {
233 &result)) {
234 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!"; 234 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!";
235 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); 235 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
236 return 0; 236 return 0;
237 } 237 }
238 238
239 size_t expected_size = static_cast<size_t>(RSA_size(rsa)); 239 size_t expected_size = static_cast<size_t>(RSA_size(rsa));
240 if (result.size() > expected_size) { 240 if (result.size() > expected_size) {
241 LOG(ERROR) << "RSA Signature size mismatch, actual: " << result.size() 241 LOG(ERROR) << "RSA Signature size mismatch, actual: " << result.size()
242 << ", expected <= " << expected_size; 242 << ", expected <= " << expected_size;
243 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); 243 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object. 310 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object.
311 // |private_key| is the JNI reference (local or global) to the object. 311 // |private_key| is the JNI reference (local or global) to the object.
312 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object 312 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object
313 // backing |private_key|. This parameter is only used for Android < 4.2 to 313 // backing |private_key|. This parameter is only used for Android < 4.2 to
314 // implement key operations not exposed by the platform. 314 // implement key operations not exposed by the platform.
315 // Returns a new EVP_PKEY on success, NULL otherwise. 315 // Returns a new EVP_PKEY on success, NULL otherwise.
316 // On success, this creates a new global JNI reference to the object 316 // On success, this creates a new global JNI reference to the object
317 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can 317 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can
318 // free |private_key| after the call. 318 // free |private_key| after the call.
319 crypto::ScopedEVP_PKEY CreateRsaPkeyWrapper( 319 crypto::ScopedEVP_PKEY CreateRsaPkeyWrapper(
320 jobject private_key, 320 const JavaRef<jobject>& private_key,
321 AndroidRSA* legacy_rsa, 321 AndroidRSA* legacy_rsa,
322 const crypto::OpenSSLErrStackTracer& tracer) { 322 const crypto::OpenSSLErrStackTracer& tracer) {
323 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); 323 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine()));
324 324
325 std::vector<uint8_t> modulus; 325 std::vector<uint8_t> modulus;
326 if (!GetRSAKeyModulus(private_key, &modulus)) { 326 if (!GetRSAKeyModulus(private_key, &modulus)) {
327 LOG(ERROR) << "Failed to get private key modulus"; 327 LOG(ERROR) << "Failed to get private key modulus";
328 return nullptr; 328 return nullptr;
329 } 329 }
330 330
331 std::unique_ptr<KeyExData> ex_data(new KeyExData); 331 std::unique_ptr<KeyExData> ex_data(new KeyExData);
332 ex_data->private_key.Reset(nullptr, private_key); 332 ex_data->private_key.Reset(private_key);
333 if (ex_data->private_key.is_null()) { 333 if (ex_data->private_key.is_null()) {
334 LOG(ERROR) << "Could not create global JNI reference"; 334 LOG(ERROR) << "Could not create global JNI reference";
335 return nullptr; 335 return nullptr;
336 } 336 }
337 ex_data->legacy_rsa = legacy_rsa; 337 ex_data->legacy_rsa = legacy_rsa;
338 ex_data->cached_size = VectorBignumSize(modulus); 338 ex_data->cached_size = VectorBignumSize(modulus);
339 339
340 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), 340 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(),
341 ex_data.release()); 341 ex_data.release());
342 342
(...skipping 10 matching lines...) Expand all
353 // ENGINE we extract in GetRsaLegacyKey. 353 // ENGINE we extract in GetRsaLegacyKey.
354 // 354 //
355 // In 4.2, this change avoids the problem: 355 // In 4.2, this change avoids the problem:
356 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d ddbe73ca5cb3d61 356 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d ddbe73ca5cb3d61
357 // 357 //
358 // https://crbug.com/381465 358 // https://crbug.com/381465
359 class KeystoreEngineWorkaround { 359 class KeystoreEngineWorkaround {
360 public: 360 public:
361 KeystoreEngineWorkaround() {} 361 KeystoreEngineWorkaround() {}
362 362
363 void LeakEngine(jobject private_key) { 363 void LeakEngine(const JavaRef<jobject>& private_key) {
364 if (!engine_.is_null()) 364 if (!engine_.is_null())
365 return; 365 return;
366 ScopedJavaLocalRef<jobject> engine = 366 ScopedJavaLocalRef<jobject> engine =
367 GetOpenSSLEngineForPrivateKey(private_key); 367 GetOpenSSLEngineForPrivateKey(private_key);
368 if (engine.is_null()) { 368 if (engine.is_null()) {
369 NOTREACHED(); 369 NOTREACHED();
370 return; 370 return;
371 } 371 }
372 engine_.Reset(engine); 372 engine_.Reset(engine);
373 } 373 }
374 374
375 private: 375 private:
376 ScopedJavaGlobalRef<jobject> engine_; 376 ScopedJavaGlobalRef<jobject> engine_;
377 }; 377 };
378 378
379 void LeakEngine(jobject private_key) { 379 void LeakEngine(const JavaRef<jobject>& private_key) {
380 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance = 380 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
381 LAZY_INSTANCE_INITIALIZER; 381 LAZY_INSTANCE_INITIALIZER;
382 s_instance.Get().LeakEngine(private_key); 382 s_instance.Get().LeakEngine(private_key);
383 } 383 }
384 384
385 // Creates an EVP_PKEY wrapper corresponding to the RSA key 385 // Creates an EVP_PKEY wrapper corresponding to the RSA key
386 // |private_key|. Returns nullptr on failure. 386 // |private_key|. Returns nullptr on failure.
387 crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key) { 387 crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(const JavaRef<jobject>& private_key) {
388 const int kAndroid42ApiLevel = 17; 388 const int kAndroid42ApiLevel = 17;
389 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); 389 crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
390 390
391 if (base::android::BuildInfo::GetInstance()->sdk_int() >= 391 if (base::android::BuildInfo::GetInstance()->sdk_int() >=
392 kAndroid42ApiLevel) { 392 kAndroid42ApiLevel) {
393 return CreateRsaPkeyWrapper(private_key, nullptr, tracer); 393 return CreateRsaPkeyWrapper(private_key, nullptr, tracer);
394 } 394 }
395 395
396 // Route around platform limitation: if Android < 4.2, then 396 // Route around platform limitation: if Android < 4.2, then
397 // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the 397 // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the
(...skipping 18 matching lines...) Expand all
416 } 416 }
417 } 417 }
418 418
419 return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer); 419 return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer);
420 } 420 }
421 421
422 // Custom ECDSA_METHOD that uses the platform APIs. 422 // Custom ECDSA_METHOD that uses the platform APIs.
423 // Note that for now, only signing through ECDSA_sign() is really supported. 423 // Note that for now, only signing through ECDSA_sign() is really supported.
424 // all other method pointers are either stubs returning errors, or no-ops. 424 // all other method pointers are either stubs returning errors, or no-ops.
425 425
426 jobject EcKeyGetKey(const EC_KEY* ec_key) { 426 const JavaRef<jobject>& EcKeyGetKey(const EC_KEY* ec_key) {
427 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( 427 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
428 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); 428 ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
429 return ex_data->private_key.obj(); 429 return ex_data->private_key;
430 } 430 }
431 431
432 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { 432 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
433 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( 433 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
434 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); 434 ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
435 return ex_data->cached_size; 435 return ex_data->cached_size;
436 } 436 }
437 437
438 int EcdsaMethodSign(const uint8_t* digest, 438 int EcdsaMethodSign(const uint8_t* digest,
439 size_t digest_len, 439 size_t digest_len,
440 uint8_t* sig, 440 uint8_t* sig,
441 unsigned int* sig_len, 441 unsigned int* sig_len,
442 EC_KEY* ec_key) { 442 EC_KEY* ec_key) {
443 // Retrieve private key JNI reference. 443 // Retrieve private key JNI reference.
444 jobject private_key = EcKeyGetKey(ec_key); 444 const JavaRef<jobject>& private_key = EcKeyGetKey(ec_key);
445 if (!private_key) { 445 if (private_key.is_null()) {
446 LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!"; 446 LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!";
447 return 0; 447 return 0;
448 } 448 }
449 // Sign message with it through JNI. 449 // Sign message with it through JNI.
450 std::vector<uint8_t> signature; 450 std::vector<uint8_t> signature;
451 base::StringPiece digest_sp(reinterpret_cast<const char*>(digest), 451 base::StringPiece digest_sp(reinterpret_cast<const char*>(digest),
452 digest_len); 452 digest_len);
453 if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) { 453 if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) {
454 LOG(WARNING) << "Could not sign message in EcdsaMethodSign!"; 454 LOG(WARNING) << "Could not sign message in EcdsaMethodSign!";
455 return 0; 455 return 0;
(...skipping 22 matching lines...) Expand all
478 OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); 478 OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
479 return 0; 479 return 0;
480 } 480 }
481 481
482 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object. 482 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
483 // |private_key| is the JNI reference (local or global) to the object. 483 // |private_key| is the JNI reference (local or global) to the object.
484 // Returns a new EVP_PKEY on success, NULL otherwise. 484 // Returns a new EVP_PKEY on success, NULL otherwise.
485 // On success, this creates a global JNI reference to the object that 485 // On success, this creates a global JNI reference to the object that
486 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall 486 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
487 // always free |private_key| after the call. 487 // always free |private_key| after the call.
488 crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) { 488 crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(
489 const JavaRef<jobject>& private_key) {
489 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); 490 crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
490 crypto::ScopedEC_KEY ec_key( 491 crypto::ScopedEC_KEY ec_key(
491 EC_KEY_new_method(global_boringssl_engine.Get().engine())); 492 EC_KEY_new_method(global_boringssl_engine.Get().engine()));
492 493
493 std::vector<uint8_t> order; 494 std::vector<uint8_t> order;
494 if (!GetECKeyOrder(private_key, &order)) { 495 if (!GetECKeyOrder(private_key, &order)) {
495 LOG(ERROR) << "Can't extract order parameter from EC private key"; 496 LOG(ERROR) << "Can't extract order parameter from EC private key";
496 return nullptr; 497 return nullptr;
497 } 498 }
498 499
499 std::unique_ptr<KeyExData> ex_data(new KeyExData); 500 std::unique_ptr<KeyExData> ex_data(new KeyExData);
500 ex_data->private_key.Reset(nullptr, private_key); 501 ex_data->private_key.Reset(private_key);
501 if (ex_data->private_key.is_null()) { 502 if (ex_data->private_key.is_null()) {
502 LOG(ERROR) << "Can't create global JNI reference"; 503 LOG(ERROR) << "Can't create global JNI reference";
503 return nullptr; 504 return nullptr;
504 } 505 }
505 ex_data->legacy_rsa = nullptr; 506 ex_data->legacy_rsa = nullptr;
506 ex_data->cached_size = VectorBignumSize(order); 507 ex_data->cached_size = VectorBignumSize(order);
507 508
508 EC_KEY_set_ex_data(ec_key.get(), 509 EC_KEY_set_ex_data(ec_key.get(),
509 global_boringssl_engine.Get().ec_key_ex_index(), 510 global_boringssl_engine.Get().ec_key_ex_index(),
510 ex_data.release()); 511 ex_data.release());
(...skipping 13 matching lines...) Expand all
524 NULL /* init */, 525 NULL /* init */,
525 NULL /* finish */, 526 NULL /* finish */,
526 EcdsaMethodGroupOrderSize, 527 EcdsaMethodGroupOrderSize,
527 EcdsaMethodSign, 528 EcdsaMethodSign,
528 EcdsaMethodVerify, 529 EcdsaMethodVerify,
529 ECDSA_FLAG_OPAQUE, 530 ECDSA_FLAG_OPAQUE,
530 }; 531 };
531 532
532 } // namespace 533 } // namespace
533 534
534 crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) { 535 crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(
536 const JavaRef<jobject>& private_key) {
535 // Create sub key type, depending on private key's algorithm type. 537 // Create sub key type, depending on private key's algorithm type.
536 PrivateKeyType key_type = GetPrivateKeyType(private_key); 538 PrivateKeyType key_type = GetPrivateKeyType(private_key);
537 switch (key_type) { 539 switch (key_type) {
538 case PRIVATE_KEY_TYPE_RSA: 540 case PRIVATE_KEY_TYPE_RSA:
539 return GetRsaPkeyWrapper(private_key); 541 return GetRsaPkeyWrapper(private_key);
540 case PRIVATE_KEY_TYPE_ECDSA: 542 case PRIVATE_KEY_TYPE_ECDSA:
541 return GetEcdsaPkeyWrapper(private_key); 543 return GetEcdsaPkeyWrapper(private_key);
542 default: 544 default:
543 LOG(WARNING) 545 LOG(WARNING)
544 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type"; 546 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
545 return nullptr; 547 return nullptr;
546 } 548 }
547 } 549 }
548 550
549 } // namespace android 551 } // namespace android
550 } // namespace net 552 } // namespace net
OLDNEW
« no previous file with comments | « net/android/keystore_openssl.h ('k') | net/android/keystore_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698