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());
97 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
99 SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
101 DLOG(ERROR
) << "SECOID_FindOIDByTag: " << PORT_GetError();
105 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
106 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
107 // In addition to the oid data, the encoding requires one byte for the ASN.1
108 // tag and one byte for the length (assuming the length is <= 127).
109 CHECK_LE(oid_data
->oid
.len
, 127U);
110 std::vector
<unsigned char> parameters_buf(2 + oid_data
->oid
.len
);
111 SECKEYECParams ec_parameters
= {
112 siDEROID
, ¶meters_buf
[0],
113 static_cast<unsigned>(parameters_buf
.size())
116 ec_parameters
.data
[0] = SEC_ASN1_OBJECT_ID
;
117 ec_parameters
.data
[1] = static_cast<unsigned char>(oid_data
->oid
.len
);
118 memcpy(ec_parameters
.data
+ 2, oid_data
->oid
.data
, oid_data
->oid
.len
);
120 result
->key_
= PK11_GenerateKeyPair(slot
.get(),
123 &result
->public_key_
,
124 PR_FALSE
/* not permanent */,
125 PR_FALSE
/* not sensitive */,
128 DLOG(ERROR
) << "PK11_GenerateKeyPair: " << PORT_GetError();
131 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(result
->public_key_
));
133 return result
.release();
137 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
138 const std::string
& password
,
139 const std::vector
<uint8
>& encrypted_private_key_info
,
140 const std::vector
<uint8
>& subject_public_key_info
) {
143 ScopedPK11Slot
slot(GetTempKeySlot());
147 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
149 SECItem encoded_spki
= {
151 const_cast<unsigned char*>(&subject_public_key_info
[0]),
152 static_cast<unsigned>(subject_public_key_info
.size())
154 CERTSubjectPublicKeyInfo
* decoded_spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(
157 DLOG(ERROR
) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
161 bool success
= ImportFromEncryptedPrivateKeyInfo(
164 &encrypted_private_key_info
[0],
165 encrypted_private_key_info
.size(),
167 false /* not permanent */,
168 false /* not sensitive */,
170 &result
->public_key_
);
172 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki
);
175 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(result
->public_key_
));
176 return result
.release();
183 bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
185 const std::string
& password
,
186 const uint8
* encrypted_private_key_info
,
187 size_t encrypted_private_key_info_len
,
188 CERTSubjectPublicKeyInfo
* decoded_spki
,
191 SECKEYPrivateKey
** key
,
192 SECKEYPublicKey
** public_key
) {
196 *public_key
= SECKEY_ExtractPublicKey(decoded_spki
);
199 DLOG(ERROR
) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
203 if (SECKEY_GetPublicKeyType(*public_key
) != ecKey
) {
204 DLOG(ERROR
) << "The public key is not an EC key";
205 SECKEY_DestroyPublicKey(*public_key
);
210 SECItem encoded_epki
= {
212 const_cast<unsigned char*>(encrypted_private_key_info
),
213 static_cast<unsigned>(encrypted_private_key_info_len
)
215 SECKEYEncryptedPrivateKeyInfo epki
;
216 memset(&epki
, 0, sizeof(epki
));
218 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
220 SECStatus rv
= SEC_QuickDERDecodeItem(
223 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
),
225 if (rv
!= SECSuccess
) {
226 DLOG(ERROR
) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
227 SECKEY_DestroyPublicKey(*public_key
);
232 SECItem password_item
= {
234 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
235 static_cast<unsigned>(password
.size())
238 rv
= ImportEncryptedECPrivateKeyInfoAndReturnKey(
243 &(*public_key
)->u
.ec
.publicValue
,
248 if (rv
!= SECSuccess
) {
249 DLOG(ERROR
) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
251 SECKEY_DestroyPublicKey(*public_key
);
259 ECPrivateKey
* ECPrivateKey::Copy() const {
260 scoped_ptr
<ECPrivateKey
> copy(new ECPrivateKey
);
262 copy
->key_
= SECKEY_CopyPrivateKey(key_
);
267 copy
->public_key_
= SECKEY_CopyPublicKey(public_key_
);
268 if (!copy
->public_key_
)
271 return copy
.release();
274 bool ECPrivateKey::ExportEncryptedPrivateKey(
275 const std::string
& password
,
277 std::vector
<uint8
>* output
) {
278 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
279 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
281 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
282 SECItem password_item
= {
284 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
285 static_cast<unsigned>(password
.size())
288 SECKEYEncryptedPrivateKeyInfo
* encrypted
= PK11_ExportEncryptedPrivKeyInfo(
289 NULL
, // Slot, optional.
290 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
,
297 DLOG(ERROR
) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
301 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
302 SECItem der_key
= {siBuffer
, NULL
, 0};
303 SECItem
* encoded_item
= SEC_ASN1EncodeItem(
307 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
));
308 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted
, PR_TRUE
);
310 DLOG(ERROR
) << "SEC_ASN1EncodeItem: " << PORT_GetError();
314 output
->assign(der_key
.data
, der_key
.data
+ der_key
.len
);
319 bool ECPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) {
320 ScopedSECItem
der_pubkey(
321 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_
));
322 if (!der_pubkey
.get()) {
326 output
->assign(der_pubkey
->data
, der_pubkey
->data
+ der_pubkey
->len
);
330 bool ECPrivateKey::ExportRawPublicKey(std::string
* output
) {
331 // public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for
332 // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
333 // elements as 32-byte, big-endian numbers.
334 static const unsigned int kExpectedKeyLength
= 65;
336 CHECK_EQ(ecKey
, SECKEY_GetPublicKeyType(public_key_
));
337 const unsigned char* const data
= public_key_
->u
.ec
.publicValue
.data
;
338 const unsigned int len
= public_key_
->u
.ec
.publicValue
.len
;
339 if (len
!= kExpectedKeyLength
|| data
[0] != 0x04)
342 output
->assign(reinterpret_cast<const char*>(data
+ 1),
343 kExpectedKeyLength
- 1);
347 bool ECPrivateKey::ExportValue(std::vector
<uint8
>* output
) {
348 return ReadAttribute(key_
, CKA_VALUE
, output
);
351 bool ECPrivateKey::ExportECParams(std::vector
<uint8
>* output
) {
352 return ReadAttribute(key_
, CKA_EC_PARAMS
, output
);
355 ECPrivateKey::ECPrivateKey() : key_(NULL
), public_key_(NULL
) {}
357 } // namespace crypto