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 <cryptohi.h>
      8 #include <keyhi.h>
      9 #include <pk11pub.h>
     10 #include <secmod.h>
     11 
     12 #include <list>
     13 
     14 #include "base/debug/leak_annotations.h"
     15 #include "base/logging.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/strings/string_util.h"
     18 #include "crypto/nss_util.h"
     19 #include "crypto/nss_util_internal.h"
     20 #include "crypto/scoped_nss_types.h"
     21 
     22 // TODO(rafaelw): Consider using NSS's ASN.1 encoder.
     23 namespace {
     24 
     25 static bool ReadAttribute(SECKEYPrivateKey* key,
     26                           CK_ATTRIBUTE_TYPE type,
     27                           std::vector<uint8>* output) {
     28   SECItem item;
     29   SECStatus rv;
     30   rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
     31   if (rv != SECSuccess) {
     32     NOTREACHED();
     33     return false;
     34   }
     35 
     36   output->assign(item.data, item.data + item.len);
     37   SECITEM_FreeItem(&item, PR_FALSE);
     38   return true;
     39 }
     40 
     41 }  // namespace
     42 
     43 namespace crypto {
     44 
     45 RSAPrivateKey::~RSAPrivateKey() {
     46   if (key_)
     47     SECKEY_DestroyPrivateKey(key_);
     48   if (public_key_)
     49     SECKEY_DestroyPublicKey(public_key_);
     50 }
     51 
     52 // static
     53 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
     54   return CreateWithParams(num_bits,
     55                           false /* not permanent */,
     56                           false /* not sensitive */);
     57 }
     58 
     59 // static
     60 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
     61     const std::vector<uint8>& input) {
     62   return CreateFromPrivateKeyInfoWithParams(input,
     63                                             false /* not permanent */,
     64                                             false /* not sensitive */);
     65 }
     66 
     67 #if defined(USE_NSS)
     68 // static
     69 RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) {
     70   return CreateWithParams(num_bits,
     71                           true /* permanent */,
     72                           true /* sensitive */);
     73 }
     74 
     75 // static
     76 RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
     77     const std::vector<uint8>& input) {
     78   return CreateFromPrivateKeyInfoWithParams(input,
     79                                             true /* permanent */,
     80                                             true /* sensitive */);
     81 }
     82 
     83 // static
     84 RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) {
     85   DCHECK(key);
     86   if (SECKEY_GetPrivateKeyType(key) != rsaKey)
     87     return NULL;
     88   RSAPrivateKey* copy = new RSAPrivateKey();
     89   copy->key_ = SECKEY_CopyPrivateKey(key);
     90   copy->public_key_ = SECKEY_ConvertToPublicKey(key);
     91   if (!copy->key_ || !copy->public_key_) {
     92     NOTREACHED();
     93     delete copy;
     94     return NULL;
     95   }
     96   return copy;
     97 }
     98 
     99 // static
    100 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo(
    101     const std::vector<uint8>& input) {
    102   EnsureNSSInit();
    103 
    104   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
    105 
    106   // First, decode and save the public key.
    107   SECItem key_der;
    108   key_der.type = siBuffer;
    109   key_der.data = const_cast<unsigned char*>(&input[0]);
    110   key_der.len = input.size();
    111 
    112   CERTSubjectPublicKeyInfo* spki =
    113       SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der);
    114   if (!spki) {
    115     NOTREACHED();
    116     return NULL;
    117   }
    118 
    119   result->public_key_ = SECKEY_ExtractPublicKey(spki);
    120   SECKEY_DestroySubjectPublicKeyInfo(spki);
    121   if (!result->public_key_) {
    122     NOTREACHED();
    123     return NULL;
    124   }
    125 
    126   // Make sure the key is an RSA key.  If not, that's an error
    127   if (result->public_key_->keyType != rsaKey) {
    128     NOTREACHED();
    129     return NULL;
    130   }
    131 
    132   ScopedSECItem ck_id(
    133       PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)));
    134   if (!ck_id.get()) {
    135     NOTREACHED();
    136     return NULL;
    137   }
    138 
    139   // Search all slots in all modules for the key with the given ID.
    140   AutoSECMODListReadLock auto_lock;
    141   SECMODModuleList* head = SECMOD_GetDefaultModuleList();
    142   for (SECMODModuleList* item = head; item != NULL; item = item->next) {
    143     int slot_count = item->module->loaded ? item->module->slotCount : 0;
    144     for (int i = 0; i < slot_count; i++) {
    145       // Finally...Look for the key!
    146       result->key_ = PK11_FindKeyByKeyID(item->module->slots[i],
    147                                          ck_id.get(), NULL);
    148       if (result->key_)
    149         return result.release();
    150     }
    151   }
    152 
    153   // We didn't find the key.
    154   return NULL;
    155 }
    156 #endif
    157 
    158 RSAPrivateKey* RSAPrivateKey::Copy() const {
    159   RSAPrivateKey* copy = new RSAPrivateKey();
    160   copy->key_ = SECKEY_CopyPrivateKey(key_);
    161   copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
    162   return copy;
    163 }
    164 
    165 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) const {
    166   PrivateKeyInfoCodec private_key_info(true);
    167 
    168   // Manually read the component attributes of the private key and build up
    169   // the PrivateKeyInfo.
    170   if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
    171       !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
    172           private_key_info.public_exponent()) ||
    173       !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
    174           private_key_info.private_exponent()) ||
    175       !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
    176       !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
    177       !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
    178       !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
    179       !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
    180     NOTREACHED();
    181     return false;
    182   }
    183 
    184   return private_key_info.Export(output);
    185 }
    186 
    187 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) const {
    188   ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
    189   if (!der_pubkey.get()) {
    190     NOTREACHED();
    191     return false;
    192   }
    193 
    194   output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
    195   return true;
    196 }
    197 
    198 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
    199   EnsureNSSInit();
    200 }
    201 
    202 // static
    203 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits,
    204                                                bool permanent,
    205                                                bool sensitive) {
    206 #if !defined(USE_NSS)
    207   if (permanent) {
    208     NOTIMPLEMENTED();
    209     return NULL;
    210   }
    211 #endif
    212 
    213   EnsureNSSInit();
    214 
    215   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
    216 
    217   ScopedPK11Slot slot(permanent ? GetPrivateNSSKeySlot() :
    218                       PK11_GetInternalSlot());
    219   if (!slot.get())
    220     return NULL;
    221 
    222   PK11RSAGenParams param;
    223   param.keySizeInBits = num_bits;
    224   param.pe = 65537L;
    225   result->key_ = PK11_GenerateKeyPair(slot.get(),
    226                                       CKM_RSA_PKCS_KEY_PAIR_GEN,
    227                                       &param,
    228                                       &result->public_key_,
    229                                       permanent,
    230                                       sensitive,
    231                                       NULL);
    232   if (!result->key_)
    233     return NULL;
    234 
    235   return result.release();
    236 }
    237 
    238 // static
    239 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
    240     const std::vector<uint8>& input, bool permanent, bool sensitive) {
    241 #if !defined(USE_NSS)
    242   if (permanent) {
    243     NOTIMPLEMENTED();
    244     return NULL;
    245   }
    246 #endif
    247 
    248   // This method currently leaks some memory.
    249   // See http://crbug.com/34742.
    250   ANNOTATE_SCOPED_MEMORY_LEAK;
    251   EnsureNSSInit();
    252 
    253   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
    254 
    255   ScopedPK11Slot slot(permanent ? GetPrivateNSSKeySlot() :
    256                       PK11_GetInternalSlot());
    257   if (!slot.get())
    258     return NULL;
    259 
    260   SECItem der_private_key_info;
    261   der_private_key_info.data = const_cast<unsigned char*>(&input.front());
    262   der_private_key_info.len = input.size();
    263   // Allow the private key to be used for key unwrapping, data decryption,
    264   // and signature generation.
    265   const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
    266                                  KU_DIGITAL_SIGNATURE;
    267   SECStatus rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(
    268       slot.get(), &der_private_key_info, NULL, NULL, permanent, sensitive,
    269       key_usage, &result->key_, NULL);
    270   if (rv != SECSuccess) {
    271     NOTREACHED();
    272     return NULL;
    273   }
    274 
    275   result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
    276   if (!result->public_key_) {
    277     NOTREACHED();
    278     return NULL;
    279   }
    280 
    281   return result.release();
    282 }
    283 
    284 }  // namespace crypto
    285