Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: crypto/ec_private_key_nss.cc

Issue 8413024: Add ECPrivateKey for Elliptic Curve keypair generation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review changes Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 #include <cryptohi.h>
13 #include <keyhi.h>
14 #include <pk11pub.h>
15 #include <secmod.h>
16
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "crypto/nss_util.h"
20 #include "crypto/nss_util_internal.h"
21 #include "crypto/scoped_nss_types.h"
22 #include "crypto/third_party/nss/ec.h"
23
24 namespace {
25
26 // Copied from rsa_private_key_nss.cc.
27 static bool ReadAttribute(SECKEYPrivateKey* key,
28 CK_ATTRIBUTE_TYPE type,
29 std::vector<uint8>* output) {
30 SECItem item;
31 SECStatus rv;
32 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
33 if (rv != SECSuccess) {
34 NOTREACHED() << "error: " << PORT_GetError();
35 return false;
36 }
37
38 output->assign(item.data, item.data + item.len);
39 SECITEM_FreeItem(&item, PR_FALSE);
40 return true;
41 }
42
43 } // namespace
44
45 namespace crypto {
46
47 ECPrivateKey::~ECPrivateKey() {
48 if (key_)
49 SECKEY_DestroyPrivateKey(key_);
50 if (public_key_)
51 SECKEY_DestroyPublicKey(public_key_);
Ryan Sleevi 2011/11/04 03:21:25 Don't need this when using the Scoped types
mattm 2011/11/08 02:12:27 Done.
52 }
53
54 // static
55 ECPrivateKey* ECPrivateKey::Create() {
56 return CreateWithParams(PR_FALSE /* not permanent */,
57 PR_FALSE /* not sensitive */);
58 }
59
60 // static
61 ECPrivateKey* ECPrivateKey::CreateSensitive() {
62 #if defined(USE_NSS)
63 return CreateWithParams(PR_TRUE /* permanent */,
64 PR_TRUE /* sensitive */);
65 #else
66 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't
67 // create permanent keys.
68 NOTIMPLEMENTED();
Ryan Sleevi 2011/11/04 03:21:25 If this will never be implemented, should it be a
wtc 2011/11/04 21:52:49 I think you're right. NOTREACHED() seems more app
mattm 2011/11/08 02:12:27 Done.
69 return NULL;
70 #endif
71 }
72
73 // static
74 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
75 const std::string& password,
76 const std::vector<uint8>& encrypted_private_key_info,
77 const std::vector<uint8>& subject_public_key_info) {
78 return CreateFromEncryptedPrivateKeyInfoWithParams(
79 password,
80 encrypted_private_key_info,
81 subject_public_key_info,
82 PR_FALSE /* not permanent */,
83 PR_FALSE /* not sensitive */);
84 }
85
86 // static
87 ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo(
88 const std::string& password,
89 const std::vector<uint8>& encrypted_private_key_info,
90 const std::vector<uint8>& subject_public_key_info) {
91 #if defined(USE_NSS)
92 return CreateFromEncryptedPrivateKeyInfoWithParams(
93 password,
94 encrypted_private_key_info,
95 subject_public_key_info,
96 PR_TRUE /* permanent */,
97 PR_TRUE /* sensitive */);
98 #else
99 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't
100 // create permanent keys.
101 NOTIMPLEMENTED();
102 return NULL;
103 #endif
104 }
105
106 bool ECPrivateKey::ExportEncryptedPrivateKey(
107 const std::string& password,
108 std::vector<uint8>* encrypted_private_key_info,
109 std::vector<uint8>* subject_public_key_info) {
110 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
111 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
112 // support EC keys.
113 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
114 SECItem password_secitem = {
wtc 2011/11/04 22:41:26 Nit: shorten the variable name suffix to _item. (
mattm 2011/11/08 02:12:27 Done.
115 siBuffer,
116 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
117 password.size()
118 };
119
120 SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo(
Ryan Sleevi 2011/11/04 03:21:25 nit? typedef scoped_ptr_malloc<SECKEYEncryptedPriv
wtc 2011/11/04 21:52:49 Unless this function becomes longer, using this sc
121 NULL, // Slot, optional.
122 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
123 &password_secitem,
124 key_,
125 1, // iterations.
Ryan Sleevi 2011/11/04 03:21:25 Could you add a comment here as to why iterations
mattm 2011/11/08 02:12:27 Since this has a password arg now I guess it also
126 NULL); // wincx.
127
128 if (!encrypted) {
129 NOTREACHED() << "PK11_ExportEncryptedPrivKeyInfo error: "
130 << PORT_GetError();
Ryan Sleevi 2011/11/04 03:21:25 Is PORT_GetError correct here, or should it be PR_
wtc 2011/11/04 21:52:49 PORT_GetError and PR_GetError are the same: http:/
131 return false;
132 }
133
134 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
135 SECItem der_key = {siBuffer, NULL, 0};
136 SECItem* rv = SEC_ASN1EncodeItem(
wtc 2011/11/04 22:41:26 Nit: name this variable 'encoded_item'.
mattm 2011/11/08 02:12:27 Done.
137 arena.get(),
138 &der_key,
139 encrypted,
140 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate));
141 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE);
142 if (!rv) {
143 NOTREACHED() << "SEC_ASN1EncodeItem error: " << PORT_GetError();
144 return false;
145 }
146
147 encrypted_private_key_info->assign(der_key.data, der_key.data + der_key.len);
148
149 ExportPublicKey(subject_public_key_info);
Ryan Sleevi 2011/11/04 03:21:25 This method can fail. Perhaps return ExportPublic
150
151 return true;
152 }
153
154 bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
155 ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
156 if (!der_pubkey.get()) {
157 NOTREACHED();
Ryan Sleevi 2011/11/04 03:21:25 Does this need to be NOTREACHED? Seems a valid (ha
wtc 2011/11/04 21:52:49 This is copied from crypto/rsa_private_key_nss.cc.
mattm 2011/11/08 02:12:27 Done.
158 return false;
159 }
160
161 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
162 return true;
163 }
164
165 bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
166 return ReadAttribute(key_, CKA_VALUE, output);
167 }
168
169 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
170 return ReadAttribute(key_, CKA_EC_PARAMS, output);
171 }
172
173 ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {
174 }
Ryan Sleevi 2011/11/04 03:21:25 nit: Brace on same line
mattm 2011/11/08 02:12:27 Done.
175
176 // static
177 ECPrivateKey* ECPrivateKey::CreateWithParams(bool permanent,
178 bool sensitive) {
179 EnsureNSSInit();
180
181 scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
182
183 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
184 if (!slot.get())
185 return NULL;
186
187 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
188 if (!oid_data) {
189 NOTREACHED();
Ryan Sleevi 2011/11/04 03:21:25 Same here for NOTREACHED()
mattm 2011/11/08 02:12:27 Done.
190 return NULL;
191 }
192
193 SECKEYECParams ec_parameters = {siDEROID, NULL, 0};
194
195 if (!SECITEM_AllocItem(NULL, &ec_parameters, (2 + oid_data->oid.len))) {
Ryan Sleevi 2011/11/04 03:21:25 Comment to explain the magic 2 here and on line 20
wtc 2011/11/04 21:52:49 The magic 2 here is indeed not obvious. The magic
wtc 2011/11/04 22:41:26 Nit: In C++ you should be able to allocate a varia
mattm 2011/11/08 02:12:27 Done.
mattm 2011/11/08 02:12:27 Hm, seems variable length arrays aren't in (standa
196 return NULL;
197 }
198
199 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
200 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
201 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
202 ec_parameters.data[1] = oid_data->oid.len;
203 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
204
205 result->key_ = PK11_GenerateKeyPair(slot.get(),
206 CKM_EC_KEY_PAIR_GEN,
207 &ec_parameters,
208 &result->public_key_,
209 permanent,
210 sensitive,
211 NULL);
212 SECITEM_FreeItem(&ec_parameters, PR_FALSE);
Ryan Sleevi 2011/11/04 03:21:25 Perhaps we should have a StackSECItem to go along
213 if (!result->key_) {
214 NOTREACHED() << "PK11_GenerateKeyPair error: " << PORT_GetError();
215 return NULL;
216 }
217
218 return result.release();
219 }
220
221 // static
222 ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
223 const std::string& password,
224 const std::vector<uint8>& encrypted_private_key_info,
225 const std::vector<uint8>& subject_public_key_info,
226 bool permanent,
227 bool sensitive) {
228 EnsureNSSInit();
229
230 scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
231
232 ScopedPK11Slot slot(GetPrivateNSSKeySlot());
233 if (!slot.get())
234 return NULL;
235
236 SECItem subject_public_key_info_secitem = {
wtc 2011/11/04 22:41:26 Nit: use the _item suffix in the variable name. Yo
mattm 2011/11/08 02:12:27 Done.
237 siBuffer,
238 const_cast<unsigned char*>(&subject_public_key_info[0]),
239 subject_public_key_info.size()
240 };
241 CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo(
242 &subject_public_key_info_secitem);
243 if (!decoded_spki) {
244 NOTREACHED() << "SECKEY_DecodeDERSubjectPublicKeyInfo error: "
245 << PORT_GetError();
246 return NULL;
247 }
248
249 result->public_key_ = SECKEY_ExtractPublicKey(decoded_spki);
250
251 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki);
252
253 if (!result->public_key_) {
254 NOTREACHED() << "SECKEY_ExtractPublicKey error: " << PORT_GetError();
255 return NULL;
256 }
257
258 SECItem encrypted_private_key_info_secitem = {
259 siBuffer,
260 const_cast<unsigned char*>(&encrypted_private_key_info[0]),
261 encrypted_private_key_info.size()
262 };
263 SECKEYEncryptedPrivateKeyInfo epki;
264 memset(&epki, 0, sizeof(epki));
265
266 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
267
268 SECStatus rv = SEC_ASN1DecodeItem(
269 arena.get(),
270 &epki,
271 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
272 &encrypted_private_key_info_secitem);
273 if (rv != SECSuccess) {
274 NOTREACHED() << "SEC_ASN1DecodeItem error: " << PORT_GetError();
275 return NULL;
276 }
277
278 SECItem password_secitem = {
wtc 2011/11/04 22:41:26 Nit: password_secitem => password_item
mattm 2011/11/08 02:12:27 Done.
279 siBuffer,
280 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
281 password.size()
282 };
283
284 rv = ImportEncryptedECPrivateKeyInfoAndReturnKey(
285 slot.get(),
286 &epki,
287 &password_secitem,
288 NULL, // nickname
289 &result->public_key_->u.ec.publicValue,
290 permanent,
291 sensitive,
292 &result->key_,
293 NULL); // wincx
294 if (rv != SECSuccess) {
295 DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey error: "
296 << PORT_GetError();
297 return NULL;
298 }
299
300 return result.release();
301 }
302
303 } // namespace crypto
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698