OLD | NEW |
| (Empty) |
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 "base/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/nss_util.h" | |
17 #include "base/nss_util_internal.h" | |
18 #include "base/string_util.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 base { | |
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 /* seneitive */); | |
79 } | |
80 | |
81 // static | |
82 RSAPrivateKey* RSAPrivateKey::FindFromPublicKeyInfo( | |
83 const std::vector<uint8>& input) { | |
84 base::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 NSS DB. If it's | |
109 // not there, consider that an error. | |
110 PK11SlotInfo *slot = GetPrivateNSSKeySlot(); | |
111 if (!slot) { | |
112 NOTREACHED(); | |
113 return NULL; | |
114 } | |
115 | |
116 // Make sure the key is an RSA key. If not, that's an error | |
117 if (result->public_key_->keyType != rsaKey) { | |
118 PK11_FreeSlot(slot); | |
119 NOTREACHED(); | |
120 return NULL; | |
121 } | |
122 | |
123 SECItem *ck_id = PK11_MakeIDFromPubKey(&(result->public_key_->u.rsa.modulus)); | |
124 if (!ck_id) { | |
125 PK11_FreeSlot(slot); | |
126 NOTREACHED(); | |
127 return NULL; | |
128 } | |
129 | |
130 // Finally...Look for the key! | |
131 result->key_ = PK11_FindKeyByKeyID(slot, ck_id, NULL); | |
132 | |
133 // Cleanup... | |
134 PK11_FreeSlot(slot); | |
135 SECITEM_FreeItem(ck_id, PR_TRUE); | |
136 | |
137 // If we didn't find it, that's ok. | |
138 if (!result->key_) | |
139 return NULL; | |
140 | |
141 return result.release(); | |
142 } | |
143 | |
144 | |
145 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) { | |
146 PrivateKeyInfoCodec private_key_info(true); | |
147 | |
148 // Manually read the component attributes of the private key and build up | |
149 // the PrivateKeyInfo. | |
150 if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) || | |
151 !ReadAttribute(key_, CKA_PUBLIC_EXPONENT, | |
152 private_key_info.public_exponent()) || | |
153 !ReadAttribute(key_, CKA_PRIVATE_EXPONENT, | |
154 private_key_info.private_exponent()) || | |
155 !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) || | |
156 !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) || | |
157 !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) || | |
158 !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) || | |
159 !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) { | |
160 NOTREACHED(); | |
161 return false; | |
162 } | |
163 | |
164 return private_key_info.Export(output); | |
165 } | |
166 | |
167 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) { | |
168 SECItem* der_pubkey = SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_); | |
169 if (!der_pubkey) { | |
170 NOTREACHED(); | |
171 return false; | |
172 } | |
173 | |
174 for (size_t i = 0; i < der_pubkey->len; ++i) | |
175 output->push_back(der_pubkey->data[i]); | |
176 | |
177 SECITEM_FreeItem(der_pubkey, PR_TRUE); | |
178 return true; | |
179 } | |
180 | |
181 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) { | |
182 EnsureNSSInit(); | |
183 } | |
184 | |
185 // static | |
186 RSAPrivateKey* RSAPrivateKey::CreateWithParams(uint16 num_bits, | |
187 bool permanent, | |
188 bool sensitive) { | |
189 base::EnsureNSSInit(); | |
190 | |
191 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); | |
192 | |
193 PK11SlotInfo *slot = GetPrivateNSSKeySlot(); | |
194 if (!slot) | |
195 return NULL; | |
196 | |
197 PK11RSAGenParams param; | |
198 param.keySizeInBits = num_bits; | |
199 param.pe = 65537L; | |
200 result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, | |
201 &result->public_key_, permanent, sensitive, NULL); | |
202 PK11_FreeSlot(slot); | |
203 if (!result->key_) | |
204 return NULL; | |
205 | |
206 return result.release(); | |
207 } | |
208 | |
209 // static | |
210 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams( | |
211 const std::vector<uint8>& input, bool permanent, bool sensitive) { | |
212 // This method currently leaks some memory. | |
213 // See http://crbug.com/34742. | |
214 ANNOTATE_SCOPED_MEMORY_LEAK; | |
215 base::EnsureNSSInit(); | |
216 | |
217 scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); | |
218 | |
219 PK11SlotInfo *slot = GetPrivateNSSKeySlot(); | |
220 if (!slot) | |
221 return NULL; | |
222 | |
223 SECItem der_private_key_info; | |
224 der_private_key_info.data = const_cast<unsigned char*>(&input.front()); | |
225 der_private_key_info.len = input.size(); | |
226 // Allow the private key to be used for key unwrapping, data decryption, | |
227 // and signature generation. | |
228 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | | |
229 KU_DIGITAL_SIGNATURE; | |
230 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( | |
231 slot, &der_private_key_info, NULL, NULL, permanent, sensitive, | |
232 key_usage, &result->key_, NULL); | |
233 PK11_FreeSlot(slot); | |
234 if (rv != SECSuccess) { | |
235 NOTREACHED(); | |
236 return NULL; | |
237 } | |
238 | |
239 result->public_key_ = SECKEY_ConvertToPublicKey(result->key_); | |
240 if (!result->public_key_) { | |
241 NOTREACHED(); | |
242 return NULL; | |
243 } | |
244 | |
245 return result.release(); | |
246 } | |
247 | |
248 } // namespace base | |
OLD | NEW |