OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |