| 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 |