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, ¶m, 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