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.
5 #include "net/android/keystore_openssl.h"
8 #include <openssl/bn.h>
9 #include <openssl/dsa.h>
10 #include <openssl/ec.h>
11 #include <openssl/engine.h>
12 #include <openssl/err.h>
13 #include <openssl/evp.h>
14 #include <openssl/rsa.h>
15 #include <openssl/x509.h>
17 #include "base/android/build_info.h"
18 #include "base/android/jni_android.h"
19 #include "base/android/scoped_java_ref.h"
20 #include "base/basictypes.h"
21 #include "base/lazy_instance.h"
22 #include "base/logging.h"
23 #include "crypto/openssl_util.h"
24 #include "net/android/keystore.h"
25 #include "net/android/legacy_openssl.h"
26 #include "net/ssl/ssl_client_cert_type.h"
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.
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.
36 // The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
37 // Internally, it can hold a pointer to a RSA, DSA or ECDSA structure,
38 // which model keypair implementations of each respective crypto
41 // The RSA type has a 'method' field pointer to a vtable-like structure
42 // called a RSA_METHOD. This contains several function pointers that
43 // correspond to operations on RSA keys (e.g. decode/encode with public
44 // key, decode/encode with private key, signing, validation), as well as
47 // For example, the RSA_sign() function will call "method->rsa_sign()" if
48 // method->rsa_sign is not NULL, otherwise, it will perform a regular
49 // signing operation using the other fields in the RSA structure (which
50 // are used to hold the typical modulus / exponent / parameters for the
53 // This source file thus defines a custom RSA_METHOD structure whose
54 // fields point to static methods used to implement the corresponding
55 // RSA operation using platform Android APIs.
57 // However, the platform APIs require a jobject JNI reference to work. It must
58 // be stored in the RSA instance, or made accessible when the custom RSA
59 // methods are called. This is done by storing it in a |KeyExData| structure
60 // that's referenced by the key using |EX_DATA|.
62 using base::android::ScopedJavaGlobalRef
;
63 using base::android::ScopedJavaLocalRef
;
70 using ScopedPKCS8_PRIV_KEY_INFO
=
71 crypto::ScopedOpenSSL
<PKCS8_PRIV_KEY_INFO
, PKCS8_PRIV_KEY_INFO_free
>::Type
;
73 extern const RSA_METHOD android_rsa_method
;
74 extern const ECDSA_METHOD android_ecdsa_method
;
76 // KeyExData contains the data that is contained in the EX_DATA of the RSA, DSA
77 // and ECDSA objects that are created to wrap Android system keys.
79 // private_key contains a reference to a Java, private-key object.
81 // legacy_rsa, if not NULL, points to an RSA* in the system's OpenSSL (which
82 // might not be ABI compatible with Chromium).
83 AndroidRSA
* legacy_rsa
;
84 // cached_size contains the "size" of the key. This is the size of the
85 // modulus (in bytes) for RSA, or the group order size for (EC)DSA. This
86 // avoids calling into Java to calculate the size.
90 // ExDataDup is called when one of the RSA, DSA or EC_KEY objects is
91 // duplicated. We don't support this and it should never happen.
92 int ExDataDup(CRYPTO_EX_DATA
* to
,
93 const CRYPTO_EX_DATA
* from
,
98 CHECK_EQ((void*)NULL
, *from_d
);
102 // ExDataFree is called when one of the RSA, DSA or EC_KEY objects is freed.
103 void ExDataFree(void* parent
,
109 // Ensure the global JNI reference created with this wrapper is
110 // properly destroyed with it.
111 KeyExData
*ex_data
= reinterpret_cast<KeyExData
*>(ptr
);
112 if (ex_data
!= NULL
) {
113 ReleaseKey(ex_data
->private_key
);
118 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA, DSA and ECDSA by
119 // forwarding the requested operations to the Java libraries.
120 class BoringSSLEngine
{
123 : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
128 ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
133 engine_(ENGINE_new()) {
134 ENGINE_set_RSA_method(
135 engine_
, &android_rsa_method
, sizeof(android_rsa_method
));
136 ENGINE_set_ECDSA_method(
137 engine_
, &android_ecdsa_method
, sizeof(android_ecdsa_method
));
140 int rsa_ex_index() const { return rsa_index_
; }
141 int ec_key_ex_index() const { return ec_key_index_
; }
143 const ENGINE
* engine() const { return engine_
; }
146 const int rsa_index_
;
147 const int ec_key_index_
;
148 ENGINE
* const engine_
;
151 base::LazyInstance
<BoringSSLEngine
>::Leaky global_boringssl_engine
=
152 LAZY_INSTANCE_INITIALIZER
;
155 // VectorBignumSize returns the number of bytes needed to represent the bignum
156 // given in |v|, i.e. the length of |v| less any leading zero bytes.
157 size_t VectorBignumSize(const std::vector
<uint8
>& v
) {
158 size_t size
= v
.size();
159 // Ignore any leading zero bytes.
160 for (size_t i
= 0; i
< v
.size() && v
[i
] == 0; i
++) {
166 KeyExData
* RsaGetExData(const RSA
* rsa
) {
167 return reinterpret_cast<KeyExData
*>(
168 RSA_get_ex_data(rsa
, global_boringssl_engine
.Get().rsa_ex_index()));
171 size_t RsaMethodSize(const RSA
*rsa
) {
172 const KeyExData
*ex_data
= RsaGetExData(rsa
);
173 return ex_data
->cached_size
;
176 int RsaMethodEncrypt(RSA
* rsa
,
184 OPENSSL_PUT_ERROR(RSA
, encrypt
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
188 int RsaMethodSignRaw(RSA
* rsa
,
195 DCHECK_EQ(RSA_PKCS1_PADDING
, padding
);
196 if (padding
!= RSA_PKCS1_PADDING
) {
197 // TODO(davidben): If we need to, we can implement RSA_NO_PADDING
198 // by using javax.crypto.Cipher and picking either the
199 // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as
200 // appropriate. I believe support for both of these was added in
201 // the same Android version as the "NONEwithRSA"
202 // java.security.Signature algorithm, so the same version checks
203 // for GetRsaLegacyKey should work.
204 OPENSSL_PUT_ERROR(RSA
, sign_raw
, RSA_R_UNKNOWN_PADDING_TYPE
);
208 // Retrieve private key JNI reference.
209 const KeyExData
*ex_data
= RsaGetExData(rsa
);
210 if (!ex_data
|| !ex_data
->private_key
) {
211 LOG(WARNING
) << "Null JNI reference passed to RsaMethodSignRaw!";
212 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
216 // Pre-4.2 legacy codepath.
217 if (ex_data
->legacy_rsa
) {
218 int ret
= ex_data
->legacy_rsa
->meth
->rsa_priv_enc(
219 in_len
, in
, out
, ex_data
->legacy_rsa
, ANDROID_RSA_PKCS1_PADDING
);
221 LOG(WARNING
) << "Could not sign message in RsaMethodSignRaw!";
222 // System OpenSSL will use a separate error queue, so it is still
223 // necessary to push a new error.
225 // TODO(davidben): It would be good to also clear the system error queue
226 // if there were some way to convince Java to do it. (Without going
227 // through Java, it's difficult to get a handle on a system OpenSSL
228 // function; dlopen loads a second copy.)
229 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
236 base::StringPiece
from_piece(reinterpret_cast<const char*>(in
), in_len
);
237 std::vector
<uint8
> result
;
238 // For RSA keys, this function behaves as RSA_private_encrypt with
240 if (!RawSignDigestWithPrivateKey(ex_data
->private_key
, from_piece
, &result
)) {
241 LOG(WARNING
) << "Could not sign message in RsaMethodSignRaw!";
242 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
246 size_t expected_size
= static_cast<size_t>(RSA_size(rsa
));
247 if (result
.size() > expected_size
) {
248 LOG(ERROR
) << "RSA Signature size mismatch, actual: "
249 << result
.size() << ", expected <= " << expected_size
;
250 OPENSSL_PUT_ERROR(RSA
, sign_raw
, ERR_R_INTERNAL_ERROR
);
254 if (max_out
< expected_size
) {
255 OPENSSL_PUT_ERROR(RSA
, sign_raw
, RSA_R_DATA_TOO_LARGE
);
259 // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey
260 // should pad with leading 0s, but if it doesn't, pad the result.
261 size_t zero_pad
= expected_size
- result
.size();
262 memset(out
, 0, zero_pad
);
263 memcpy(out
+ zero_pad
, &result
[0], result
.size());
264 *out_len
= expected_size
;
269 int RsaMethodDecrypt(RSA
* rsa
,
277 OPENSSL_PUT_ERROR(RSA
, decrypt
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
281 int RsaMethodVerifyRaw(RSA
* rsa
,
289 OPENSSL_PUT_ERROR(RSA
, verify_raw
, RSA_R_UNKNOWN_ALGORITHM_TYPE
);
293 const RSA_METHOD android_rsa_method
= {
309 NULL
/* private_transform */,
311 NULL
/* bn_mod_exp */,
316 // Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object.
317 // |private_key| is the JNI reference (local or global) to the object.
318 // |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object
319 // backing |private_key|. This parameter is only used for Android < 4.2 to
320 // implement key operations not exposed by the platform.
321 // Returns a new EVP_PKEY on success, NULL otherwise.
322 // On success, this creates a new global JNI reference to the object
323 // that is owned by and destroyed with the EVP_PKEY. I.e. caller can
324 // free |private_key| after the call.
325 crypto::ScopedEVP_PKEY
CreateRsaPkeyWrapper(
327 AndroidRSA
* legacy_rsa
,
328 const crypto::OpenSSLErrStackTracer
& tracer
) {
329 crypto::ScopedRSA
rsa(
330 RSA_new_method(global_boringssl_engine
.Get().engine()));
332 ScopedJavaGlobalRef
<jobject
> global_key
;
333 global_key
.Reset(NULL
, private_key
);
334 if (global_key
.is_null()) {
335 LOG(ERROR
) << "Could not create global JNI reference";
336 return crypto::ScopedEVP_PKEY();
339 std::vector
<uint8
> modulus
;
340 if (!GetRSAKeyModulus(private_key
, &modulus
)) {
341 LOG(ERROR
) << "Failed to get private key modulus";
342 return crypto::ScopedEVP_PKEY();
345 KeyExData
* ex_data
= new KeyExData
;
346 ex_data
->private_key
= global_key
.Release();
347 ex_data
->legacy_rsa
= legacy_rsa
;
348 ex_data
->cached_size
= VectorBignumSize(modulus
);
350 rsa
.get(), global_boringssl_engine
.Get().rsa_ex_index(), ex_data
);
352 crypto::ScopedEVP_PKEY
pkey(EVP_PKEY_new());
354 !EVP_PKEY_set1_RSA(pkey
.get(), rsa
.get())) {
355 return crypto::ScopedEVP_PKEY();
360 // On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
361 // added to the global engine list. If all references to it are dropped, OpenSSL
362 // will dlclose the module, leaving a dangling function pointer in the RSA
363 // CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
364 // ENGINE we extract in GetRsaLegacyKey.
366 // In 4.2, this change avoids the problem:
367 // https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1dddbe73ca5cb3d61
369 // https://crbug.com/381465
370 class KeystoreEngineWorkaround
{
372 KeystoreEngineWorkaround() {}
374 void LeakEngine(jobject private_key
) {
375 if (!engine_
.is_null())
377 ScopedJavaLocalRef
<jobject
> engine
=
378 GetOpenSSLEngineForPrivateKey(private_key
);
379 if (engine
.is_null()) {
383 engine_
.Reset(engine
);
387 ScopedJavaGlobalRef
<jobject
> engine_
;
390 void LeakEngine(jobject private_key
) {
391 static base::LazyInstance
<KeystoreEngineWorkaround
>::Leaky s_instance
=
392 LAZY_INSTANCE_INITIALIZER
;
393 s_instance
.Get().LeakEngine(private_key
);
396 // Creates an EVP_PKEY wrapper corresponding to the RSA key
397 // |private_key|. Returns nullptr on failure.
398 crypto::ScopedEVP_PKEY
GetRsaPkeyWrapper(jobject private_key
) {
399 const int kAndroid42ApiLevel
= 17;
400 crypto::OpenSSLErrStackTracer
tracer(FROM_HERE
);
402 if (base::android::BuildInfo::GetInstance()->sdk_int() >=
403 kAndroid42ApiLevel
) {
404 return CreateRsaPkeyWrapper(private_key
, nullptr, tracer
);
407 // Route around platform bug: if Android < 4.2, then
408 // base::android::RawSignDigestWithPrivateKey() cannot work, so instead, try
409 // to get the system OpenSSL's EVP_PKEY begin this PrivateKey object.
410 AndroidEVP_PKEY
* sys_pkey
=
411 GetOpenSSLSystemHandleForPrivateKey(private_key
);
412 if (sys_pkey
!= NULL
) {
413 if (sys_pkey
->type
!= ANDROID_EVP_PKEY_RSA
) {
414 LOG(ERROR
) << "Private key has wrong type!";
418 AndroidRSA
* sys_rsa
= sys_pkey
->pkey
.rsa
;
419 if (sys_rsa
->engine
) {
420 // |private_key| may not have an engine if the PrivateKey did not come
421 // from the key store, such as in unit tests.
422 if (strcmp(sys_rsa
->engine
->id
, "keystore") == 0) {
423 LeakEngine(private_key
);
429 return CreateRsaPkeyWrapper(private_key
, sys_rsa
, tracer
);
432 // GetOpenSSLSystemHandleForPrivateKey() will fail on Android 4.0.3 and
433 // earlier. However, it is possible to get the key content with
434 // PrivateKey.getEncoded() on these platforms. Note that this method may
435 // return false on 4.0.4 and later.
436 std::vector
<uint8_t> encoded
;
437 if (!GetPrivateKeyEncodedBytes(private_key
, &encoded
) || encoded
.empty()) {
438 LOG(ERROR
) << "Can't get private key data!";
441 const uint8_t* p
= &encoded
[0];
442 ScopedPKCS8_PRIV_KEY_INFO
pkcs8(
443 d2i_PKCS8_PRIV_KEY_INFO(NULL
, &p
, encoded
.size()));
444 if (!pkcs8
.get() || p
!= &encoded
[0] + encoded
.size()) {
445 LOG(ERROR
) << "Can't decode PrivateKeyInfo";
448 crypto::ScopedEVP_PKEY
pkey(EVP_PKCS82PKEY(pkcs8
.get()));
449 if (!pkey
|| EVP_PKEY_id(pkey
.get()) != EVP_PKEY_RSA
) {
450 LOG(ERROR
) << "Can't decode RSA key";
456 // Custom ECDSA_METHOD that uses the platform APIs.
457 // Note that for now, only signing through ECDSA_sign() is really supported.
458 // all other method pointers are either stubs returning errors, or no-ops.
460 jobject
EcKeyGetKey(const EC_KEY
* ec_key
) {
461 KeyExData
* ex_data
= reinterpret_cast<KeyExData
*>(EC_KEY_get_ex_data(
462 ec_key
, global_boringssl_engine
.Get().ec_key_ex_index()));
463 return ex_data
->private_key
;
466 size_t EcdsaMethodGroupOrderSize(const EC_KEY
* ec_key
) {
467 KeyExData
* ex_data
= reinterpret_cast<KeyExData
*>(EC_KEY_get_ex_data(
468 ec_key
, global_boringssl_engine
.Get().ec_key_ex_index()));
469 return ex_data
->cached_size
;
472 int EcdsaMethodSign(const uint8_t* digest
,
475 unsigned int* sig_len
,
477 // Retrieve private key JNI reference.
478 jobject private_key
= EcKeyGetKey(ec_key
);
480 LOG(WARNING
) << "Null JNI reference passed to EcdsaMethodSign!";
483 // Sign message with it through JNI.
484 std::vector
<uint8
> signature
;
485 base::StringPiece
digest_sp(reinterpret_cast<const char*>(digest
),
487 if (!RawSignDigestWithPrivateKey(private_key
, digest_sp
, &signature
)) {
488 LOG(WARNING
) << "Could not sign message in EcdsaMethodSign!";
492 // Note: With ECDSA, the actual signature may be smaller than
494 size_t max_expected_size
= ECDSA_size(ec_key
);
495 if (signature
.size() > max_expected_size
) {
496 LOG(ERROR
) << "ECDSA Signature size mismatch, actual: "
497 << signature
.size() << ", expected <= "
498 << max_expected_size
;
502 memcpy(sig
, &signature
[0], signature
.size());
503 *sig_len
= signature
.size();
507 int EcdsaMethodVerify(const uint8_t* digest
,
513 OPENSSL_PUT_ERROR(ECDSA
, ECDSA_do_verify
, ECDSA_R_NOT_IMPLEMENTED
);
517 // Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
518 // |private_key| is the JNI reference (local or global) to the object.
519 // Returns a new EVP_PKEY on success, NULL otherwise.
520 // On success, this creates a global JNI reference to the object that
521 // is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
522 // always free |private_key| after the call.
523 crypto::ScopedEVP_PKEY
GetEcdsaPkeyWrapper(jobject private_key
) {
524 crypto::OpenSSLErrStackTracer
tracer(FROM_HERE
);
525 crypto::ScopedEC_KEY
ec_key(
526 EC_KEY_new_method(global_boringssl_engine
.Get().engine()));
528 ScopedJavaGlobalRef
<jobject
> global_key
;
529 global_key
.Reset(NULL
, private_key
);
530 if (global_key
.is_null()) {
531 LOG(ERROR
) << "Can't create global JNI reference";
532 return crypto::ScopedEVP_PKEY();
535 std::vector
<uint8
> order
;
536 if (!GetECKeyOrder(private_key
, &order
)) {
537 LOG(ERROR
) << "Can't extract order parameter from EC private key";
538 return crypto::ScopedEVP_PKEY();
541 KeyExData
* ex_data
= new KeyExData
;
542 ex_data
->private_key
= global_key
.Release();
543 ex_data
->legacy_rsa
= NULL
;
544 ex_data
->cached_size
= VectorBignumSize(order
);
547 ec_key
.get(), global_boringssl_engine
.Get().ec_key_ex_index(), ex_data
);
549 crypto::ScopedEVP_PKEY
pkey(EVP_PKEY_new());
551 !EVP_PKEY_set1_EC_KEY(pkey
.get(), ec_key
.get())) {
552 return crypto::ScopedEVP_PKEY();
557 const ECDSA_METHOD android_ecdsa_method
= {
566 EcdsaMethodGroupOrderSize
,
574 crypto::ScopedEVP_PKEY
GetOpenSSLPrivateKeyWrapper(jobject private_key
) {
575 // Create sub key type, depending on private key's algorithm type.
576 PrivateKeyType key_type
= GetPrivateKeyType(private_key
);
578 case PRIVATE_KEY_TYPE_RSA
:
579 return GetRsaPkeyWrapper(private_key
);
580 case PRIVATE_KEY_TYPE_ECDSA
:
581 return GetEcdsaPkeyWrapper(private_key
);
584 << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
589 } // namespace android