1 // Copyright (c) 2012 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/ec_private_key.h"
8 // Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "crypto/nss_util.h"
22 #include "crypto/nss_util_internal.h"
23 #include "crypto/scoped_nss_types.h"
24 #include "crypto/third_party/nss/chromium-nss.h"
28 PK11SlotInfo
* GetTempKeySlot() {
29 return PK11_GetInternalSlot();
32 class EllipticCurveSupportChecker
{
34 EllipticCurveSupportChecker() {
35 // NOTE: we can do this check here only because we use the NSS internal
36 // slot. If we support other slots in the future, checking whether they
37 // support ECDSA may block NSS, and the value may also change as devices are
38 // inserted/removed, so we would need to re-check on every use.
39 crypto::EnsureNSSInit();
40 crypto::ScopedPK11Slot
slot(GetTempKeySlot());
41 supported_
= PK11_DoesMechanism(slot
.get(), CKM_EC_KEY_PAIR_GEN
) &&
42 PK11_DoesMechanism(slot
.get(), CKM_ECDSA
);
53 static base::LazyInstance
<EllipticCurveSupportChecker
>::Leaky
54 g_elliptic_curve_supported
= LAZY_INSTANCE_INITIALIZER
;
56 // Copied from rsa_private_key_nss.cc.
57 static bool ReadAttribute(SECKEYPrivateKey
* key
,
58 CK_ATTRIBUTE_TYPE type
,
59 std::vector
<uint8
>* output
) {
62 rv
= PK11_ReadRawAttribute(PK11_TypePrivKey
, key
, type
, &item
);
63 if (rv
!= SECSuccess
) {
64 DLOG(ERROR
) << "PK11_ReadRawAttribute: " << PORT_GetError();
68 output
->assign(item
.data
, item
.data
+ item
.len
);
69 SECITEM_FreeItem(&item
, PR_FALSE
);
77 ECPrivateKey::~ECPrivateKey() {
79 SECKEY_DestroyPrivateKey(key_
);
81 SECKEY_DestroyPublicKey(public_key_
);
85 bool ECPrivateKey::IsSupported() {
86 return g_elliptic_curve_supported
.Get().Supported();
90 ECPrivateKey
* ECPrivateKey::Create() {
93 ScopedPK11Slot
slot(GetTempKeySlot());
94 return CreateWithParams(slot
.get(),
95 false /* not permanent */,
96 false /* not sensitive */);
101 ECPrivateKey
* ECPrivateKey::CreateSensitive(PK11SlotInfo
* slot
) {
102 return CreateWithParams(
103 slot
, true /* permanent */, true /* sensitive */);
108 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
109 const std::string
& password
,
110 const std::vector
<uint8
>& encrypted_private_key_info
,
111 const std::vector
<uint8
>& subject_public_key_info
) {
114 ScopedPK11Slot
slot(GetTempKeySlot());
115 return CreateFromEncryptedPrivateKeyInfoWithParams(
118 encrypted_private_key_info
,
119 subject_public_key_info
,
120 false /* not permanent */,
121 false /* not sensitive */);
126 ECPrivateKey
* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo(
128 const std::string
& password
,
129 const std::vector
<uint8
>& encrypted_private_key_info
,
130 const std::vector
<uint8
>& subject_public_key_info
) {
131 return CreateFromEncryptedPrivateKeyInfoWithParams(
134 encrypted_private_key_info
,
135 subject_public_key_info
,
136 true /* permanent */,
137 true /* sensitive */);
142 bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
144 const std::string
& password
,
145 const uint8
* encrypted_private_key_info
,
146 size_t encrypted_private_key_info_len
,
147 CERTSubjectPublicKeyInfo
* decoded_spki
,
150 SECKEYPrivateKey
** key
,
151 SECKEYPublicKey
** public_key
) {
155 *public_key
= SECKEY_ExtractPublicKey(decoded_spki
);
158 DLOG(ERROR
) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
162 if (SECKEY_GetPublicKeyType(*public_key
) != ecKey
) {
163 DLOG(ERROR
) << "The public key is not an EC key";
164 SECKEY_DestroyPublicKey(*public_key
);
169 SECItem encoded_epki
= {
171 const_cast<unsigned char*>(encrypted_private_key_info
),
172 static_cast<unsigned>(encrypted_private_key_info_len
)
174 SECKEYEncryptedPrivateKeyInfo epki
;
175 memset(&epki
, 0, sizeof(epki
));
177 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
179 SECStatus rv
= SEC_QuickDERDecodeItem(
182 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
),
184 if (rv
!= SECSuccess
) {
185 DLOG(ERROR
) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
186 SECKEY_DestroyPublicKey(*public_key
);
191 SECItem password_item
= {
193 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
194 static_cast<unsigned>(password
.size())
197 rv
= ImportEncryptedECPrivateKeyInfoAndReturnKey(
202 &(*public_key
)->u
.ec
.publicValue
,
207 if (rv
!= SECSuccess
) {
208 DLOG(ERROR
) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
210 SECKEY_DestroyPublicKey(*public_key
);
218 ECPrivateKey
* ECPrivateKey::Copy() const {
219 scoped_ptr
<ECPrivateKey
> copy(new ECPrivateKey
);
221 copy
->key_
= SECKEY_CopyPrivateKey(key_
);
226 copy
->public_key_
= SECKEY_CopyPublicKey(public_key_
);
227 if (!copy
->public_key_
)
230 return copy
.release();
233 bool ECPrivateKey::ExportEncryptedPrivateKey(
234 const std::string
& password
,
236 std::vector
<uint8
>* output
) {
237 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
238 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
240 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
241 SECItem password_item
= {
243 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
244 static_cast<unsigned>(password
.size())
247 SECKEYEncryptedPrivateKeyInfo
* encrypted
= PK11_ExportEncryptedPrivKeyInfo(
248 NULL
, // Slot, optional.
249 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
,
256 DLOG(ERROR
) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
260 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
261 SECItem der_key
= {siBuffer
, NULL
, 0};
262 SECItem
* encoded_item
= SEC_ASN1EncodeItem(
266 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
));
267 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted
, PR_TRUE
);
269 DLOG(ERROR
) << "SEC_ASN1EncodeItem: " << PORT_GetError();
273 output
->assign(der_key
.data
, der_key
.data
+ der_key
.len
);
278 bool ECPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) {
279 ScopedSECItem
der_pubkey(
280 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_
));
281 if (!der_pubkey
.get()) {
285 output
->assign(der_pubkey
->data
, der_pubkey
->data
+ der_pubkey
->len
);
289 bool ECPrivateKey::ExportRawPublicKey(std::string
* output
) {
290 // public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for
291 // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
292 // elements as 32-byte, big-endian numbers.
293 static const unsigned int kExpectedKeyLength
= 65;
295 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(public_key_
));
296 const unsigned char* const data
= public_key_
->u
.ec
.publicValue
.data
;
297 const unsigned int len
= public_key_
->u
.ec
.publicValue
.len
;
298 if (len
!= kExpectedKeyLength
|| data
[0] != 0x04)
301 output
->assign(reinterpret_cast<const char*>(data
+ 1),
302 kExpectedKeyLength
- 1);
306 bool ECPrivateKey::ExportValue(std::vector
<uint8
>* output
) {
307 return ReadAttribute(key_
, CKA_VALUE
, output
);
310 bool ECPrivateKey::ExportECParams(std::vector
<uint8
>* output
) {
311 return ReadAttribute(key_
, CKA_EC_PARAMS
, output
);
314 ECPrivateKey::ECPrivateKey() : key_(NULL
), public_key_(NULL
) {}
317 ECPrivateKey
* ECPrivateKey::CreateWithParams(PK11SlotInfo
* slot
,
323 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
325 SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
327 DLOG(ERROR
) << "SECOID_FindOIDByTag: " << PORT_GetError();
331 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
332 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
333 // In addition to the oid data, the encoding requires one byte for the ASN.1
334 // tag and one byte for the length (assuming the length is <= 127).
335 DCHECK_LE(oid_data
->oid
.len
, 127U);
336 std::vector
<unsigned char> parameters_buf(2 + oid_data
->oid
.len
);
337 SECKEYECParams ec_parameters
= {
338 siDEROID
, ¶meters_buf
[0],
339 static_cast<unsigned>(parameters_buf
.size())
342 ec_parameters
.data
[0] = SEC_ASN1_OBJECT_ID
;
343 ec_parameters
.data
[1] = oid_data
->oid
.len
;
344 memcpy(ec_parameters
.data
+ 2, oid_data
->oid
.data
, oid_data
->oid
.len
);
346 result
->key_
= PK11_GenerateKeyPair(slot
,
349 &result
->public_key_
,
354 DLOG(ERROR
) << "PK11_GenerateKeyPair: " << PORT_GetError();
357 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(result
->public_key_
));
359 return result
.release();
363 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
365 const std::string
& password
,
366 const std::vector
<uint8
>& encrypted_private_key_info
,
367 const std::vector
<uint8
>& subject_public_key_info
,
370 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
372 SECItem encoded_spki
= {
374 const_cast<unsigned char*>(&subject_public_key_info
[0]),
375 static_cast<unsigned>(subject_public_key_info
.size())
377 CERTSubjectPublicKeyInfo
* decoded_spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(
380 DLOG(ERROR
) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
384 bool success
= ImportFromEncryptedPrivateKeyInfo(
387 &encrypted_private_key_info
[0],
388 encrypted_private_key_info
.size(),
393 &result
->public_key_
);
395 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki
);
398 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(result
->public_key_
));
399 return result
.release();
405 } // namespace crypto