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.
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/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "crypto/nss_util.h"
21 #include "crypto/nss_util_internal.h"
22 #include "crypto/scoped_nss_types.h"
23 #include "crypto/third_party/nss/chromium-nss.h"
27 // Copied from rsa_private_key_nss.cc.
28 static bool ReadAttribute(SECKEYPrivateKey
* key
,
29 CK_ATTRIBUTE_TYPE type
,
30 std::vector
<uint8
>* output
) {
33 rv
= PK11_ReadRawAttribute(PK11_TypePrivKey
, key
, type
, &item
);
34 if (rv
!= SECSuccess
) {
35 DLOG(ERROR
) << "PK11_ReadRawAttribute: " << PORT_GetError();
39 output
->assign(item
.data
, item
.data
+ item
.len
);
40 SECITEM_FreeItem(&item
, PR_FALSE
);
48 ECPrivateKey::~ECPrivateKey() {
50 SECKEY_DestroyPrivateKey(key_
);
52 SECKEY_DestroyPublicKey(public_key_
);
56 ECPrivateKey
* ECPrivateKey::Create() {
57 return CreateWithParams(PR_FALSE
/* not permanent */,
58 PR_FALSE
/* not sensitive */);
62 ECPrivateKey
* ECPrivateKey::CreateSensitive() {
64 return CreateWithParams(PR_TRUE
/* permanent */,
65 PR_TRUE
/* sensitive */);
67 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't
68 // create permanent keys.
75 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
76 const std::string
& password
,
77 const std::vector
<uint8
>& encrypted_private_key_info
,
78 const std::vector
<uint8
>& subject_public_key_info
) {
79 return CreateFromEncryptedPrivateKeyInfoWithParams(
81 encrypted_private_key_info
,
82 subject_public_key_info
,
83 PR_FALSE
/* not permanent */,
84 PR_FALSE
/* not sensitive */);
88 ECPrivateKey
* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo(
89 const std::string
& password
,
90 const std::vector
<uint8
>& encrypted_private_key_info
,
91 const std::vector
<uint8
>& subject_public_key_info
) {
93 return CreateFromEncryptedPrivateKeyInfoWithParams(
95 encrypted_private_key_info
,
96 subject_public_key_info
,
97 PR_TRUE
/* permanent */,
98 PR_TRUE
/* sensitive */);
100 // If USE_NSS is not defined, we initialize NSS with no databases, so we can't
101 // create permanent keys.
108 bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
109 const std::string
& password
,
110 const uint8
* encrypted_private_key_info
,
111 size_t encrypted_private_key_info_len
,
112 CERTSubjectPublicKeyInfo
* decoded_spki
,
115 SECKEYPrivateKey
** key
,
116 SECKEYPublicKey
** public_key
) {
117 ScopedPK11Slot
slot(GetPrivateNSSKeySlot());
121 *public_key
= SECKEY_ExtractPublicKey(decoded_spki
);
124 DLOG(ERROR
) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
128 SECItem encoded_epki
= {
130 const_cast<unsigned char*>(encrypted_private_key_info
),
131 encrypted_private_key_info_len
133 SECKEYEncryptedPrivateKeyInfo epki
;
134 memset(&epki
, 0, sizeof(epki
));
136 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
138 SECStatus rv
= SEC_QuickDERDecodeItem(
141 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
),
143 if (rv
!= SECSuccess
) {
144 DLOG(ERROR
) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
145 SECKEY_DestroyPublicKey(*public_key
);
150 SECItem password_item
= {
152 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
156 rv
= ImportEncryptedECPrivateKeyInfoAndReturnKey(
161 &(*public_key
)->u
.ec
.publicValue
,
166 if (rv
!= SECSuccess
) {
167 DLOG(ERROR
) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
169 SECKEY_DestroyPublicKey(*public_key
);
177 bool ECPrivateKey::ExportEncryptedPrivateKey(
178 const std::string
& password
,
180 std::vector
<uint8
>* output
) {
181 // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
182 // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
184 // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
185 SECItem password_item
= {
187 reinterpret_cast<unsigned char*>(const_cast<char*>(password
.data())),
191 SECKEYEncryptedPrivateKeyInfo
* encrypted
= PK11_ExportEncryptedPrivKeyInfo(
192 NULL
, // Slot, optional.
193 SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
,
200 DLOG(ERROR
) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
204 ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
205 SECItem der_key
= {siBuffer
, NULL
, 0};
206 SECItem
* encoded_item
= SEC_ASN1EncodeItem(
210 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate
));
211 SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted
, PR_TRUE
);
213 DLOG(ERROR
) << "SEC_ASN1EncodeItem: " << PORT_GetError();
217 output
->assign(der_key
.data
, der_key
.data
+ der_key
.len
);
222 bool ECPrivateKey::ExportPublicKey(std::vector
<uint8
>* output
) {
223 ScopedSECItem
der_pubkey(
224 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_
));
225 if (!der_pubkey
.get()) {
229 output
->assign(der_pubkey
->data
, der_pubkey
->data
+ der_pubkey
->len
);
233 bool ECPrivateKey::ExportValue(std::vector
<uint8
>* output
) {
234 return ReadAttribute(key_
, CKA_VALUE
, output
);
237 bool ECPrivateKey::ExportECParams(std::vector
<uint8
>* output
) {
238 return ReadAttribute(key_
, CKA_EC_PARAMS
, output
);
241 ECPrivateKey::ECPrivateKey() : key_(NULL
), public_key_(NULL
) {}
244 ECPrivateKey
* ECPrivateKey::CreateWithParams(bool permanent
,
248 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
250 ScopedPK11Slot
slot(GetPrivateNSSKeySlot());
254 SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
256 DLOG(ERROR
) << "SECOID_FindOIDByTag: " << PORT_GetError();
260 // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
261 // value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
262 // In addition to the oid data, the encoding requires one byte for the ASN.1
263 // tag and one byte for the length (assuming the length is <= 127).
264 DCHECK_LE(oid_data
->oid
.len
, 127U);
265 std::vector
<unsigned char> parameters_buf(2 + oid_data
->oid
.len
);
266 SECKEYECParams ec_parameters
= {
267 siDEROID
, ¶meters_buf
[0], parameters_buf
.size()
270 ec_parameters
.data
[0] = SEC_ASN1_OBJECT_ID
;
271 ec_parameters
.data
[1] = oid_data
->oid
.len
;
272 memcpy(ec_parameters
.data
+ 2, oid_data
->oid
.data
, oid_data
->oid
.len
);
274 result
->key_
= PK11_GenerateKeyPair(slot
.get(),
277 &result
->public_key_
,
282 DLOG(ERROR
) << "PK11_GenerateKeyPair: " << PORT_GetError();
286 return result
.release();
290 ECPrivateKey
* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
291 const std::string
& password
,
292 const std::vector
<uint8
>& encrypted_private_key_info
,
293 const std::vector
<uint8
>& subject_public_key_info
,
298 scoped_ptr
<ECPrivateKey
> result(new ECPrivateKey
);
300 SECItem encoded_spki
= {
302 const_cast<unsigned char*>(&subject_public_key_info
[0]),
303 subject_public_key_info
.size()
305 CERTSubjectPublicKeyInfo
* decoded_spki
= SECKEY_DecodeDERSubjectPublicKeyInfo(
308 DLOG(ERROR
) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
312 bool success
= ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
314 &encrypted_private_key_info
[0],
315 encrypted_private_key_info
.size(),
320 &result
->public_key_
);
322 SECKEY_DestroySubjectPublicKeyInfo(decoded_spki
);
325 return result
.release();
330 } // namespace crypto