blob: 8ca8f25ecafedfa3630b7c851ef5ce707c8de2b6 [file] [log] [blame]
[email protected]3fcbd4b2012-06-05 01:54:461// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]eaa60482011-11-09 05:08:512// 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
7extern "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>
avidd373b8b2015-12-21 21:34:4317#include <stddef.h>
18#include <stdint.h>
[email protected]eaa60482011-11-09 05:08:5119
thakisd1a18472016-04-08 22:30:4120#include <memory>
21
[email protected]eaa60482011-11-09 05:08:5122#include "base/logging.h"
[email protected]eaa60482011-11-09 05:08:5123#include "crypto/nss_util.h"
24#include "crypto/nss_util_internal.h"
25#include "crypto/scoped_nss_types.h"
26#include "crypto/third_party/nss/chromium-nss.h"
27
28namespace {
29
davidben7dad2a32016-03-01 23:47:4730static bool AppendAttribute(SECKEYPrivateKey* key,
31 CK_ATTRIBUTE_TYPE type,
32 std::vector<uint8_t>* output) {
[email protected]eaa60482011-11-09 05:08:5133 SECItem item;
34 SECStatus rv;
35 rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
36 if (rv != SECSuccess) {
37 DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError();
38 return false;
39 }
40
davidben7dad2a32016-03-01 23:47:4741 output->insert(output->end(), item.data, item.data + item.len);
[email protected]eaa60482011-11-09 05:08:5142 SECITEM_FreeItem(&item, PR_FALSE);
43 return true;
44}
45
46} // namespace
47
48namespace crypto {
49
50ECPrivateKey::~ECPrivateKey() {
51 if (key_)
52 SECKEY_DestroyPrivateKey(key_);
53 if (public_key_)
54 SECKEY_DestroyPublicKey(public_key_);
55}
56
57// static
58ECPrivateKey* ECPrivateKey::Create() {
[email protected]6e7da44d2013-11-13 03:29:2259 EnsureNSSInit();
60
davidben24bb5a42015-10-15 22:13:2261 ScopedPK11Slot slot(PK11_GetInternalSlot());
davidbenf2331cd2015-02-25 21:17:2962 if (!slot)
63 return nullptr;
[email protected]eaa60482011-11-09 05:08:5164
thakisd1a18472016-04-08 22:30:4165 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey);
davidbenf2331cd2015-02-25 21:17:2966
67 SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
68 if (!oid_data) {
69 DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
70 return nullptr;
71 }
72
73 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
74 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
75 // In addition to the oid data, the encoding requires one byte for the ASN.1
76 // tag and one byte for the length (assuming the length is <= 127).
77 CHECK_LE(oid_data->oid.len, 127U);
78 std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len);
79 SECKEYECParams ec_parameters = {
80 siDEROID, &parameters_buf[0],
81 static_cast<unsigned>(parameters_buf.size())
82 };
83
84 ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
85 ec_parameters.data[1] = static_cast<unsigned char>(oid_data->oid.len);
86 memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
87
88 result->key_ = PK11_GenerateKeyPair(slot.get(),
89 CKM_EC_KEY_PAIR_GEN,
90 &ec_parameters,
91 &result->public_key_,
92 PR_FALSE /* not permanent */,
93 PR_FALSE /* not sensitive */,
94 NULL);
95 if (!result->key_) {
96 DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError();
97 return nullptr;
98 }
99 CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
100
101 return result.release();
[email protected]eaa60482011-11-09 05:08:51102}
103
104// static
105ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
106 const std::string& password,
avidd373b8b2015-12-21 21:34:43107 const std::vector<uint8_t>& encrypted_private_key_info,
108 const std::vector<uint8_t>& subject_public_key_info) {
[email protected]6e7da44d2013-11-13 03:29:22109 EnsureNSSInit();
110
davidben24bb5a42015-10-15 22:13:22111 ScopedPK11Slot slot(PK11_GetInternalSlot());
davidbenf2331cd2015-02-25 21:17:29112 if (!slot)
113 return nullptr;
114
thakisd1a18472016-04-08 22:30:41115 std::unique_ptr<ECPrivateKey> result(new ECPrivateKey);
davidbenf2331cd2015-02-25 21:17:29116
117 SECItem encoded_spki = {
118 siBuffer,
119 const_cast<unsigned char*>(&subject_public_key_info[0]),
120 static_cast<unsigned>(subject_public_key_info.size())
121 };
122 CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo(
123 &encoded_spki);
124 if (!decoded_spki) {
125 DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
126 return nullptr;
127 }
128
129 bool success = ImportFromEncryptedPrivateKeyInfo(
[email protected]6e7da44d2013-11-13 03:29:22130 slot.get(),
[email protected]eaa60482011-11-09 05:08:51131 password,
davidbenf2331cd2015-02-25 21:17:29132 &encrypted_private_key_info[0],
133 encrypted_private_key_info.size(),
134 decoded_spki,
[email protected]6e7da44d2013-11-13 03:29:22135 false /* not permanent */,
davidbenf2331cd2015-02-25 21:17:29136 false /* not sensitive */,
137 &result->key_,
138 &result->public_key_);
[email protected]eaa60482011-11-09 05:08:51139
davidbenf2331cd2015-02-25 21:17:29140 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki);
141
142 if (success) {
143 CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
144 return result.release();
145 }
146
147 return nullptr;
[email protected]eaa60482011-11-09 05:08:51148}
149
[email protected]550cee92011-12-06 04:21:09150// static
151bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
[email protected]6e7da44d2013-11-13 03:29:22152 PK11SlotInfo* slot,
[email protected]550cee92011-12-06 04:21:09153 const std::string& password,
avidd373b8b2015-12-21 21:34:43154 const uint8_t* encrypted_private_key_info,
[email protected]550cee92011-12-06 04:21:09155 size_t encrypted_private_key_info_len,
156 CERTSubjectPublicKeyInfo* decoded_spki,
157 bool permanent,
158 bool sensitive,
159 SECKEYPrivateKey** key,
160 SECKEYPublicKey** public_key) {
[email protected]6e7da44d2013-11-13 03:29:22161 if (!slot)
[email protected]550cee92011-12-06 04:21:09162 return false;
163
164 *public_key = SECKEY_ExtractPublicKey(decoded_spki);
165
166 if (!*public_key) {
167 DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
168 return false;
169 }
170
[email protected]ac30ed0e2014-06-24 04:12:34171 if (SECKEY_GetPublicKeyType(*public_key) != ecKey) {
172 DLOG(ERROR) << "The public key is not an EC key";
173 SECKEY_DestroyPublicKey(*public_key);
174 *public_key = NULL;
175 return false;
176 }
177
[email protected]550cee92011-12-06 04:21:09178 SECItem encoded_epki = {
179 siBuffer,
180 const_cast<unsigned char*>(encrypted_private_key_info),
[email protected]3fcbd4b2012-06-05 01:54:46181 static_cast<unsigned>(encrypted_private_key_info_len)
[email protected]550cee92011-12-06 04:21:09182 };
183 SECKEYEncryptedPrivateKeyInfo epki;
184 memset(&epki, 0, sizeof(epki));
185
186 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
187
188 SECStatus rv = SEC_QuickDERDecodeItem(
189 arena.get(),
190 &epki,
191 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
192 &encoded_epki);
193 if (rv != SECSuccess) {
194 DLOG(ERROR) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
195 SECKEY_DestroyPublicKey(*public_key);
196 *public_key = NULL;
197 return false;
198 }
199
200 SECItem password_item = {
201 siBuffer,
202 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
[email protected]3fcbd4b2012-06-05 01:54:46203 static_cast<unsigned>(password.size())
[email protected]550cee92011-12-06 04:21:09204 };
205
206 rv = ImportEncryptedECPrivateKeyInfoAndReturnKey(
[email protected]6e7da44d2013-11-13 03:29:22207 slot,
[email protected]550cee92011-12-06 04:21:09208 &epki,
209 &password_item,
210 NULL, // nickname
211 &(*public_key)->u.ec.publicValue,
212 permanent,
213 sensitive,
214 key,
215 NULL); // wincx
216 if (rv != SECSuccess) {
217 DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
218 << PORT_GetError();
219 SECKEY_DestroyPublicKey(*public_key);
220 *public_key = NULL;
221 return false;
222 }
223
224 return true;
225}
226
[email protected]ac30ed0e2014-06-24 04:12:34227ECPrivateKey* ECPrivateKey::Copy() const {
thakisd1a18472016-04-08 22:30:41228 std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey);
[email protected]ac30ed0e2014-06-24 04:12:34229 if (key_) {
230 copy->key_ = SECKEY_CopyPrivateKey(key_);
231 if (!copy->key_)
232 return NULL;
233 }
234 if (public_key_) {
235 copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
236 if (!copy->public_key_)
237 return NULL;
238 }
239 return copy.release();
240}
241
avidd373b8b2015-12-21 21:34:43242bool ECPrivateKey::ExportEncryptedPrivateKey(const std::string& password,
243 int iterations,
244 std::vector<uint8_t>* output) {
[email protected]eaa60482011-11-09 05:08:51245 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
246 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
247 // support EC keys.
248 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
249 SECItem password_item = {
250 siBuffer,
251 reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
[email protected]3fcbd4b2012-06-05 01:54:46252 static_cast<unsigned>(password.size())
[email protected]eaa60482011-11-09 05:08:51253 };
254
255 SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo(
[email protected]c9c251d2014-07-22 00:09:25256 NULL, // Slot, optional.
[email protected]eaa60482011-11-09 05:08:51257 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
258 &password_item,
259 key_,
260 iterations,
[email protected]c9c251d2014-07-22 00:09:25261 NULL); // wincx.
[email protected]eaa60482011-11-09 05:08:51262
263 if (!encrypted) {
264 DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
265 return false;
266 }
267
268 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
269 SECItem der_key = {siBuffer, NULL, 0};
270 SECItem* encoded_item = SEC_ASN1EncodeItem(
271 arena.get(),
272 &der_key,
273 encrypted,
274 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate));
275 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE);
276 if (!encoded_item) {
277 DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError();
278 return false;
279 }
280
281 output->assign(der_key.data, der_key.data + der_key.len);
282
283 return true;
284}
285
avidd373b8b2015-12-21 21:34:43286bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) {
[email protected]eaa60482011-11-09 05:08:51287 ScopedSECItem der_pubkey(
288 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
289 if (!der_pubkey.get()) {
290 return false;
291 }
292
293 output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
294 return true;
295}
296
[email protected]ac30ed0e2014-06-24 04:12:34297bool ECPrivateKey::ExportRawPublicKey(std::string* output) {
298 // public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for
299 // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
300 // elements as 32-byte, big-endian numbers.
301 static const unsigned int kExpectedKeyLength = 65;
302
303 CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(public_key_));
304 const unsigned char* const data = public_key_->u.ec.publicValue.data;
305 const unsigned int len = public_key_->u.ec.publicValue.len;
306 if (len != kExpectedKeyLength || data[0] != 0x04)
307 return false;
308
309 output->assign(reinterpret_cast<const char*>(data + 1),
310 kExpectedKeyLength - 1);
311 return true;
312}
313
davidben7dad2a32016-03-01 23:47:47314bool ECPrivateKey::ExportValueForTesting(std::vector<uint8_t>* output) {
315 // This serialization format is purely for testing equality, so just
316 // concatenate the raw private key (always 32 bytes for P-256) with the
317 // parameters.
318 output->clear();
319 return AppendAttribute(key_, CKA_VALUE, output) &&
320 output->size() == 32 &&
321 AppendAttribute(key_, CKA_EC_PARAMS, output);
[email protected]eaa60482011-11-09 05:08:51322}
323
324ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {}
325
[email protected]eaa60482011-11-09 05:08:51326} // namespace crypto