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