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 SECItem encoded_epki
= {
164 const_cast<unsigned char*>(encrypted_private_key_info
),
165 static_cast<unsigned>(encrypted_private_key_info_len
)
167 SECKEYEncryptedPrivateKeyInfo epki
;
168 memset(&epki
, 0, sizeof(epki
));
170 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
172 SECStatus rv
= SEC_QuickDERDecodeItem(
175 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
),
177 if (rv
!= SECSuccess
) {
178 DLOG(ERROR
) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
179 SECKEY_DestroyPublicKey(*public_key
);
184 SECItem password_item
= {
186 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
187 static_cast<unsigned>(password
.size())
190 rv
= ImportEncryptedECPrivateKeyInfoAndReturnKey(
195 &(*public_key
)->u
.ec
.publicValue
,
200 if (rv
!= SECSuccess
) {
201 DLOG(ERROR
) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
203 SECKEY_DestroyPublicKey(*public_key
);
211 bool ECPrivateKey::ExportEncryptedPrivateKey(
212 const std::string
& password
,
214 std::vector
<uint8
>* output
) {
215 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
216 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
218 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
219 SECItem password_item
= {
221 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
222 static_cast<unsigned>(password
.size())
225 SECKEYEncryptedPrivateKeyInfo
* encrypted
= PK11_ExportEncryptedPrivKeyInfo(
226 NULL
, // Slot, optional.
227 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
,
234 DLOG(ERROR
) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
238 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
239 SECItem der_key
= {siBuffer
, NULL
, 0};
240 SECItem
* encoded_item
= SEC_ASN1EncodeItem(
244 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
));
245 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted
, PR_TRUE
);
247 DLOG(ERROR
) << "SEC_ASN1EncodeItem: " << PORT_GetError();
251 output
->assign(der_key
.data
, der_key
.data
+ der_key
.len
);
256 bool ECPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) {
257 ScopedSECItem
der_pubkey(
258 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_
));
259 if (!der_pubkey
.get()) {
263 output
->assign(der_pubkey
->data
, der_pubkey
->data
+ der_pubkey
->len
);
267 bool ECPrivateKey::ExportValue(std::vector
<uint8
>* output
) {
268 return ReadAttribute(key_
, CKA_VALUE
, output
);
271 bool ECPrivateKey::ExportECParams(std::vector
<uint8
>* output
) {
272 return ReadAttribute(key_
, CKA_EC_PARAMS
, output
);
275 ECPrivateKey::ECPrivateKey() : key_(NULL
), public_key_(NULL
) {}
278 ECPrivateKey
* ECPrivateKey::CreateWithParams(PK11SlotInfo
* slot
,
284 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
286 SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
288 DLOG(ERROR
) << "SECOID_FindOIDByTag: " << PORT_GetError();
292 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
293 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
294 // In addition to the oid data, the encoding requires one byte for the ASN.1
295 // tag and one byte for the length (assuming the length is <= 127).
296 DCHECK_LE(oid_data
->oid
.len
, 127U);
297 std::vector
<unsigned char> parameters_buf(2 + oid_data
->oid
.len
);
298 SECKEYECParams ec_parameters
= {
299 siDEROID
, ¶meters_buf
[0],
300 static_cast<unsigned>(parameters_buf
.size())
303 ec_parameters
.data
[0] = SEC_ASN1_OBJECT_ID
;
304 ec_parameters
.data
[1] = oid_data
->oid
.len
;
305 memcpy(ec_parameters
.data
+ 2, oid_data
->oid
.data
, oid_data
->oid
.len
);
307 result
->key_
= PK11_GenerateKeyPair(slot
,
310 &result
->public_key_
,
315 DLOG(ERROR
) << "PK11_GenerateKeyPair: " << PORT_GetError();
319 return result
.release();
323 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
325 const std::string
& password
,
326 const std::vector
<uint8
>& encrypted_private_key_info
,
327 const std::vector
<uint8
>& subject_public_key_info
,
330 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
332 SECItem encoded_spki
= {
334 const_cast<unsigned char*>(&subject_public_key_info
[0]),
335 static_cast<unsigned>(subject_public_key_info
.size())
337 CERTSubjectPublicKeyInfo
* decoded_spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(
340 DLOG(ERROR
) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
344 bool success
= ImportFromEncryptedPrivateKeyInfo(
347 &encrypted_private_key_info
[0],
348 encrypted_private_key_info
.size(),
353 &result
->public_key_
);
355 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki
);
358 return result
.release();
363 } // namespace crypto