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. 23namespace { 24 25static 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 43namespace crypto { 44 45RSAPrivateKey::~RSAPrivateKey() { 46 if (key_) 47 SECKEY_DestroyPrivateKey(key_); 48 if (public_key_) 49 SECKEY_DestroyPublicKey(public_key_); 50} 51 52// static 53RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { 54 return CreateWithParams(num_bits, 55 false /* not permanent */, 56 false /* not sensitive */); 57} 58 59// static 60RSAPrivateKey* 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 69RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { 70 return CreateWithParams(num_bits, 71 true /* permanent */, 72 true /* sensitive */); 73} 74 75// static 76RSAPrivateKey* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo( 77 const std::vector<uint8>& input) { 78 return CreateFromPrivateKeyInfoWithParams(input, 79 true /* permanent */, 80 true /* sensitive */); 81} 82 83// static 84RSAPrivateKey* 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 100RSAPrivateKey* 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 158RSAPrivateKey* 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 165bool 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 187bool 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 198RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { 199 EnsureNSSInit(); 200} 201 202// static 203RSAPrivateKey* 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 ¶m, 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 239RSAPrivateKey* 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