Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 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 "crypto/rsa_private_key.h"
      6 
      7 #include <list>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "crypto/cssm_init.h"
     12 
     13 namespace crypto {
     14 
     15 // static
     16 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
     17   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     18 
     19   CSSM_CC_HANDLE cc_handle;
     20   CSSM_RETURN crtn;
     21   crtn = CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA,
     22                                       num_bits, NULL, NULL, NULL, NULL, NULL,
     23                                       &cc_handle);
     24   if (crtn) {
     25     NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn;
     26     return NULL;
     27   }
     28 
     29   CSSM_DATA label = { 9,
     30       const_cast<uint8*>(reinterpret_cast<const uint8*>("temp_key")) };
     31   crtn = CSSM_GenerateKeyPair(cc_handle,
     32       CSSM_KEYUSE_VERIFY,
     33       CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label,
     34       result->public_key(), CSSM_KEYUSE_SIGN,
     35       CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label, NULL,
     36       result->key());
     37   CSSM_DeleteContext(cc_handle);
     38   if (crtn) {
     39     NOTREACHED() << "CSSM_CSP_CreateKeyGenContext failed: " << crtn;
     40     return NULL;
     41   }
     42 
     43   return result.release();
     44 }
     45 
     46 // static
     47 RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
     48   NOTIMPLEMENTED();
     49   return NULL;
     50 }
     51 
     52 // static
     53 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
     54     const std::vector<uint8>& input) {
     55   if (input.empty())
     56     return NULL;
     57 
     58   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     59 
     60   CSSM_KEY key;
     61   memset(&key, 0, sizeof(key));
     62   key.KeyData.Data = const_cast<uint8*>(&input.front());
     63   key.KeyData.Length = input.size();
     64   key.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
     65   key.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
     66   key.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
     67   key.KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
     68   key.KeyHeader.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
     69   key.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
     70   key.KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
     71 
     72   CSSM_KEY_SIZE key_size;
     73   CSSM_RETURN crtn;
     74   crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, &key, &key_size);
     75   if (crtn) {
     76     NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn;
     77     return NULL;
     78   }
     79   key.KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
     80 
     81   // Perform a NULL unwrap operation on the key so that result's key_
     82   // instance variable points to a key that can be released via CSSM_FreeKey().
     83   CSSM_ACCESS_CREDENTIALS creds;
     84   memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
     85   CSSM_CC_HANDLE cc_handle;
     86   crtn = CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE,
     87       CSSM_ALGMODE_NONE, &creds, NULL, NULL, CSSM_PADDING_NONE, 0, &cc_handle);
     88   if (crtn) {
     89     NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn;
     90     return NULL;
     91   }
     92   CSSM_DATA label_data, desc_data = { 0, NULL };
     93   label_data.Data =
     94       const_cast<uint8*>(reinterpret_cast<const uint8*>("unwrapped"));
     95   label_data.Length = 9;
     96   crtn = CSSM_UnwrapKey(cc_handle, NULL, &key, CSSM_KEYUSE_ANY,
     97       CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, &label_data,
     98       NULL, result->key(), &desc_data);
     99   if (crtn) {
    100     NOTREACHED() << "CSSM_UnwrapKey failed: " << crtn;
    101     return NULL;
    102   }
    103 
    104   // Extract a public key from the private key.
    105   // Apple doesn't accept CSSM_KEYBLOB_RAW_FORMAT_X509 as a valid key
    106   // format when attempting to generate certs, so use PKCS1 instead.
    107   PrivateKeyInfoCodec codec(true);
    108   std::vector<uint8> private_key_data;
    109   private_key_data.assign(key.KeyData.Data,
    110                           key.KeyData.Data + key.KeyData.Length);
    111   if (!codec.Import(private_key_data)) {
    112     return NULL;
    113   }
    114   std::vector<uint8> public_key_data;
    115   if (!codec.ExportPublicKey(&public_key_data)) {
    116     return NULL;
    117   }
    118 
    119   CSSM_KEY* public_key = result->public_key();
    120   size_t size = public_key_data.size();
    121   public_key->KeyData.Data = reinterpret_cast<uint8*>(CSSMMalloc(size));
    122   if (!public_key->KeyData.Data) {
    123     NOTREACHED() << "CSSMMalloc failed";
    124     return NULL;
    125   }
    126   memcpy(public_key->KeyData.Data, &public_key_data.front(), size);
    127   public_key->KeyData.Length = size;
    128   public_key->KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
    129   public_key->KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
    130   public_key->KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
    131   public_key->KeyHeader.AlgorithmId = CSSM_ALGID_RSA;
    132   public_key->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
    133   public_key->KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
    134   public_key->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
    135 
    136   crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, public_key,
    137                                  &key_size);
    138   if (crtn) {
    139     DLOG(ERROR) << "CSSM_QueryKeySizeInBits failed " << crtn;
    140     return NULL;
    141   }
    142   public_key->KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
    143 
    144   return result.release();
    145 }
    146 
    147 // static
    148 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
    149     const std::vector<uint8>& input) {
    150   NOTIMPLEMENTED();
    151   return NULL;
    152 }
    153 
    154 // static
    155 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
    156     const std::vector<uint8>& input) {
    157   NOTIMPLEMENTED();
    158   return NULL;
    159 }
    160 
    161 RSAPrivateKey::RSAPrivateKey() {
    162   memset(&key_, 0, sizeof(key_));
    163   memset(&public_key_, 0, sizeof(public_key_));
    164 
    165   EnsureCSSMInit();
    166 }
    167 
    168 RSAPrivateKey::~RSAPrivateKey() {
    169   if (key_.KeyData.Data) {
    170     CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE);
    171   }
    172   if (public_key_.KeyData.Data) {
    173     CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key_, CSSM_FALSE);
    174   }
    175 }
    176 
    177 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
    178   if (!key_.KeyData.Data || !key_.KeyData.Length) {
    179     return false;
    180   }
    181   output->clear();
    182   output->insert(output->end(), key_.KeyData.Data,
    183                 key_.KeyData.Data + key_.KeyData.Length);
    184   return true;
    185 }
    186 
    187 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
    188   PrivateKeyInfoCodec private_key_info(true);
    189   std::vector<uint8> private_key_data;
    190   private_key_data.assign(key_.KeyData.Data,
    191                           key_.KeyData.Data + key_.KeyData.Length);
    192   return (private_key_info.Import(private_key_data) &&
    193           private_key_info.ExportPublicKeyInfo(output));
    194 }
    195 
    196 }  // namespace crypto
    197