Home | History | Annotate | Download | only in ssl
      1 // Copyright 2014 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/ssl/openssl_platform_key.h"
      6 
      7 #include <openssl/err.h>
      8 #include <openssl/evp.h>
      9 #include <openssl/rsa.h>
     10 
     11 #include <Security/cssm.h>
     12 #include <Security/SecBase.h>
     13 #include <Security/SecCertificate.h>
     14 #include <Security/SecIdentity.h>
     15 #include <Security/SecKey.h>
     16 
     17 #include "base/lazy_instance.h"
     18 #include "base/location.h"
     19 #include "base/logging.h"
     20 #include "base/mac/mac_logging.h"
     21 #include "base/mac/scoped_cftyperef.h"
     22 #include "base/memory/scoped_policy.h"
     23 #include "base/memory/scoped_ptr.h"
     24 #include "base/synchronization/lock.h"
     25 #include "crypto/mac_security_services_lock.h"
     26 #include "net/base/net_errors.h"
     27 #include "net/cert/x509_certificate.h"
     28 #include "net/ssl/openssl_ssl_util.h"
     29 
     30 namespace net {
     31 
     32 namespace {
     33 
     34 class ScopedCSSM_CC_HANDLE {
     35  public:
     36   ScopedCSSM_CC_HANDLE() : handle_(0) {
     37   }
     38 
     39   ~ScopedCSSM_CC_HANDLE() {
     40     reset();
     41   }
     42 
     43   CSSM_CC_HANDLE get() const {
     44     return handle_;
     45   }
     46 
     47   void reset() {
     48     if (handle_)
     49       CSSM_DeleteContext(handle_);
     50     handle_ = 0;
     51   }
     52 
     53   CSSM_CC_HANDLE* InitializeInto() {
     54     reset();
     55     return &handle_;
     56   }
     57  private:
     58   CSSM_CC_HANDLE handle_;
     59 
     60   DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE);
     61 };
     62 
     63 // Looks up the private key for |certificate| in KeyChain and returns
     64 // a SecKeyRef or NULL on failure. The caller takes ownership of the
     65 // result.
     66 SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate) {
     67   OSStatus status;
     68   base::ScopedCFTypeRef<SecIdentityRef> identity;
     69   {
     70     base::AutoLock lock(crypto::GetMacSecurityServicesLock());
     71     status = SecIdentityCreateWithCertificate(
     72         NULL, certificate->os_cert_handle(), identity.InitializeInto());
     73   }
     74   if (status != noErr) {
     75     OSSTATUS_LOG(WARNING, status);
     76     return NULL;
     77   }
     78 
     79   base::ScopedCFTypeRef<SecKeyRef> private_key;
     80   status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto());
     81   if (status != noErr) {
     82     OSSTATUS_LOG(WARNING, status);
     83     return NULL;
     84   }
     85 
     86   return private_key.release();
     87 }
     88 
     89 extern const RSA_METHOD mac_rsa_method;
     90 extern const ECDSA_METHOD mac_ecdsa_method;
     91 
     92 // KeyExData contains the data that is contained in the EX_DATA of the
     93 // RSA and ECDSA objects that are created to wrap Mac system keys.
     94 struct KeyExData {
     95   KeyExData(SecKeyRef key, const CSSM_KEY* cssm_key)
     96       : key(key, base::scoped_policy::RETAIN), cssm_key(cssm_key) {}
     97 
     98   base::ScopedCFTypeRef<SecKeyRef> key;
     99   const CSSM_KEY* cssm_key;
    100 };
    101 
    102 // ExDataDup is called when one of the RSA or EC_KEY objects is
    103 // duplicated. This is not supported and should never happen.
    104 int ExDataDup(CRYPTO_EX_DATA* to,
    105               const CRYPTO_EX_DATA* from,
    106               void** from_d,
    107               int idx,
    108               long argl,
    109               void* argp) {
    110   CHECK_EQ((void*)NULL, *from_d);
    111   return 0;
    112 }
    113 
    114 // ExDataFree is called when one of the RSA or EC_KEY objects is freed.
    115 void ExDataFree(void* parent,
    116                 void* ptr,
    117                 CRYPTO_EX_DATA* ex_data,
    118                 int idx,
    119                 long argl, void* argp) {
    120   KeyExData* data = reinterpret_cast<KeyExData*>(ptr);
    121   delete data;
    122 }
    123 
    124 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA
    125 // by forwarding the requested operations to Apple's CSSM
    126 // implementation.
    127 class BoringSSLEngine {
    128  public:
    129   BoringSSLEngine()
    130       : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
    131                                         NULL /* argp */,
    132                                         NULL /* new_func */,
    133                                         ExDataDup,
    134                                         ExDataFree)),
    135         ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
    136                                               NULL /* argp */,
    137                                               NULL /* new_func */,
    138                                               ExDataDup,
    139                                               ExDataFree)),
    140         engine_(ENGINE_new()) {
    141     ENGINE_set_RSA_method(
    142         engine_, &mac_rsa_method, sizeof(mac_rsa_method));
    143     ENGINE_set_ECDSA_method(
    144         engine_, &mac_ecdsa_method, sizeof(mac_ecdsa_method));
    145   }
    146 
    147   int rsa_ex_index() const { return rsa_index_; }
    148   int ec_key_ex_index() const { return ec_key_index_; }
    149 
    150   const ENGINE* engine() const { return engine_; }
    151 
    152  private:
    153   const int rsa_index_;
    154   const int ec_key_index_;
    155   ENGINE* const engine_;
    156 };
    157 
    158 base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
    159     LAZY_INSTANCE_INITIALIZER;
    160 
    161 // Helper function for making a signature.
    162 
    163 // MakeCSSMSignature uses the key information in |ex_data| to sign the
    164 // |in_len| bytes pointed by |in|. It writes up to |max_out| bytes
    165 // into the buffer pointed to by |out|, setting |*out_len| to the
    166 // number of bytes written. It returns 1 on success and 0 on failure.
    167 int MakeCSSMSignature(const KeyExData* ex_data,
    168                       size_t* out_len,
    169                       uint8_t* out,
    170                       size_t max_out,
    171                       const uint8_t* in,
    172                       size_t in_len) {
    173   CSSM_CSP_HANDLE csp_handle;
    174   OSStatus status = SecKeyGetCSPHandle(ex_data->key.get(), &csp_handle);
    175   if (status != noErr) {
    176     OSSTATUS_LOG(WARNING, status);
    177     OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
    178     return 0;
    179   }
    180 
    181   const CSSM_ACCESS_CREDENTIALS* cssm_creds = NULL;
    182   status = SecKeyGetCredentials(ex_data->key.get(), CSSM_ACL_AUTHORIZATION_SIGN,
    183                                 kSecCredentialTypeDefault, &cssm_creds);
    184   if (status != noErr) {
    185     OSSTATUS_LOG(WARNING, status);
    186     OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
    187     return 0;
    188   }
    189 
    190   ScopedCSSM_CC_HANDLE cssm_signature;
    191   if (CSSM_CSP_CreateSignatureContext(
    192           csp_handle, ex_data->cssm_key->KeyHeader.AlgorithmId, cssm_creds,
    193           ex_data->cssm_key, cssm_signature.InitializeInto()) != CSSM_OK) {
    194     OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
    195     return 0;
    196   }
    197 
    198   if (ex_data->cssm_key->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
    199     // Set RSA blinding.
    200     CSSM_CONTEXT_ATTRIBUTE blinding_attr;
    201     blinding_attr.AttributeType   = CSSM_ATTRIBUTE_RSA_BLINDING;
    202     blinding_attr.AttributeLength = sizeof(uint32);
    203     blinding_attr.Attribute.Uint32 = 1;
    204     if (CSSM_UpdateContextAttributes(
    205             cssm_signature.get(), 1, &blinding_attr) != CSSM_OK) {
    206       OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
    207       return 0;
    208     }
    209   }
    210 
    211   CSSM_DATA hash_data;
    212   hash_data.Length = in_len;
    213   hash_data.Data = const_cast<uint8*>(in);
    214 
    215   CSSM_DATA signature_data;
    216   signature_data.Length = max_out;
    217   signature_data.Data = out;
    218 
    219   if (CSSM_SignData(cssm_signature.get(), &hash_data, 1,
    220                     CSSM_ALGID_NONE, &signature_data) != CSSM_OK) {
    221     OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED);
    222     return 0;
    223   }
    224 
    225   *out_len = signature_data.Length;
    226   return 1;
    227 }
    228 
    229 // Custom RSA_METHOD that uses the platform APIs for signing.
    230 
    231 const KeyExData* RsaGetExData(const RSA* rsa) {
    232   return reinterpret_cast<const KeyExData*>(
    233       RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index()));
    234 }
    235 
    236 size_t RsaMethodSize(const RSA *rsa) {
    237   const KeyExData *ex_data = RsaGetExData(rsa);
    238   return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
    239 }
    240 
    241 int RsaMethodEncrypt(RSA* rsa,
    242                      size_t* out_len,
    243                      uint8_t* out,
    244                      size_t max_out,
    245                      const uint8_t* in,
    246                      size_t in_len,
    247                      int padding) {
    248   NOTIMPLEMENTED();
    249   OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
    250   return 0;
    251 }
    252 
    253 int RsaMethodSignRaw(RSA* rsa,
    254                      size_t* out_len,
    255                      uint8_t* out,
    256                      size_t max_out,
    257                      const uint8_t* in,
    258                      size_t in_len,
    259                      int padding) {
    260   // Only support PKCS#1 padding.
    261   DCHECK_EQ(RSA_PKCS1_PADDING, padding);
    262   if (padding != RSA_PKCS1_PADDING) {
    263     OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
    264     return 0;
    265   }
    266 
    267   const KeyExData *ex_data = RsaGetExData(rsa);
    268   if (!ex_data) {
    269     OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
    270     return 0;
    271   }
    272   DCHECK_EQ(CSSM_ALGID_RSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
    273 
    274   return MakeCSSMSignature(ex_data, out_len, out, max_out, in, in_len);
    275 }
    276 
    277 int RsaMethodDecrypt(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, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE);
    286   return 0;
    287 }
    288 
    289 int RsaMethodVerifyRaw(RSA* rsa,
    290                        size_t* out_len,
    291                        uint8_t* out,
    292                        size_t max_out,
    293                        const uint8_t* in,
    294                        size_t in_len,
    295                        int padding) {
    296   NOTIMPLEMENTED();
    297   OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE);
    298   return 0;
    299 }
    300 
    301 const RSA_METHOD mac_rsa_method = {
    302     {
    303      0 /* references */,
    304      1 /* is_static */
    305     } /* common */,
    306     NULL /* app_data */,
    307 
    308     NULL /* init */,
    309     NULL /* finish */,
    310     RsaMethodSize,
    311     NULL /* sign */,
    312     NULL /* verify */,
    313     RsaMethodEncrypt,
    314     RsaMethodSignRaw,
    315     RsaMethodDecrypt,
    316     RsaMethodVerifyRaw,
    317     NULL /* private_transform */,
    318     NULL /* mod_exp */,
    319     NULL /* bn_mod_exp */,
    320     RSA_FLAG_OPAQUE,
    321     NULL /* keygen */,
    322 };
    323 
    324 crypto::ScopedEVP_PKEY CreateRSAWrapper(SecKeyRef key,
    325                                         const CSSM_KEY* cssm_key) {
    326   crypto::ScopedRSA rsa(
    327       RSA_new_method(global_boringssl_engine.Get().engine()));
    328   if (!rsa)
    329     return crypto::ScopedEVP_PKEY();
    330 
    331   RSA_set_ex_data(
    332       rsa.get(), global_boringssl_engine.Get().rsa_ex_index(),
    333       new KeyExData(key, cssm_key));
    334 
    335   crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
    336   if (!pkey)
    337     return crypto::ScopedEVP_PKEY();
    338 
    339   if (!EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
    340     return crypto::ScopedEVP_PKEY();
    341 
    342   return pkey.Pass();
    343 }
    344 
    345 // Custom ECDSA_METHOD that uses the platform APIs.
    346 // Note that for now, only signing through ECDSA_sign() is really supported.
    347 // all other method pointers are either stubs returning errors, or no-ops.
    348 
    349 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) {
    350   return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data(
    351       ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
    352 }
    353 
    354 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
    355   const KeyExData* ex_data = EcKeyGetExData(ec_key);
    356   // LogicalKeySizeInBits is the size of an EC public key. But an
    357   // ECDSA signature length depends on the size of the base point's
    358   // order. For P-256, P-384, and P-521, these two sizes are the same.
    359   return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8;
    360 }
    361 
    362 int EcdsaMethodSign(const uint8_t* digest,
    363                     size_t digest_len,
    364                     uint8_t* sig,
    365                     unsigned int* sig_len,
    366                     EC_KEY* ec_key) {
    367   const KeyExData *ex_data = EcKeyGetExData(ec_key);
    368   if (!ex_data) {
    369     OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR);
    370     return 0;
    371   }
    372   DCHECK_EQ(CSSM_ALGID_ECDSA, ex_data->cssm_key->KeyHeader.AlgorithmId);
    373 
    374   // TODO(davidben): Fix BoringSSL to make sig_len a size_t*.
    375   size_t out_len;
    376   int ret = MakeCSSMSignature(
    377       ex_data, &out_len, sig, ECDSA_size(ec_key), digest, digest_len);
    378   if (!ret)
    379     return 0;
    380   *sig_len = out_len;
    381   return 1;
    382 }
    383 
    384 int EcdsaMethodVerify(const uint8_t* digest,
    385                       size_t digest_len,
    386                       const uint8_t* sig,
    387                       size_t sig_len,
    388                       EC_KEY* eckey) {
    389   NOTIMPLEMENTED();
    390   OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
    391   return 0;
    392 }
    393 
    394 const ECDSA_METHOD mac_ecdsa_method = {
    395     {
    396      0 /* references */,
    397      1 /* is_static */
    398     } /* common */,
    399     NULL /* app_data */,
    400 
    401     NULL /* init */,
    402     NULL /* finish */,
    403     EcdsaMethodGroupOrderSize,
    404     EcdsaMethodSign,
    405     EcdsaMethodVerify,
    406     ECDSA_FLAG_OPAQUE,
    407 };
    408 
    409 crypto::ScopedEVP_PKEY CreateECDSAWrapper(SecKeyRef key,
    410                                           const CSSM_KEY* cssm_key) {
    411   crypto::ScopedEC_KEY ec_key(
    412       EC_KEY_new_method(global_boringssl_engine.Get().engine()));
    413   if (!ec_key)
    414     return crypto::ScopedEVP_PKEY();
    415 
    416   EC_KEY_set_ex_data(
    417       ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(),
    418       new KeyExData(key, cssm_key));
    419 
    420   crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
    421   if (!pkey)
    422     return crypto::ScopedEVP_PKEY();
    423 
    424   if (!EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()))
    425     return crypto::ScopedEVP_PKEY();
    426 
    427   return pkey.Pass();
    428 }
    429 
    430 crypto::ScopedEVP_PKEY CreatePkeyWrapper(SecKeyRef key) {
    431   const CSSM_KEY* cssm_key;
    432   OSStatus status = SecKeyGetCSSMKey(key, &cssm_key);
    433   if (status != noErr)
    434     return crypto::ScopedEVP_PKEY();
    435 
    436   switch (cssm_key->KeyHeader.AlgorithmId) {
    437     case CSSM_ALGID_RSA:
    438       return CreateRSAWrapper(key, cssm_key);
    439     case CSSM_ALGID_ECDSA:
    440       return CreateECDSAWrapper(key, cssm_key);
    441     default:
    442       // TODO(davidben): Filter out anything other than ECDSA and RSA
    443       // elsewhere. We don't support other key types.
    444       NOTREACHED();
    445       LOG(ERROR) << "Unknown key type";
    446       return crypto::ScopedEVP_PKEY();
    447   }
    448 }
    449 
    450 }  // namespace
    451 
    452 crypto::ScopedEVP_PKEY FetchClientCertPrivateKey(
    453     const X509Certificate* certificate) {
    454   // Look up the private key.
    455   base::ScopedCFTypeRef<SecKeyRef> private_key(
    456       FetchSecKeyRefForCertificate(certificate));
    457   if (!private_key)
    458     return crypto::ScopedEVP_PKEY();
    459 
    460   // Create an EVP_PKEY wrapper.
    461   return CreatePkeyWrapper(private_key.get());
    462 }
    463 
    464 }  // namespace net
    465