| 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(engine_, &android_rsa_method, | |
| 128 sizeof(android_rsa_method)); | |
| 129 ENGINE_set_ECDSA_method(engine_, &android_ecdsa_method, | |
| 130 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 // VectorBignumSize returns the number of bytes needed to represent the bignum | |
| 148 // given in |v|, i.e. the length of |v| less any leading zero bytes. | |
| 149 size_t VectorBignumSize(const std::vector<uint8_t>& v) { | |
| 150 size_t size = v.size(); | |
| 151 // Ignore any leading zero bytes. | |
| 152 for (size_t i = 0; i < v.size() && v[i] == 0; i++) { | |
| 153 size--; | |
| 154 } | |
| 155 return size; | |
| 156 } | |
| 157 | |
| 158 KeyExData* RsaGetExData(const RSA* rsa) { | |
| 159 return reinterpret_cast<KeyExData*>( | |
| 160 RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index())); | |
| 161 } | |
| 162 | |
| 163 size_t RsaMethodSize(const RSA* rsa) { | |
| 164 const KeyExData* ex_data = RsaGetExData(rsa); | |
| 165 return ex_data->cached_size; | |
| 166 } | |
| 167 | |
| 168 int RsaMethodEncrypt(RSA* rsa, | |
| 169 size_t* out_len, | |
| 170 uint8_t* out, | |
| 171 size_t max_out, | |
| 172 const uint8_t* in, | |
| 173 size_t in_len, | |
| 174 int padding) { | |
| 175 NOTIMPLEMENTED(); | |
| 176 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 177 return 0; | |
| 178 } | |
| 179 | |
| 180 int RsaMethodSignRaw(RSA* rsa, | |
| 181 size_t* out_len, | |
| 182 uint8_t* out, | |
| 183 size_t max_out, | |
| 184 const uint8_t* in, | |
| 185 size_t in_len, | |
| 186 int padding) { | |
| 187 DCHECK_EQ(RSA_PKCS1_PADDING, padding); | |
| 188 if (padding != RSA_PKCS1_PADDING) { | |
| 189 // TODO(davidben): If we need to, we can implement RSA_NO_PADDING | |
| 190 // by using javax.crypto.Cipher and picking either the | |
| 191 // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as | |
| 192 // appropriate. I believe support for both of these was added in | |
| 193 // the same Android version as the "NONEwithRSA" | |
| 194 // java.security.Signature algorithm, so the same version checks | |
| 195 // for GetRsaLegacyKey should work. | |
| 196 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); | |
| 197 return 0; | |
| 198 } | |
| 199 | |
| 200 // Retrieve private key JNI reference. | |
| 201 const KeyExData* ex_data = RsaGetExData(rsa); | |
| 202 if (!ex_data || !ex_data->private_key.obj()) { | |
| 203 LOG(WARNING) << "Null JNI reference passed to RsaMethodSignRaw!"; | |
| 204 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 205 return 0; | |
| 206 } | |
| 207 | |
| 208 // Pre-4.2 legacy codepath. | |
| 209 if (ex_data->legacy_rsa) { | |
| 210 int ret = ex_data->legacy_rsa->meth->rsa_priv_enc( | |
| 211 in_len, in, out, ex_data->legacy_rsa, ANDROID_RSA_PKCS1_PADDING); | |
| 212 if (ret < 0) { | |
| 213 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!"; | |
| 214 // System OpenSSL will use a separate error queue, so it is still | |
| 215 // necessary to push a new error. | |
| 216 // | |
| 217 // TODO(davidben): It would be good to also clear the system error queue | |
| 218 // if there were some way to convince Java to do it. (Without going | |
| 219 // through Java, it's difficult to get a handle on a system OpenSSL | |
| 220 // function; dlopen loads a second copy.) | |
| 221 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 222 return 0; | |
| 223 } | |
| 224 *out_len = ret; | |
| 225 return 1; | |
| 226 } | |
| 227 | |
| 228 base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len); | |
| 229 std::vector<uint8_t> result; | |
| 230 // For RSA keys, this function behaves as RSA_private_encrypt with | |
| 231 // PKCS#1 padding. | |
| 232 if (!RawSignDigestWithPrivateKey(ex_data->private_key.obj(), from_piece, | |
| 233 &result)) { | |
| 234 LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!"; | |
| 235 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 236 return 0; | |
| 237 } | |
| 238 | |
| 239 size_t expected_size = static_cast<size_t>(RSA_size(rsa)); | |
| 240 if (result.size() > expected_size) { | |
| 241 LOG(ERROR) << "RSA Signature size mismatch, actual: " << result.size() | |
| 242 << ", expected <= " << expected_size; | |
| 243 OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); | |
| 244 return 0; | |
| 245 } | |
| 246 | |
| 247 if (max_out < expected_size) { | |
| 248 OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); | |
| 249 return 0; | |
| 250 } | |
| 251 | |
| 252 // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey | |
| 253 // should pad with leading 0s, but if it doesn't, pad the result. | |
| 254 size_t zero_pad = expected_size - result.size(); | |
| 255 memset(out, 0, zero_pad); | |
| 256 memcpy(out + zero_pad, &result[0], result.size()); | |
| 257 *out_len = expected_size; | |
| 258 | |
| 259 return 1; | |
| 260 } | |
| 261 | |
| 262 int RsaMethodDecrypt(RSA* rsa, | |
| 263 size_t* out_len, | |
| 264 uint8_t* out, | |
| 265 size_t max_out, | |
| 266 const uint8_t* in, | |
| 267 size_t in_len, | |
| 268 int padding) { | |
| 269 NOTIMPLEMENTED(); | |
| 270 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 271 return 0; | |
| 272 } | |
| 273 | |
| 274 int RsaMethodVerifyRaw(RSA* rsa, | |
| 275 size_t* out_len, | |
| 276 uint8_t* out, | |
| 277 size_t max_out, | |
| 278 const uint8_t* in, | |
| 279 size_t in_len, | |
| 280 int padding) { | |
| 281 NOTIMPLEMENTED(); | |
| 282 OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); | |
| 283 return 0; | |
| 284 } | |
| 285 | |
| 286 const RSA_METHOD android_rsa_method = { | |
| 287 { | |
| 288 0 /* references */, 1 /* is_static */ | |
| 289 } /* common */, | |
| 290 nullptr /* app_data */, | |
| 291 | |
| 292 nullptr /* init */, | |
| 293 nullptr /* finish */, | |
| 294 RsaMethodSize, | |
| 295 nullptr /* sign */, | |
| 296 nullptr /* verify */, | |
| 297 RsaMethodEncrypt, | |
| 298 RsaMethodSignRaw, | |
| 299 RsaMethodDecrypt, | |
| 300 RsaMethodVerifyRaw, | |
| 301 nullptr /* private_transform */, | |
| 302 nullptr /* mod_exp */, | |
| 303 nullptr /* bn_mod_exp */, | |
| 304 RSA_FLAG_OPAQUE, | |
| 305 nullptr /* keygen */, | |
| 306 nullptr /* multi_prime_keygen */, | |
| 307 nullptr /* supports_digest */, | |
| 308 }; | |
| 309 | |
| 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. | |
| 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 | |
| 314 // implement key operations not exposed by the platform. | |
| 315 // Returns a new EVP_PKEY on success, NULL otherwise. | |
| 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 | |
| 318 // free |private_key| after the call. | |
| 319 crypto::ScopedEVP_PKEY CreateRsaPkeyWrapper( | |
| 320 jobject private_key, | |
| 321 AndroidRSA* legacy_rsa, | |
| 322 const crypto::OpenSSLErrStackTracer& tracer) { | |
| 323 crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); | |
| 324 | |
| 325 std::vector<uint8_t> modulus; | |
| 326 if (!GetRSAKeyModulus(private_key, &modulus)) { | |
| 327 LOG(ERROR) << "Failed to get private key modulus"; | |
| 328 return nullptr; | |
| 329 } | |
| 330 | |
| 331 std::unique_ptr<KeyExData> ex_data(new KeyExData); | |
| 332 ex_data->private_key.Reset(nullptr, private_key); | |
| 333 if (ex_data->private_key.is_null()) { | |
| 334 LOG(ERROR) << "Could not create global JNI reference"; | |
| 335 return nullptr; | |
| 336 } | |
| 337 ex_data->legacy_rsa = legacy_rsa; | |
| 338 ex_data->cached_size = VectorBignumSize(modulus); | |
| 339 | |
| 340 RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), | |
| 341 ex_data.release()); | |
| 342 | |
| 343 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 344 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | |
| 345 return nullptr; | |
| 346 return pkey; | |
| 347 } | |
| 348 | |
| 349 // On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not | |
| 350 // added to the global engine list. If all references to it are dropped, OpenSSL | |
| 351 // will dlclose the module, leaving a dangling function pointer in the RSA | |
| 352 // CRYPTO_EX_DATA class. To work around this, leak an extra reference to the | |
| 353 // ENGINE we extract in GetRsaLegacyKey. | |
| 354 // | |
| 355 // In 4.2, this change avoids the problem: | |
| 356 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1d
ddbe73ca5cb3d61 | |
| 357 // | |
| 358 // https://crbug.com/381465 | |
| 359 class KeystoreEngineWorkaround { | |
| 360 public: | |
| 361 KeystoreEngineWorkaround() {} | |
| 362 | |
| 363 void LeakEngine(jobject private_key) { | |
| 364 if (!engine_.is_null()) | |
| 365 return; | |
| 366 ScopedJavaLocalRef<jobject> engine = | |
| 367 GetOpenSSLEngineForPrivateKey(private_key); | |
| 368 if (engine.is_null()) { | |
| 369 NOTREACHED(); | |
| 370 return; | |
| 371 } | |
| 372 engine_.Reset(engine); | |
| 373 } | |
| 374 | |
| 375 private: | |
| 376 ScopedJavaGlobalRef<jobject> engine_; | |
| 377 }; | |
| 378 | |
| 379 void LeakEngine(jobject private_key) { | |
| 380 static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance = | |
| 381 LAZY_INSTANCE_INITIALIZER; | |
| 382 s_instance.Get().LeakEngine(private_key); | |
| 383 } | |
| 384 | |
| 385 // Creates an EVP_PKEY wrapper corresponding to the RSA key | |
| 386 // |private_key|. Returns nullptr on failure. | |
| 387 crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key) { | |
| 388 const int kAndroid42ApiLevel = 17; | |
| 389 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); | |
| 390 | |
| 391 if (base::android::BuildInfo::GetInstance()->sdk_int() >= | |
| 392 kAndroid42ApiLevel) { | |
| 393 return CreateRsaPkeyWrapper(private_key, nullptr, tracer); | |
| 394 } | |
| 395 | |
| 396 // Route around platform limitation: if Android < 4.2, then | |
| 397 // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the | |
| 398 // system OpenSSL's EVP_PKEY backing this PrivateKey object. | |
| 399 AndroidEVP_PKEY* sys_pkey = GetOpenSSLSystemHandleForPrivateKey(private_key); | |
| 400 if (sys_pkey == nullptr) | |
| 401 return nullptr; | |
| 402 | |
| 403 if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) { | |
| 404 LOG(ERROR) << "Private key has wrong type!"; | |
| 405 return nullptr; | |
| 406 } | |
| 407 | |
| 408 AndroidRSA* sys_rsa = sys_pkey->pkey.rsa; | |
| 409 if (sys_rsa->engine) { | |
| 410 // |private_key| may not have an engine if the PrivateKey did not come | |
| 411 // from the key store, such as in unit tests. | |
| 412 if (strcmp(sys_rsa->engine->id, "keystore") == 0) { | |
| 413 LeakEngine(private_key); | |
| 414 } else { | |
| 415 NOTREACHED(); | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer); | |
| 420 } | |
| 421 | |
| 422 // Custom ECDSA_METHOD that uses the platform APIs. | |
| 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. | |
| 425 | |
| 426 jobject EcKeyGetKey(const EC_KEY* ec_key) { | |
| 427 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( | |
| 428 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | |
| 429 return ex_data->private_key.obj(); | |
| 430 } | |
| 431 | |
| 432 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { | |
| 433 KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( | |
| 434 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); | |
| 435 return ex_data->cached_size; | |
| 436 } | |
| 437 | |
| 438 int EcdsaMethodSign(const uint8_t* digest, | |
| 439 size_t digest_len, | |
| 440 uint8_t* sig, | |
| 441 unsigned int* sig_len, | |
| 442 EC_KEY* ec_key) { | |
| 443 // Retrieve private key JNI reference. | |
| 444 jobject private_key = EcKeyGetKey(ec_key); | |
| 445 if (!private_key) { | |
| 446 LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!"; | |
| 447 return 0; | |
| 448 } | |
| 449 // Sign message with it through JNI. | |
| 450 std::vector<uint8_t> signature; | |
| 451 base::StringPiece digest_sp(reinterpret_cast<const char*>(digest), | |
| 452 digest_len); | |
| 453 if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) { | |
| 454 LOG(WARNING) << "Could not sign message in EcdsaMethodSign!"; | |
| 455 return 0; | |
| 456 } | |
| 457 | |
| 458 // Note: With ECDSA, the actual signature may be smaller than | |
| 459 // ECDSA_size(). | |
| 460 size_t max_expected_size = ECDSA_size(ec_key); | |
| 461 if (signature.size() > max_expected_size) { | |
| 462 LOG(ERROR) << "ECDSA Signature size mismatch, actual: " << signature.size() | |
| 463 << ", expected <= " << max_expected_size; | |
| 464 return 0; | |
| 465 } | |
| 466 | |
| 467 memcpy(sig, &signature[0], signature.size()); | |
| 468 *sig_len = signature.size(); | |
| 469 return 1; | |
| 470 } | |
| 471 | |
| 472 int EcdsaMethodVerify(const uint8_t* digest, | |
| 473 size_t digest_len, | |
| 474 const uint8_t* sig, | |
| 475 size_t sig_len, | |
| 476 EC_KEY* ec_key) { | |
| 477 NOTIMPLEMENTED(); | |
| 478 OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); | |
| 479 return 0; | |
| 480 } | |
| 481 | |
| 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. | |
| 484 // Returns a new EVP_PKEY on success, NULL otherwise. | |
| 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 | |
| 487 // always free |private_key| after the call. | |
| 488 crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) { | |
| 489 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); | |
| 490 crypto::ScopedEC_KEY ec_key( | |
| 491 EC_KEY_new_method(global_boringssl_engine.Get().engine())); | |
| 492 | |
| 493 std::vector<uint8_t> order; | |
| 494 if (!GetECKeyOrder(private_key, &order)) { | |
| 495 LOG(ERROR) << "Can't extract order parameter from EC private key"; | |
| 496 return nullptr; | |
| 497 } | |
| 498 | |
| 499 std::unique_ptr<KeyExData> ex_data(new KeyExData); | |
| 500 ex_data->private_key.Reset(nullptr, private_key); | |
| 501 if (ex_data->private_key.is_null()) { | |
| 502 LOG(ERROR) << "Can't create global JNI reference"; | |
| 503 return nullptr; | |
| 504 } | |
| 505 ex_data->legacy_rsa = nullptr; | |
| 506 ex_data->cached_size = VectorBignumSize(order); | |
| 507 | |
| 508 EC_KEY_set_ex_data(ec_key.get(), | |
| 509 global_boringssl_engine.Get().ec_key_ex_index(), | |
| 510 ex_data.release()); | |
| 511 | |
| 512 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 513 if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) | |
| 514 return nullptr; | |
| 515 return pkey; | |
| 516 } | |
| 517 | |
| 518 const ECDSA_METHOD android_ecdsa_method = { | |
| 519 { | |
| 520 0 /* references */, 1 /* is_static */ | |
| 521 } /* common */, | |
| 522 NULL /* app_data */, | |
| 523 | |
| 524 NULL /* init */, | |
| 525 NULL /* finish */, | |
| 526 EcdsaMethodGroupOrderSize, | |
| 527 EcdsaMethodSign, | |
| 528 EcdsaMethodVerify, | |
| 529 ECDSA_FLAG_OPAQUE, | |
| 530 }; | |
| 531 | |
| 532 } // namespace | |
| 533 | |
| 534 crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) { | |
| 535 // Create sub key type, depending on private key's algorithm type. | |
| 536 PrivateKeyType key_type = GetPrivateKeyType(private_key); | |
| 537 switch (key_type) { | |
| 538 case PRIVATE_KEY_TYPE_RSA: | |
| 539 return GetRsaPkeyWrapper(private_key); | |
| 540 case PRIVATE_KEY_TYPE_ECDSA: | |
| 541 return GetEcdsaPkeyWrapper(private_key); | |
| 542 default: | |
| 543 LOG(WARNING) | |
| 544 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type"; | |
| 545 return nullptr; | |
| 546 } | |
| 547 } | |
| 548 | |
| 549 } // namespace android | |
| 550 } // namespace net | |
| OLD | NEW |