keystore_openssl.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/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
16#include "base/android/build_info.h"
17#include "base/android/jni_android.h"
18#include "base/android/scoped_java_ref.h"
19#include "base/basictypes.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/ssl_client_cert_type.h"
26
27// IMPORTANT NOTE: The following code will currently only work when used
28// to implement client certificate support with OpenSSL. That's because
29// only the signing operations used in this use case are implemented here.
30//
31// Generally speaking, OpenSSL provides many different ways to sign
32// digests. This code doesn't support all these cases, only the ones that
33// are required to sign the digest during the OpenSSL handshake for TLS.
34//
35// The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
36// Internally, it can hold a pointer to a RSA, DSA or ECDSA structure,
37// which model keypair implementations of each respective crypto
38// 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
61using base::android::ScopedJavaGlobalRef;
62using base::android::ScopedJavaLocalRef;
63
64namespace net {
65namespace android {
66
67namespace {
68
69extern const RSA_METHOD android_rsa_method;
70extern const ECDSA_METHOD android_ecdsa_method;
71
72// KeyExData contains the data that is contained in the EX_DATA of the RSA, DSA
73// and ECDSA objects that are created to wrap Android system keys.
74struct KeyExData {
75  // private_key contains a reference to a Java, private-key object.
76  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 (EC)DSA. 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, DSA or EC_KEY objects is
87// duplicated. We don't support this and it should never happen.
88int 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, DSA or EC_KEY object is freed.
99void 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  if (ex_data != NULL) {
109    ReleaseKey(ex_data->private_key);
110    delete ex_data;
111  }
112}
113
114// BoringSSLEngine is a BoringSSL ENGINE that implements RSA, DSA and ECDSA by
115// forwarding the requested operations to the Java libraries.
116class BoringSSLEngine {
117 public:
118  BoringSSLEngine()
119      : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
120                                        NULL /* argp */,
121                                        NULL /* new_func */,
122                                        ExDataDup,
123                                        ExDataFree)),
124        ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
125                                              NULL /* argp */,
126                                              NULL /* new_func */,
127                                              ExDataDup,
128                                              ExDataFree)),
129        engine_(ENGINE_new()) {
130    ENGINE_set_RSA_method(
131        engine_, &android_rsa_method, sizeof(android_rsa_method));
132    ENGINE_set_ECDSA_method(
133        engine_, &android_ecdsa_method, sizeof(android_ecdsa_method));
134  }
135
136  int rsa_ex_index() const { return rsa_index_; }
137  int ec_key_ex_index() const { return ec_key_index_; }
138
139  const ENGINE* engine() const { return engine_; }
140
141 private:
142  const int rsa_index_;
143  const int ec_key_index_;
144  ENGINE* const engine_;
145};
146
147base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
148    LAZY_INSTANCE_INITIALIZER;
149
150
151// VectorBignumSize returns the number of bytes needed to represent the bignum
152// given in |v|, i.e. the length of |v| less any leading zero bytes.
153size_t VectorBignumSize(const std::vector<uint8>& v) {
154  size_t size = v.size();
155  // Ignore any leading zero bytes.
156  for (size_t i = 0; i < v.size() && v[i] == 0; i++) {
157    size--;
158  }
159  return size;
160}
161
162KeyExData* RsaGetExData(const RSA* rsa) {
163  return reinterpret_cast<KeyExData*>(
164      RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index()));
165}
166
167size_t RsaMethodSize(const RSA *rsa) {
168  const KeyExData *ex_data = RsaGetExData(rsa);
169  return ex_data->cached_size;
170}
171
172int RsaMethodEncrypt(RSA* rsa,
173                     size_t* out_len,
174                     uint8_t* out,
175                     size_t max_out,
176                     const uint8_t* in,
177                     size_t in_len,
178                     int padding) {
179  NOTIMPLEMENTED();
180  OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
181  return 0;
182}
183
184int RsaMethodSignRaw(RSA* rsa,
185                     size_t* out_len,
186                     uint8_t* out,
187                     size_t max_out,
188                     const uint8_t* in,
189                     size_t in_len,
190                     int padding) {
191  DCHECK_EQ(RSA_PKCS1_PADDING, padding);
192  if (padding != RSA_PKCS1_PADDING) {
193    // TODO(davidben): If we need to, we can implement RSA_NO_PADDING
194    // by using javax.crypto.Cipher and picking either the
195    // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as
196    // appropriate. I believe support for both of these was added in
197    // the same Android version as the "NONEwithRSA"
198    // java.security.Signature algorithm, so the same version checks
199    // for GetRsaLegacyKey should work.
200    OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
201    return 0;
202  }
203
204  // Retrieve private key JNI reference.
205  const KeyExData *ex_data = RsaGetExData(rsa);
206  if (!ex_data || !ex_data->private_key) {
207    LOG(WARNING) << "Null JNI reference passed to RsaMethodPrivEnc!";
208    OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
209    return 0;
210  }
211
212  // Pre-4.2 legacy codepath.
213  if (ex_data->legacy_rsa) {
214    int ret = ex_data->legacy_rsa->meth->rsa_priv_enc(
215        in_len, in, out, ex_data->legacy_rsa, ANDROID_RSA_PKCS1_PADDING);
216    if (ret < 0) {
217      LOG(WARNING) << "Could not sign message in RsaMethodPrivEnc!";
218      // System OpenSSL will use a separate error queue, so it is still
219      // necessary to push a new error.
220      //
221      // TODO(davidben): It would be good to also clear the system error queue
222      // if there were some way to convince Java to do it. (Without going
223      // through Java, it's difficult to get a handle on a system OpenSSL
224      // function; dlopen loads a second copy.)
225      OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
226      return 0;
227    }
228    *out_len = ret;
229    return 1;
230  }
231
232  base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len);
233  std::vector<uint8> result;
234  // For RSA keys, this function behaves as RSA_private_encrypt with
235  // PKCS#1 padding.
236  if (!RawSignDigestWithPrivateKey(ex_data->private_key, from_piece, &result)) {
237    LOG(WARNING) << "Could not sign message in RsaMethodPrivEnc!";
238    OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
239    return 0;
240  }
241
242  size_t expected_size = static_cast<size_t>(RSA_size(rsa));
243  if (result.size() > expected_size) {
244    LOG(ERROR) << "RSA Signature size mismatch, actual: "
245               <<  result.size() << ", expected <= " << expected_size;
246    OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
247    return 0;
248  }
249
250  if (max_out < expected_size) {
251    OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_DATA_TOO_LARGE);
252    return 0;
253  }
254
255  // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey
256  // should pad with leading 0s, but if it doesn't, pad the result.
257  size_t zero_pad = expected_size - result.size();
258  memset(out, 0, zero_pad);
259  memcpy(out + zero_pad, &result[0], result.size());
260  *out_len = expected_size;
261
262  return 1;
263}
264
265int RsaMethodDecrypt(RSA* rsa,
266                     size_t* out_len,
267                     uint8_t* out,
268                     size_t max_out,
269                     const uint8_t* in,
270                     size_t in_len,
271                     int padding) {
272  NOTIMPLEMENTED();
273  OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
274  return 0;
275}
276
277int RsaMethodVerifyRaw(RSA* rsa,
278                       size_t* out_len,
279                       uint8_t* out,
280                       size_t max_out,
281                       const uint8_t* in,
282                       size_t in_len,
283                       int padding) {
284  NOTIMPLEMENTED();
285  OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE);
286  return 0;
287}
288
289const RSA_METHOD android_rsa_method = {
290    {
291     0 /* references */,
292     1 /* is_static */
293    } /* common */,
294    NULL /* app_data */,
295
296    NULL /* init */,
297    NULL /* finish */,
298    RsaMethodSize,
299    NULL /* sign */,
300    NULL /* verify */,
301    RsaMethodEncrypt,
302    RsaMethodSignRaw,
303    RsaMethodDecrypt,
304    RsaMethodVerifyRaw,
305    NULL /* private_transform */,
306    NULL /* mod_exp */,
307    NULL /* bn_mod_exp */,
308    RSA_FLAG_OPAQUE,
309    NULL /* keygen */,
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.
321crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key,
322                                         AndroidRSA* legacy_rsa) {
323  crypto::ScopedRSA rsa(
324      RSA_new_method(global_boringssl_engine.Get().engine()));
325
326  ScopedJavaGlobalRef<jobject> global_key;
327  global_key.Reset(NULL, private_key);
328  if (global_key.is_null()) {
329    LOG(ERROR) << "Could not create global JNI reference";
330    return crypto::ScopedEVP_PKEY();
331  }
332
333  std::vector<uint8> modulus;
334  if (!GetRSAKeyModulus(private_key, &modulus)) {
335    LOG(ERROR) << "Failed to get private key modulus";
336    return crypto::ScopedEVP_PKEY();
337  }
338
339  KeyExData* ex_data = new KeyExData;
340  ex_data->private_key = global_key.Release();
341  ex_data->legacy_rsa = legacy_rsa;
342  ex_data->cached_size = VectorBignumSize(modulus);
343  RSA_set_ex_data(
344      rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), ex_data);
345
346  crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
347  if (!pkey ||
348      !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) {
349    return crypto::ScopedEVP_PKEY();
350  }
351  return pkey.Pass();
352}
353
354// On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
355// added to the global engine list. If all references to it are dropped, OpenSSL
356// will dlclose the module, leaving a dangling function pointer in the RSA
357// CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
358// ENGINE we extract in GetRsaLegacyKey.
359//
360// In 4.2, this change avoids the problem:
361// https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1dddbe73ca5cb3d61
362//
363// https://crbug.com/381465
364class KeystoreEngineWorkaround {
365 public:
366  KeystoreEngineWorkaround() {}
367
368  void LeakEngine(jobject private_key) {
369    if (!engine_.is_null())
370      return;
371    ScopedJavaLocalRef<jobject> engine =
372        GetOpenSSLEngineForPrivateKey(private_key);
373    if (engine.is_null()) {
374      NOTREACHED();
375      return;
376    }
377    engine_.Reset(engine);
378  }
379
380 private:
381  ScopedJavaGlobalRef<jobject> engine_;
382};
383
384void LeakEngine(jobject private_key) {
385  static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
386      LAZY_INSTANCE_INITIALIZER;
387  s_instance.Get().LeakEngine(private_key);
388}
389
390// Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object
391// for Android 4.0 to 4.1.x. Must only be used on Android < 4.2.
392// |private_key| is a JNI reference (local or global) to the object.
393// |pkey| is the EVP_PKEY to setup as a wrapper.
394// Returns true on success, false otherwise.
395crypto::ScopedEVP_PKEY GetRsaLegacyKey(jobject private_key) {
396  AndroidEVP_PKEY* sys_pkey =
397      GetOpenSSLSystemHandleForPrivateKey(private_key);
398  if (sys_pkey != NULL) {
399    if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) {
400      LOG(ERROR) << "Private key has wrong type!";
401      return crypto::ScopedEVP_PKEY();
402    }
403
404    AndroidRSA* sys_rsa = sys_pkey->pkey.rsa;
405    if (sys_rsa->engine) {
406      // |private_key| may not have an engine if the PrivateKey did not come
407      // from the key store, such as in unit tests.
408      if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
409        LeakEngine(private_key);
410      } else {
411        NOTREACHED();
412      }
413    }
414
415    return GetRsaPkeyWrapper(private_key, sys_rsa);
416  }
417
418  // GetOpenSSLSystemHandleForPrivateKey() will fail on Android 4.0.3 and
419  // earlier. However, it is possible to get the key content with
420  // PrivateKey.getEncoded() on these platforms.  Note that this method may
421  // return NULL on 4.0.4 and later.
422  std::vector<uint8> encoded;
423  if (!GetPrivateKeyEncodedBytes(private_key, &encoded)) {
424    LOG(ERROR) << "Can't get private key data!";
425    return crypto::ScopedEVP_PKEY();
426  }
427  const unsigned char* p =
428      reinterpret_cast<const unsigned char*>(&encoded[0]);
429  int len = static_cast<int>(encoded.size());
430  crypto::ScopedEVP_PKEY pkey(d2i_AutoPrivateKey(NULL, &p, len));
431  if (!pkey) {
432    LOG(ERROR) << "Can't convert private key data!";
433    return crypto::ScopedEVP_PKEY();
434  }
435  return pkey.Pass();
436}
437
438// Custom ECDSA_METHOD that uses the platform APIs.
439// Note that for now, only signing through ECDSA_sign() is really supported.
440// all other method pointers are either stubs returning errors, or no-ops.
441
442jobject EcKeyGetKey(const EC_KEY* ec_key) {
443  KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
444      ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
445  return ex_data->private_key;
446}
447
448size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
449  KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
450      ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
451  return ex_data->cached_size;
452}
453
454int EcdsaMethodSign(const uint8_t* digest,
455                    size_t digest_len,
456                    uint8_t* sig,
457                    unsigned int* sig_len,
458                    EC_KEY* ec_key) {
459  // Retrieve private key JNI reference.
460  jobject private_key = EcKeyGetKey(ec_key);
461  if (!private_key) {
462    LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!";
463    return 0;
464  }
465  // Sign message with it through JNI.
466  std::vector<uint8> signature;
467  base::StringPiece digest_sp(reinterpret_cast<const char*>(digest),
468                              digest_len);
469  if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) {
470    LOG(WARNING) << "Could not sign message in EcdsaMethodSign!";
471    return 0;
472  }
473
474  // Note: With ECDSA, the actual signature may be smaller than
475  // ECDSA_size().
476  size_t max_expected_size = ECDSA_size(ec_key);
477  if (signature.size() > max_expected_size) {
478    LOG(ERROR) << "ECDSA Signature size mismatch, actual: "
479               <<  signature.size() << ", expected <= "
480               << max_expected_size;
481    return 0;
482  }
483
484  memcpy(sig, &signature[0], signature.size());
485  *sig_len = signature.size();
486  return 1;
487}
488
489int EcdsaMethodVerify(const uint8_t* digest,
490                      size_t digest_len,
491                      const uint8_t* sig,
492                      size_t sig_len,
493                      EC_KEY* ec_key) {
494  NOTIMPLEMENTED();
495  OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
496  return 0;
497}
498
499// Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
500// |private_key| is the JNI reference (local or global) to the object.
501// Returns a new EVP_PKEY on success, NULL otherwise.
502// On success, this creates a global JNI reference to the object that
503// is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
504// always free |private_key| after the call.
505crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) {
506  crypto::ScopedEC_KEY ec_key(
507      EC_KEY_new_method(global_boringssl_engine.Get().engine()));
508
509  ScopedJavaGlobalRef<jobject> global_key;
510  global_key.Reset(NULL, private_key);
511  if (global_key.is_null()) {
512    LOG(ERROR) << "Can't create global JNI reference";
513    return crypto::ScopedEVP_PKEY();
514  }
515
516  std::vector<uint8> order;
517  if (!GetECKeyOrder(private_key, &order)) {
518    LOG(ERROR) << "Can't extract order parameter from EC private key";
519    return crypto::ScopedEVP_PKEY();
520  }
521
522  KeyExData* ex_data = new KeyExData;
523  ex_data->private_key = global_key.Release();
524  ex_data->legacy_rsa = NULL;
525  ex_data->cached_size = VectorBignumSize(order);
526
527  EC_KEY_set_ex_data(
528      ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(), ex_data);
529
530  crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
531  if (!pkey ||
532      !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) {
533    return crypto::ScopedEVP_PKEY();
534  }
535  return pkey.Pass();
536}
537
538const ECDSA_METHOD android_ecdsa_method = {
539    {
540     0 /* references */,
541     1 /* is_static */
542    } /* common */,
543    NULL /* app_data */,
544
545    NULL /* init */,
546    NULL /* finish */,
547    EcdsaMethodGroupOrderSize,
548    EcdsaMethodSign,
549    EcdsaMethodVerify,
550    ECDSA_FLAG_OPAQUE,
551};
552
553}  // namespace
554
555crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) {
556  const int kAndroid42ApiLevel = 17;
557
558  // Create sub key type, depending on private key's algorithm type.
559  PrivateKeyType key_type = GetPrivateKeyType(private_key);
560  switch (key_type) {
561    case PRIVATE_KEY_TYPE_RSA:
562      // Route around platform bug: if Android < 4.2, then
563      // base::android::RawSignDigestWithPrivateKey() cannot work, so
564      // instead, obtain a raw EVP_PKEY* to the system object
565      // backing this PrivateKey object.
566      if (base::android::BuildInfo::GetInstance()->sdk_int() <
567          kAndroid42ApiLevel) {
568        return GetRsaLegacyKey(private_key);
569      } else {
570        // Running on Android 4.2.
571        return GetRsaPkeyWrapper(private_key, NULL);
572      }
573    case PRIVATE_KEY_TYPE_ECDSA:
574      return GetEcdsaPkeyWrapper(private_key);
575    default:
576      LOG(WARNING)
577          << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
578      return crypto::ScopedEVP_PKEY();
579  }
580}
581
582}  // namespace android
583}  // namespace net
584