| OLD | NEW |
| (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 #include <openssl/ec.h> | |
| 10 #include <openssl/engine.h> | |
| 11 #include <openssl/err.h> | |
| 12 #include <openssl/evp.h> | |
| 13 #include <openssl/rsa.h> | |
| 14 #include <stdint.h> | |
| 15 | |
| 16 #include <memory> | |
| 17 | |
| 18 #include "base/android/build_info.h" | |
| 19 #include "base/android/scoped_java_ref.h" | |
| 20 #include "base/lazy_instance.h" | |
| 21 #include "base/logging.h" | |
| 22 #include "crypto/openssl_util.h" | |
| 23 #include "net/android/keystore.h" | |
| 24 #include "net/android/legacy_openssl.h" | |
| 25 #include "net/ssl/scoped_openssl_types.h" | |
| 26 #include "net/ssl/ssl_client_cert_type.h" | |
| 27 | |
| 28 // IMPORTANT NOTE: The following code will currently only work when used | |
| 29 // to implement client certificate support with OpenSSL. That's because | |
| 30 // only the signing operations used in this use case are implemented here. | |
| 31 // | |
| 32 // Generally speaking, OpenSSL provides many different ways to sign | |
| 33 // digests. This code doesn't support all these cases, only the ones that | |
| 34 // are required to sign the digest during the OpenSSL handshake for TLS. | |
| 35 // | |
| 36 // The OpenSSL EVP_PKEY type is a generic wrapper around key pairs. | |
| 37 // Internally, it can hold a pointer to a RSA or ECDSA structure, which model | |
| 38 // keypair implementations of each respective crypto algorithm. | |
| 39 // | |
| 40 // The RSA type has a 'method' field pointer to a vtable-like structure | |
| 41 // called a RSA_METHOD. This contains several function pointers that | |
| 42 // correspond to operations on RSA keys (e.g. decode/encode with public | |
| 43 // key, decode/encode with private key, signing, validation), as well as | |
| 44 // a few flags. | |
| 45 // | |
| 46 // For example, the RSA_sign() function will call "method->rsa_sign()" if | |
| 47 // method->rsa_sign is not NULL, otherwise, it will perform a regular | |
| 48 // signing operation using the other fields in the RSA structure (which | |
| 49 // are used to hold the typical modulus / exponent / parameters for the | |
| 50 // key pair). | |
| 51 // | |
| 52 // This source file thus defines a custom RSA_METHOD structure whose | |
| 53 // fields point to static methods used to implement the corresponding | |
| 54 // RSA operation using platform Android APIs. | |
| 55 // | |
| 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 | |
| 58 // methods are called. This is done by storing it in a |KeyExData| structure | |
| 59 // that's referenced by the key using |EX_DATA|. | |
| 60 | |
| 61 using base::android::ScopedJavaGlobalRef; | |
| 62 using base::android::ScopedJavaLocalRef; | |
| 63 | |
| 64 namespace net { | |
| 65 namespace android { | |
| 66 | |
| 67 namespace { | |
| 68 | |
| 69 extern const RSA_METHOD android_rsa_method; | |
| 70 extern const ECDSA_METHOD android_ecdsa_method; | |
| 71 | |
| 72 // KeyExData contains the data that is contained in the EX_DATA of the RSA and | |
| 73 // EC_KEY objects that are created to wrap Android system keys. | |
| 74 struct KeyExData { | |
| 75 // private_key contains a reference to a Java, private-key object. | |
| 76 ScopedJavaGlobalRef<jobject> private_key; | |
| 77 // legacy_rsa, if not NULL, points to an RSA* in the system's OpenSSL (which | |
| 78 // might not be ABI compatible with Chromium). | |
| 79 AndroidRSA* legacy_rsa; | |
| 80 // cached_size contains the "size" of the key. This is the size of the | |
| 81 // modulus (in bytes) for RSA, or the group order size for ECDSA. This | |
| 82 // avoids calling into Java to calculate the size. | |
| 83 size_t cached_size; | |
| 84 }; | |
| 85 | |
| 86 // ExDataDup is called when one of the RSA or EC_KEY objects is duplicated. We | |
| 87 // don't support this and it should never happen. | |
| 88 int ExDataDup(CRYPTO_EX_DATA* to, | |
| 89 const CRYPTO_EX_DATA* from, | |
| 90 void** from_d, | |
| 91 int index, | |
| 92 long argl, | |
| 93 void* argp) { | |
| 94 CHECK_EQ((void*)NULL, *from_d); | |
| 95 return 0; | |
| 96 } | |
| 97 | |
| 98 // ExDataFree is called when one of the RSA or EC_KEY objects is freed. | |
| 99 void ExDataFree(void* parent, | |
| 100 void* ptr, | |
| 101 CRYPTO_EX_DATA* ad, | |
| 102 int index, | |
| 103 long argl, | |
| 104 void* argp) { | |
| 105 // Ensure the global JNI reference created with this wrapper is | |
| 106 // properly destroyed with it. | |
| 107 KeyExData *ex_data = reinterpret_cast<KeyExData*>(ptr); | |
| 108 delete ex_data; | |
| 109 } | |
| 110 | |
| 111 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA by | |
| 112 // forwarding the requested operations to the Java libraries. | |
| 113 class BoringSSLEngine { | |
| 114 public: | |
| 115 BoringSSLEngine() | |
| 116 : rsa_index_(RSA_get_ex_new_index(0 /* argl */, | |
| 117 NULL /* argp */, | |
| 118 NULL /* new_func */, | |
| 119 ExDataDup, | |
| 120 ExDataFree)), | |
| 121 ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, | |
| 122 NULL /* argp */, | |
| 123 NULL /* new_func */, | |
| 124 ExDataDup, | |
| 125 ExDataFree)), | |
| 126 engine_(ENGINE_new()) { | |
| 127 ENGINE_set_RSA_method( | |
| 128 engine_, &android_rsa_method, sizeof(android_rsa_method)); | |
| 129 ENGINE_set_ECDSA_method( | |
| 130 engine_, &android_ecdsa_method, sizeof(android_ecdsa_method)); | |
| 131 } | |
| 132 | |
| 133 int rsa_ex_index() const { return rsa_index_; } | |
| 134 int ec_key_ex_index() const { return ec_key_index_; } | |
| 135 | |
| 136 const ENGINE* engine() const { return engine_; } | |
| 137 | |
| 138 private: | |
| 139 const int rsa_index_; | |
| 140 const int ec_key_index_; | |
| 141 ENGINE* const engine_; | |
| 142 }; | |
| 143 | |
| 144 base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine = | |
| 145 LAZY_INSTANCE_INITIALIZER; | |
| 146 | |
| 147 | |
| 148 // VectorBignumSize returns the number of bytes needed to represent the bignum | |
| 149 // given in |v|, i.e. the length of |v| less any leading zero bytes. | |
| 150 size_t VectorBignumSize(const std::vector<uint8_t>& v) { | |
| 151 size_t size = v.size(); | |
| 152 // Ignore any leading zero bytes. | |
| 153 for (size_t i = 0; i < v.size() && v[i] == 0; i++) { | |
| 154 size--; | |
| 155 } | |
| 156 return size; | |
| 157 } | |
| 158 | |
| 159 KeyExData* RsaGetExData(const RSA* rsa) { | |
| 160 return reinterpret_cast<KeyExData*>( | |
| 161 RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index())); | |
| 162 } | |
| 163 | |
| 164 size_t RsaMethodSize(const RSA *rsa) { | |
| 165 const KeyExData *ex_data = RsaGetExData(rsa); | |
| 166 return ex_data->cached_size; | |
| 167 } | |
| 168 | |
| 169 int RsaMethodEncrypt(RSA* rsa, | |
| 170 size_t* out_len, | |
| 171 uint8_t* out, | |
| 172 size_t max_out, | |
| 173 const uint8_t* in, | |
| 174 size_t in_len, | |
| 175 int padding) { | |
| 176 NOTIMPLEMENTED(); | |
| 177 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 178 return 0; | |
| 179 } | |
| 180 | |
| 181 int RsaMethodSignRaw(RSA* rsa, | |
| 182 size_t* out_len, | |
| 183 uint8_t* out, | |
| 184 size_t max_out, | |
| 185 const uint8_t* in, | |
| 186 size_t in_len, | |
| 187 int padding) { | |
| 188 DCHECK_EQ(RSA_PKCS1_PADDING, padding); | |
| 189 if (padding != RSA_PKCS1_PADDING) { | |
| 190 // TODO(davidben): If we need to, we can implement RSA_NO_PADDING | |
| 191 // by using javax.crypto.Cipher and picking either the | |
| 192 // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as | |
| 193 // appropriate. I believe support for both of these was added in | |
| 194 // the same Android version as the "NONEwithRSA" | |
| 195 // java.security.Signature algorithm, so the same version checks | |
| 196 // for GetRsaLegacyKey should work. | |
| 197 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); | |
| 198 return 0; | |
| 199 } | |
| 200 | |
| 201 // Retrieve private key JNI reference. | |
| 202 const KeyExData *ex_data = RsaGetExData(rsa); | |
| 203 if (!ex_data || !ex_data->private_key.obj()) { | |
| 204 LOG(WARNING) << "Null JNI reference passed to RsaMethodSignRaw!"; | |
| 205 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 206 return 0; | |
| 207 } | |
| 208 | |
| 209 // Pre-4.2 legacy codepath. | |
| 210 if (ex_data->legacy_rsa) { | |
| 211 int ret = ex_data->legacy_rsa->meth->rsa_priv_enc( | |
| 212 in_len, in, out, ex_data->legacy_rsa, ANDROID_RSA_PKCS1_PADDING); | |
| 213 if (ret < 0) { | |
| 214 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!"; | |
| 215 // System OpenSSL will use a separate error queue, so it is still | |
| 216 // necessary to push a new error. | |
| 217 // | |
| 218 // TODO(davidben): It would be good to also clear the system error queue | |
| 219 // if there were some way to convince Java to do it. (Without going | |
| 220 // through Java, it's difficult to get a handle on a system OpenSSL | |
| 221 // function; dlopen loads a second copy.) | |
| 222 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 223 return 0; | |
| 224 } | |
| 225 *out_len = ret; | |
| 226 return 1; | |
| 227 } | |
| 228 | |
| 229 base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len); | |
| 230 std::vector<uint8_t> result; | |
| 231 // For RSA keys, this function behaves as RSA_private_encrypt with | |
| 232 // PKCS#1 padding. | |
| 233 if (!RawSignDigestWithPrivateKey(ex_data->private_key.obj(), from_piece, | |
| 234 &result)) { | |
| 235 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!"; | |
| 236 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 237 return 0; | |
| 238 } | |
| 239 | |
| 240 size_t expected_size = static_cast<size_t>(RSA_size(rsa)); | |
| 241 if (result.size() > expected_size) { | |
| 242 LOG(ERROR) << "RSA Signature size mismatch, actual: " | |
| 243 << result.size() << ", expected <= " << expected_size; | |
| 244 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 245 return 0; | |
| 246 } | |
| 247 | |
| 248 if (max_out < expected_size) { | |
| 249 OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); | |
| 250 return 0; | |
| 251 } | |
| 252 | |
| 253 // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey | |
| 254 // should pad with leading 0s, but if it doesn't, pad the result. | |
| 255 size_t zero_pad = expected_size - result.size(); | |
| 256 memset(out, 0, zero_pad); | |
| 257 memcpy(out + zero_pad, &result[0], result.size()); | |
| 258 *out_len = expected_size; | |
| 259 | |
| 260 return 1; | |
| 261 } | |
| 262 | |
| 263 int RsaMethodDecrypt(RSA* rsa, | |
| 264 size_t* out_len, | |
| 265 uint8_t* out, | |
| 266 size_t max_out, | |
| 267 const uint8_t* in, | |
| 268 size_t in_len, | |
| 269 int padding) { | |
| 270 NOTIMPLEMENTED(); | |
| 271 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 272 return 0; | |
| 273 } | |
| 274 | |
| 275 int RsaMethodVerifyRaw(RSA* rsa, | |
| 276 size_t* out_len, | |
| 277 uint8_t* out, | |
| 278 size_t max_out, | |
| 279 const uint8_t* in, | |
| 280 size_t in_len, | |
| 281 int padding) { | |
| 282 NOTIMPLEMENTED(); | |
| 283 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 284 return 0; | |
| 285 } | |
| 286 | |
| 287 const RSA_METHOD android_rsa_method = { | |
| 288 { | |
| 289 0 /* references */, | |
| 290 1 /* is_static */ | |
| 291 } /* common */, | |
| 292 nullptr /* app_data */, | |
| 293 | |
| 294 nullptr /* init */, | |
| 295 nullptr /* finish */, | |
| 296 RsaMethodSize, | |
| 297 nullptr /* sign */, | |
| 298 nullptr /* verify */, | |
| 299 RsaMethodEncrypt, | |
| 300 RsaMethodSignRaw, | |
| 301 RsaMethodDecrypt, | |
| 302 RsaMethodVerifyRaw, | |
| 303 nullptr /* private_transform */, | |
| 304 nullptr /* mod_exp */, | |
| 305 nullptr /* bn_mod_exp */, | |
| 306 RSA_FLAG_OPAQUE, | |
| 307 nullptr /* keygen */, | |
| 308 nullptr /* multi_prime_keygen */, | |
| 309 nullptr /* supports_digest */, | |
| 310 }; | |
| 311 | |
| 312 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object. | |
| 313 // |private_key| is the JNI reference (local or global) to the object. | |
| 314 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object | |
| 315 // backing |private_key|. This parameter is only used for Android < 4.2 to | |
| 316 // implement key operations not exposed by the platform. | |
| 317 // Returns a new EVP_PKEY on success, NULL otherwise. | |
| 318 // On success, this creates a new global JNI reference to the object | |
| 319 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can | |
| 320 // free |private_key| after the call. | |
| 321 crypto::ScopedEVP_PKEY CreateRsaPkeyWrapper( | |
| 322 jobject private_key, | |
| 323 AndroidRSA* legacy_rsa, | |
| 324 const crypto::OpenSSLErrStackTracer& tracer) { | |
| 325 crypto::ScopedRSA rsa( | |
| 326 RSA_new_method(global_boringssl_engine.Get().engine())); | |
| 327 | |
| 328 std::vector<uint8_t> modulus; | |
| 329 if (!GetRSAKeyModulus(private_key, &modulus)) { | |
| 330 LOG(ERROR) << "Failed to get private key modulus"; | |
| 331 return nullptr; | |
| 332 } | |
| 333 | |
| 334 std::unique_ptr<KeyExData> ex_data(new KeyExData); | |
| 335 ex_data->private_key.Reset(nullptr, private_key); | |
| 336 if (ex_data->private_key.is_null()) { | |
| 337 LOG(ERROR) << "Could not create global JNI reference"; | |
| 338 return nullptr; | |
| 339 } | |
| 340 ex_data->legacy_rsa = legacy_rsa; | |
| 341 ex_data->cached_size = VectorBignumSize(modulus); | |
| 342 | |
| 343 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), | |
| 344 ex_data.release()); | |
| 345 | |
| 346 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 347 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | |
| 348 return nullptr; | |
| 349 return pkey; | |
| 350 } | |
| 351 | |
| 352 // 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 | |
| 354 // 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 | |
| 356 // ENGINE we extract in GetRsaLegacyKey. | |
| 357 // | |
| 358 // In 4.2, this change avoids the problem: | |
| 359 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d
ddbe73ca5cb3d61 | |
| 360 // | |
| 361 // https://crbug.com/381465 | |
| 362 class KeystoreEngineWorkaround { | |
| 363 public: | |
| 364 KeystoreEngineWorkaround() {} | |
| 365 | |
| 366 void LeakEngine(jobject private_key) { | |
| 367 if (!engine_.is_null()) | |
| 368 return; | |
| 369 ScopedJavaLocalRef<jobject> engine = | |
| 370 GetOpenSSLEngineForPrivateKey(private_key); | |
| 371 if (engine.is_null()) { | |
| 372 NOTREACHED(); | |
| 373 return; | |
| 374 } | |
| 375 engine_.Reset(engine); | |
| 376 } | |
| 377 | |
| 378 private: | |
| 379 ScopedJavaGlobalRef<jobject> engine_; | |
| 380 }; | |
| 381 | |
| 382 void LeakEngine(jobject private_key) { | |
| 383 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance = | |
| 384 LAZY_INSTANCE_INITIALIZER; | |
| 385 s_instance.Get().LeakEngine(private_key); | |
| 386 } | |
| 387 | |
| 388 // Creates an EVP_PKEY wrapper corresponding to the RSA key | |
| 389 // |private_key|. Returns nullptr on failure. | |
| 390 crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key) { | |
| 391 const int kAndroid42ApiLevel = 17; | |
| 392 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); | |
| 393 | |
| 394 if (base::android::BuildInfo::GetInstance()->sdk_int() >= | |
| 395 kAndroid42ApiLevel) { | |
| 396 return CreateRsaPkeyWrapper(private_key, nullptr, tracer); | |
| 397 } | |
| 398 | |
| 399 // Route around platform limitation: if Android < 4.2, then | |
| 400 // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the | |
| 401 // system OpenSSL's EVP_PKEY backing this PrivateKey object. | |
| 402 AndroidEVP_PKEY* sys_pkey = | |
| 403 GetOpenSSLSystemHandleForPrivateKey(private_key); | |
| 404 if (sys_pkey == nullptr) | |
| 405 return nullptr; | |
| 406 | |
| 407 if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) { | |
| 408 LOG(ERROR) << "Private key has wrong type!"; | |
| 409 return nullptr; | |
| 410 } | |
| 411 | |
| 412 AndroidRSA* sys_rsa = sys_pkey->pkey.rsa; | |
| 413 if (sys_rsa->engine) { | |
| 414 // |private_key| may not have an engine if the PrivateKey did not come | |
| 415 // from the key store, such as in unit tests. | |
| 416 if (strcmp(sys_rsa->engine->id, "keystore") == 0) { | |
| 417 LeakEngine(private_key); | |
| 418 } else { | |
| 419 NOTREACHED(); | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer); | |
| 424 } | |
| 425 | |
| 426 // Custom ECDSA_METHOD that uses the platform APIs. | |
| 427 // Note that for now, only signing through ECDSA_sign() is really supported. | |
| 428 // all other method pointers are either stubs returning errors, or no-ops. | |
| 429 | |
| 430 jobject EcKeyGetKey(const EC_KEY* ec_key) { | |
| 431 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( | |
| 432 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | |
| 433 return ex_data->private_key.obj(); | |
| 434 } | |
| 435 | |
| 436 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { | |
| 437 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( | |
| 438 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | |
| 439 return ex_data->cached_size; | |
| 440 } | |
| 441 | |
| 442 int EcdsaMethodSign(const uint8_t* digest, | |
| 443 size_t digest_len, | |
| 444 uint8_t* sig, | |
| 445 unsigned int* sig_len, | |
| 446 EC_KEY* ec_key) { | |
| 447 // Retrieve private key JNI reference. | |
| 448 jobject private_key = EcKeyGetKey(ec_key); | |
| 449 if (!private_key) { | |
| 450 LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!"; | |
| 451 return 0; | |
| 452 } | |
| 453 // Sign message with it through JNI. | |
| 454 std::vector<uint8_t> signature; | |
| 455 base::StringPiece digest_sp(reinterpret_cast<const char*>(digest), | |
| 456 digest_len); | |
| 457 if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) { | |
| 458 LOG(WARNING) << "Could not sign message in EcdsaMethodSign!"; | |
| 459 return 0; | |
| 460 } | |
| 461 | |
| 462 // Note: With ECDSA, the actual signature may be smaller than | |
| 463 // ECDSA_size(). | |
| 464 size_t max_expected_size = ECDSA_size(ec_key); | |
| 465 if (signature.size() > max_expected_size) { | |
| 466 LOG(ERROR) << "ECDSA Signature size mismatch, actual: " | |
| 467 << signature.size() << ", expected <= " | |
| 468 << max_expected_size; | |
| 469 return 0; | |
| 470 } | |
| 471 | |
| 472 memcpy(sig, &signature[0], signature.size()); | |
| 473 *sig_len = signature.size(); | |
| 474 return 1; | |
| 475 } | |
| 476 | |
| 477 int EcdsaMethodVerify(const uint8_t* digest, | |
| 478 size_t digest_len, | |
| 479 const uint8_t* sig, | |
| 480 size_t sig_len, | |
| 481 EC_KEY* ec_key) { | |
| 482 NOTIMPLEMENTED(); | |
| 483 OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); | |
| 484 return 0; | |
| 485 } | |
| 486 | |
| 487 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object. | |
| 488 // |private_key| is the JNI reference (local or global) to the object. | |
| 489 // Returns a new EVP_PKEY on success, NULL otherwise. | |
| 490 // On success, this creates a global JNI reference to the object that | |
| 491 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall | |
| 492 // always free |private_key| after the call. | |
| 493 crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) { | |
| 494 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); | |
| 495 crypto::ScopedEC_KEY ec_key( | |
| 496 EC_KEY_new_method(global_boringssl_engine.Get().engine())); | |
| 497 | |
| 498 std::vector<uint8_t> order; | |
| 499 if (!GetECKeyOrder(private_key, &order)) { | |
| 500 LOG(ERROR) << "Can't extract order parameter from EC private key"; | |
| 501 return nullptr; | |
| 502 } | |
| 503 | |
| 504 std::unique_ptr<KeyExData> ex_data(new KeyExData); | |
| 505 ex_data->private_key.Reset(nullptr, private_key); | |
| 506 if (ex_data->private_key.is_null()) { | |
| 507 LOG(ERROR) << "Can't create global JNI reference"; | |
| 508 return nullptr; | |
| 509 } | |
| 510 ex_data->legacy_rsa = nullptr; | |
| 511 ex_data->cached_size = VectorBignumSize(order); | |
| 512 | |
| 513 EC_KEY_set_ex_data(ec_key.get(), | |
| 514 global_boringssl_engine.Get().ec_key_ex_index(), | |
| 515 ex_data.release()); | |
| 516 | |
| 517 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 518 if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) | |
| 519 return nullptr; | |
| 520 return pkey; | |
| 521 } | |
| 522 | |
| 523 const ECDSA_METHOD android_ecdsa_method = { | |
| 524 { | |
| 525 0 /* references */, | |
| 526 1 /* is_static */ | |
| 527 } /* common */, | |
| 528 NULL /* app_data */, | |
| 529 | |
| 530 NULL /* init */, | |
| 531 NULL /* finish */, | |
| 532 EcdsaMethodGroupOrderSize, | |
| 533 EcdsaMethodSign, | |
| 534 EcdsaMethodVerify, | |
| 535 ECDSA_FLAG_OPAQUE, | |
| 536 }; | |
| 537 | |
| 538 } // namespace | |
| 539 | |
| 540 crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) { | |
| 541 // Create sub key type, depending on private key's algorithm type. | |
| 542 PrivateKeyType key_type = GetPrivateKeyType(private_key); | |
| 543 switch (key_type) { | |
| 544 case PRIVATE_KEY_TYPE_RSA: | |
| 545 return GetRsaPkeyWrapper(private_key); | |
| 546 case PRIVATE_KEY_TYPE_ECDSA: | |
| 547 return GetEcdsaPkeyWrapper(private_key); | |
| 548 default: | |
| 549 LOG(WARNING) | |
| 550 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type"; | |
| 551 return nullptr; | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 } // namespace android | |
| 556 } // namespace net | |
| OLD | NEW |