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 "crypto/ec_private_key.h" | |
6 | |
7 extern "C" { | |
8 // Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before | |
9 // other NSS headers. | |
10 #include <secmodt.h> | |
11 } | |
12 | |
13 #include <cryptohi.h> | |
14 #include <keyhi.h> | |
15 #include <pk11pub.h> | |
16 #include <secmod.h> | |
17 | |
18 #include "base/logging.h" | |
19 #include "base/memory/scoped_ptr.h" | |
20 #include "crypto/nss_util.h" | |
21 #include "crypto/nss_util_internal.h" | |
22 #include "crypto/scoped_nss_types.h" | |
23 #include "crypto/third_party/nss/chromium-nss.h" | |
24 | |
25 namespace { | |
26 | |
27 // Copied from rsa_private_key_nss.cc. | |
28 static bool ReadAttribute(SECKEYPrivateKey* key, | |
29 CK_ATTRIBUTE_TYPE type, | |
30 std::vector<uint8>* output) { | |
31 SECItem item; | |
32 SECStatus rv; | |
33 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item); | |
34 if (rv != SECSuccess) { | |
35 DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError(); | |
36 return false; | |
37 } | |
38 | |
39 output->assign(item.data, item.data + item.len); | |
40 SECITEM_FreeItem(&item, PR_FALSE); | |
41 return true; | |
42 } | |
43 | |
44 } // namespace | |
45 | |
46 namespace crypto { | |
47 | |
48 ECPrivateKey::~ECPrivateKey() { | |
49 if (key_) | |
50 SECKEY_DestroyPrivateKey(key_); | |
51 if (public_key_) | |
52 SECKEY_DestroyPublicKey(public_key_); | |
53 } | |
54 | |
55 // static | |
56 ECPrivateKey* ECPrivateKey::Create() { | |
57 return CreateWithParams(PR_FALSE /* not permanent */, | |
58 PR_FALSE /* not sensitive */); | |
59 } | |
60 | |
61 // static | |
62 ECPrivateKey* ECPrivateKey::CreateSensitive() { | |
63 #if defined(USE_NSS) | |
64 return CreateWithParams(PR_TRUE /* permanent */, | |
65 PR_TRUE /* sensitive */); | |
66 #else | |
67 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't | |
68 // create permanent keys. | |
69 NOTREACHED(); | |
wtc
2011/11/08 23:21:18
Perhaps we should remove the CreateSensitive() and
| |
70 return NULL; | |
71 #endif | |
72 } | |
73 | |
74 // static | |
75 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( | |
76 const std::string& password, | |
77 const std::vector<uint8>& encrypted_private_key_info, | |
78 const std::vector<uint8>& subject_public_key_info) { | |
79 return CreateFromEncryptedPrivateKeyInfoWithParams( | |
80 password, | |
81 encrypted_private_key_info, | |
82 subject_public_key_info, | |
83 PR_FALSE /* not permanent */, | |
84 PR_FALSE /* not sensitive */); | |
85 } | |
86 | |
87 // static | |
88 ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo( | |
89 const std::string& password, | |
90 const std::vector<uint8>& encrypted_private_key_info, | |
91 const std::vector<uint8>& subject_public_key_info) { | |
92 #if defined(USE_NSS) | |
93 return CreateFromEncryptedPrivateKeyInfoWithParams( | |
94 password, | |
95 encrypted_private_key_info, | |
96 subject_public_key_info, | |
97 PR_TRUE /* permanent */, | |
98 PR_TRUE /* sensitive */); | |
99 #else | |
100 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't | |
101 // create permanent keys. | |
102 NOTREACHED(); | |
103 return NULL; | |
104 #endif | |
105 } | |
106 | |
107 bool ECPrivateKey::ExportEncryptedPrivateKey( | |
108 const std::string& password, | |
109 int iterations, | |
110 std::vector<uint8>* output) { | |
111 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8 | |
112 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't | |
113 // support EC keys. | |
114 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773 | |
115 SECItem password_item = { | |
116 siBuffer, | |
117 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), | |
118 password.size() | |
119 }; | |
120 | |
121 SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo( | |
122 NULL, // Slot, optional. | |
123 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC, | |
124 &password_item, | |
125 key_, | |
126 iterations, | |
127 NULL); // wincx. | |
128 | |
129 if (!encrypted) { | |
130 DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError(); | |
131 return false; | |
132 } | |
133 | |
134 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); | |
135 SECItem der_key = {siBuffer, NULL, 0}; | |
136 SECItem* encoded_item = SEC_ASN1EncodeItem( | |
137 arena.get(), | |
138 &der_key, | |
139 encrypted, | |
140 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate)); | |
141 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE); | |
142 if (!encoded_item) { | |
143 DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError(); | |
144 return false; | |
145 } | |
146 | |
147 output->assign(der_key.data, der_key.data + der_key.len); | |
148 | |
149 return true; | |
150 } | |
151 | |
152 bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) { | |
153 ScopedSECItem der_pubkey( | |
154 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_)); | |
155 if (!der_pubkey.get()) { | |
156 return false; | |
157 } | |
158 | |
159 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len); | |
160 return true; | |
161 } | |
162 | |
163 bool ECPrivateKey::ExportValue(std::vector<uint8>* output) { | |
164 return ReadAttribute(key_, CKA_VALUE, output); | |
165 } | |
166 | |
167 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) { | |
168 return ReadAttribute(key_, CKA_EC_PARAMS, output); | |
169 } | |
170 | |
171 ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {} | |
172 | |
173 // static | |
174 ECPrivateKey* ECPrivateKey::CreateWithParams(bool permanent, | |
175 bool sensitive) { | |
176 EnsureNSSInit(); | |
177 | |
178 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); | |
179 | |
180 ScopedPK11Slot slot(GetPrivateNSSKeySlot()); | |
181 if (!slot.get()) | |
182 return NULL; | |
183 | |
184 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); | |
185 if (!oid_data) { | |
186 DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError(); | |
187 return NULL; | |
188 } | |
189 | |
190 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters | |
191 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve. | |
192 // The in addition to the oid data, the encoding requires one byte for the | |
wtc
2011/11/08 23:21:18
Typo: The in => In
mattm
2011/11/09 04:11:35
Done.
| |
193 // ASN.1 tag and one byte for the length (assuming the length is <= 127). | |
194 DCHECK_LE(oid_data->oid.len, 127U); | |
195 std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len); | |
196 SECKEYECParams ec_parameters = { | |
197 siDEROID, ¶meters_buf[0], parameters_buf.size() | |
198 }; | |
199 | |
200 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID; | |
201 ec_parameters.data[1] = oid_data->oid.len; | |
202 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len); | |
203 | |
204 result->key_ = PK11_GenerateKeyPair(slot.get(), | |
205 CKM_EC_KEY_PAIR_GEN, | |
206 &ec_parameters, | |
207 &result->public_key_, | |
208 permanent, | |
209 sensitive, | |
210 NULL); | |
211 if (!result->key_) { | |
212 DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError(); | |
213 return NULL; | |
214 } | |
215 | |
216 return result.release(); | |
217 } | |
218 | |
219 // static | |
220 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams( | |
221 const std::string& password, | |
222 const std::vector<uint8>& encrypted_private_key_info, | |
223 const std::vector<uint8>& subject_public_key_info, | |
224 bool permanent, | |
225 bool sensitive) { | |
226 EnsureNSSInit(); | |
227 | |
228 scoped_ptr<ECPrivateKey> result(new ECPrivateKey); | |
229 | |
230 ScopedPK11Slot slot(GetPrivateNSSKeySlot()); | |
231 if (!slot.get()) | |
232 return NULL; | |
233 | |
234 SECItem encoded_spki = { | |
235 siBuffer, | |
236 const_cast<unsigned char*>(&subject_public_key_info[0]), | |
237 subject_public_key_info.size() | |
238 }; | |
239 CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo( | |
240 &encoded_spki); | |
241 if (!decoded_spki) { | |
242 DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError(); | |
243 return NULL; | |
244 } | |
245 | |
246 result->public_key_ = SECKEY_ExtractPublicKey(decoded_spki); | |
247 | |
248 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki); | |
249 | |
250 if (!result->public_key_) { | |
251 DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError(); | |
252 return NULL; | |
253 } | |
254 | |
255 SECItem encoded_epki = { | |
256 siBuffer, | |
257 const_cast<unsigned char*>(&encrypted_private_key_info[0]), | |
258 encrypted_private_key_info.size() | |
259 }; | |
260 SECKEYEncryptedPrivateKeyInfo epki; | |
261 memset(&epki, 0, sizeof(epki)); | |
262 | |
263 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); | |
264 | |
265 SECStatus rv = SEC_QuickDERDecodeItem( | |
266 arena.get(), | |
267 &epki, | |
268 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), | |
269 &encoded_epki); | |
270 if (rv != SECSuccess) { | |
271 DLOG(ERROR) << "SEC_ASN1DecodeItem: " << PORT_GetError(); | |
272 return NULL; | |
273 } | |
274 | |
275 SECItem password_item = { | |
276 siBuffer, | |
277 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())), | |
278 password.size() | |
279 }; | |
280 | |
281 rv = ImportEncryptedECPrivateKeyInfoAndReturnKey( | |
282 slot.get(), | |
283 &epki, | |
284 &password_item, | |
285 NULL, // nickname | |
286 &result->public_key_->u.ec.publicValue, | |
287 permanent, | |
288 sensitive, | |
289 &result->key_, | |
290 NULL); // wincx | |
291 if (rv != SECSuccess) { | |
292 DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: " | |
293 << PORT_GetError(); | |
294 return NULL; | |
295 } | |
296 | |
297 return result.release(); | |
298 } | |
299 | |
300 } // namespace crypto | |
OLD | NEW |