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.
5 #include "crypto/rsa_private_key.h"
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"
22 // TODO(rafaelw): Consider using NSS's ASN.1 encoder.
25 static bool ReadAttribute(SECKEYPrivateKey
* key
,
26 CK_ATTRIBUTE_TYPE type
,
27 std::vector
<uint8
>* output
) {
30 rv
= PK11_ReadRawAttribute(PK11_TypePrivKey
, key
, type
, &item
);
31 if (rv
!= SECSuccess
) {
36 output
->assign(item
.data
, item
.data
+ item
.len
);
37 SECITEM_FreeItem(&item
, PR_FALSE
);
45 RSAPrivateKey::~RSAPrivateKey() {
47 SECKEY_DestroyPrivateKey(key_
);
49 SECKEY_DestroyPublicKey(public_key_
);
53 RSAPrivateKey
* RSAPrivateKey::Create(uint16 num_bits
) {
54 return CreateWithParams(num_bits
,
55 false /* not permanent */,
56 false /* not sensitive */);
60 RSAPrivateKey
* RSAPrivateKey::CreateFromPrivateKeyInfo(
61 const std::vector
<uint8
>& input
) {
62 return CreateFromPrivateKeyInfoWithParams(input
,
63 false /* not permanent */,
64 false /* not sensitive */);
69 RSAPrivateKey
* RSAPrivateKey::CreateSensitive(uint16 num_bits
) {
70 return CreateWithParams(num_bits
,
72 true /* sensitive */);
76 RSAPrivateKey
* RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(
77 const std::vector
<uint8
>& input
) {
78 return CreateFromPrivateKeyInfoWithParams(input
,
80 true /* sensitive */);
84 RSAPrivateKey
* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey
* key
) {
86 if (SECKEY_GetPrivateKeyType(key
) != rsaKey
)
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_
) {
100 RSAPrivateKey
* RSAPrivateKey::FindFromPublicKeyInfo(
101 const std::vector
<uint8
>& input
) {
104 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
106 // First, decode and save the public key.
108 key_der
.type
= siBuffer
;
109 key_der
.data
= const_cast<unsigned char*>(&input
[0]);
110 key_der
.len
= input
.size();
112 CERTSubjectPublicKeyInfo
* spki
=
113 SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der
);
119 result
->public_key_
= SECKEY_ExtractPublicKey(spki
);
120 SECKEY_DestroySubjectPublicKeyInfo(spki
);
121 if (!result
->public_key_
) {
126 // Make sure the key is an RSA key. If not, that's an error
127 if (result
->public_key_
->keyType
!= rsaKey
) {
133 PK11_MakeIDFromPubKey(&(result
->public_key_
->u
.rsa
.modulus
)));
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
],
149 return result
.release();
153 // We didn't find the key.
158 RSAPrivateKey
* RSAPrivateKey::Copy() const {
159 RSAPrivateKey
* copy
= new RSAPrivateKey();
160 copy
->key_
= SECKEY_CopyPrivateKey(key_
);
161 copy
->public_key_
= SECKEY_CopyPublicKey(public_key_
);
165 bool RSAPrivateKey::ExportPrivateKey(std::vector
<uint8
>* output
) const {
166 PrivateKeyInfoCodec
private_key_info(true);
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())) {
184 return private_key_info
.Export(output
);
187 bool RSAPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) const {
188 ScopedSECItem
der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_
));
189 if (!der_pubkey
.get()) {
194 output
->assign(der_pubkey
->data
, der_pubkey
->data
+ der_pubkey
->len
);
198 RSAPrivateKey::RSAPrivateKey() : key_(NULL
), public_key_(NULL
) {
203 RSAPrivateKey
* RSAPrivateKey::CreateWithParams(uint16 num_bits
,
206 #if !defined(USE_NSS)
215 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
217 ScopedPK11Slot
slot(permanent
? GetPrivateNSSKeySlot() :
218 PK11_GetInternalSlot());
222 PK11RSAGenParams param
;
223 param
.keySizeInBits
= num_bits
;
225 result
->key_
= PK11_GenerateKeyPair(slot
.get(),
226 CKM_RSA_PKCS_KEY_PAIR_GEN
,
228 &result
->public_key_
,
235 return result
.release();
239 RSAPrivateKey
* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
240 const std::vector
<uint8
>& input
, bool permanent
, bool sensitive
) {
241 #if !defined(USE_NSS)
248 // This method currently leaks some memory.
249 // See http://crbug.com/34742.
250 ANNOTATE_SCOPED_MEMORY_LEAK
;
253 scoped_ptr
<RSAPrivateKey
> result(new RSAPrivateKey
);
255 ScopedPK11Slot
slot(permanent
? GetPrivateNSSKeySlot() :
256 PK11_GetInternalSlot());
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
) {
275 result
->public_key_
= SECKEY_ConvertToPublicKey(result
->key_
);
276 if (!result
->public_key_
) {
281 return result
.release();
284 } // namespace crypto