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 <stdint.h> 11 12 #include <list> 13 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/strings/string_util.h" 17 #include "crypto/nss_key_util.h" 18 #include "crypto/nss_util.h" 19 #include "crypto/scoped_nss_types.h" 20 21 // TODO(rafaelw): Consider using NSS's ASN.1 encoder. 22 namespace { 23 24 static bool ReadAttribute(SECKEYPrivateKey* key, 25 CK_ATTRIBUTE_TYPE type, 26 std::vector<uint8_t>* 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_t num_bits) { 53 EnsureNSSInit(); 54 55 ScopedPK11Slot slot(PK11_GetInternalSlot()); 56 if (!slot) { 57 NOTREACHED(); 58 return nullptr; 59 } 60 61 ScopedSECKEYPublicKey public_key; 62 ScopedSECKEYPrivateKey private_key; 63 if (!GenerateRSAKeyPairNSS(slot.get(), num_bits, false /* not permanent */, 64 &public_key, &private_key)) { 65 return nullptr; 66 } 67 68 RSAPrivateKey* rsa_key = new RSAPrivateKey; 69 rsa_key->public_key_ = public_key.release(); 70 rsa_key->key_ = private_key.release(); 71 return rsa_key; 72 } 73 74 // static 75 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( 76 const std::vector<uint8_t>& input) { 77 EnsureNSSInit(); 78 79 ScopedPK11Slot slot(PK11_GetInternalSlot()); 80 if (!slot) { 81 NOTREACHED(); 82 return nullptr; 83 } 84 ScopedSECKEYPrivateKey key(ImportNSSKeyFromPrivateKeyInfo( 85 slot.get(), input, false /* not permanent */)); 86 if (!key || SECKEY_GetPrivateKeyType(key.get()) != rsaKey) 87 return nullptr; 88 return RSAPrivateKey::CreateFromKey(key.get()); 89 } 90 91 // static 92 RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) { 93 DCHECK(key); 94 if (SECKEY_GetPrivateKeyType(key) != rsaKey) 95 return NULL; 96 RSAPrivateKey* copy = new RSAPrivateKey(); 97 copy->key_ = SECKEY_CopyPrivateKey(key); 98 copy->public_key_ = SECKEY_ConvertToPublicKey(key); 99 if (!copy->key_ || !copy->public_key_) { 100 NOTREACHED(); 101 delete copy; 102 return NULL; 103 } 104 return copy; 105 } 106 107 RSAPrivateKey* RSAPrivateKey::Copy() const { 108 RSAPrivateKey* copy = new RSAPrivateKey(); 109 copy->key_ = SECKEY_CopyPrivateKey(key_); 110 copy->public_key_ = SECKEY_CopyPublicKey(public_key_); 111 return copy; 112 } 113 114 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { 115 PrivateKeyInfoCodec private_key_info(true); 116 117 // Manually read the component attributes of the private key and build up 118 // the PrivateKeyInfo. 119 if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) || 120 !ReadAttribute(key_, CKA_PUBLIC_EXPONENT, 121 private_key_info.public_exponent()) || 122 !ReadAttribute(key_, CKA_PRIVATE_EXPONENT, 123 private_key_info.private_exponent()) || 124 !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) || 125 !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) || 126 !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) || 127 !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) || 128 !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) { 129 NOTREACHED(); 130 return false; 131 } 132 133 return private_key_info.Export(output); 134 } 135 136 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { 137 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); 138 if (!der_pubkey.get()) { 139 NOTREACHED(); 140 return false; 141 } 142 143 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); 144 return true; 145 } 146 147 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { 148 EnsureNSSInit(); 149 } 150 151 } // namespace crypto 152