1 // Copyright (c) 2013 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 "net/quic/crypto/p256_key_exchange.h"
7 #include "base/logging.h"
8 #include "base/sys_byteorder.h"
10 using base::StringPiece
;
18 // Password used by |NewPrivateKey| to encrypt exported EC private keys.
19 // This is not used to provide any security, but to workaround NSS being
20 // unwilling to export unencrypted EC keys. Note that SPDY and ChannelID
21 // use the same approach.
22 const char kExportPassword
[] = "";
24 // Convert StringPiece to vector of uint8.
25 static vector
<uint8
> StringPieceToVector(StringPiece piece
) {
26 return vector
<uint8
>(piece
.data(), piece
.data() + piece
.length());
31 P256KeyExchange::P256KeyExchange(crypto::ECPrivateKey
* key_pair
,
32 const uint8
* public_key
)
33 : key_pair_(key_pair
) {
34 memcpy(public_key_
, public_key
, sizeof(public_key_
));
37 P256KeyExchange::~P256KeyExchange() {
41 P256KeyExchange
* P256KeyExchange::New(StringPiece key
) {
43 DVLOG(1) << "Key pair is too small.";
47 const uint8
* data
= reinterpret_cast<const uint8
*>(key
.data());
48 size_t size
= static_cast<size_t>(data
[0]) |
49 (static_cast<size_t>(data
[1]) << 8);
51 if (key
.size() < size
) {
52 DVLOG(1) << "Key pair does not contain key material.";
56 StringPiece
private_piece(key
.data(), size
);
57 key
.remove_prefix(size
);
59 DVLOG(1) << "Key pair does not contain public key.";
63 StringPiece
public_piece(key
);
65 scoped_ptr
<crypto::ECPrivateKey
> key_pair(
66 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
68 // TODO(thaidn): fix this interface to avoid copying secrets.
69 StringPieceToVector(private_piece
),
70 StringPieceToVector(public_piece
)));
72 if (!key_pair
.get()) {
73 DVLOG(1) << "Can't decrypt private key.";
77 // Perform some sanity checks on the public key.
78 SECKEYPublicKey
* public_key
= key_pair
->public_key();
79 if (public_key
->keyType
!= ecKey
||
80 public_key
->u
.ec
.publicValue
.len
!= kUncompressedP256PointBytes
||
81 !public_key
->u
.ec
.publicValue
.data
||
82 public_key
->u
.ec
.publicValue
.data
[0] != kUncompressedECPointForm
) {
83 DVLOG(1) << "Key is invalid.";
87 // Ensure that the key is using the correct curve, i.e., NIST P-256.
88 const SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
90 DVLOG(1) << "Can't get P-256's OID.";
94 if (public_key
->u
.ec
.DEREncodedParams
.len
!= oid_data
->oid
.len
+ 2 ||
95 !public_key
->u
.ec
.DEREncodedParams
.data
||
96 public_key
->u
.ec
.DEREncodedParams
.data
[0] != SEC_ASN1_OBJECT_ID
||
97 public_key
->u
.ec
.DEREncodedParams
.data
[1] != oid_data
->oid
.len
||
98 memcmp(public_key
->u
.ec
.DEREncodedParams
.data
+ 2,
99 oid_data
->oid
.data
, oid_data
->oid
.len
) != 0) {
100 DVLOG(1) << "Key is invalid.";
103 return new P256KeyExchange(key_pair
.release(),
104 public_key
->u
.ec
.publicValue
.data
);
108 string
P256KeyExchange::NewPrivateKey() {
109 scoped_ptr
<crypto::ECPrivateKey
> key_pair(crypto::ECPrivateKey::Create());
111 if (!key_pair
.get()) {
112 DVLOG(1) << "Can't generate new key pair.";
116 vector
<uint8
> private_key
;
117 if (!key_pair
->ExportEncryptedPrivateKey(kExportPassword
,
120 DVLOG(1) << "Can't export private key.";
124 // NSS lacks the ability to import an ECC private key without
125 // also importing the public key, so it is necessary to also
126 // store the public key.
127 vector
<uint8
> public_key
;
128 if (!key_pair
->ExportPublicKey(&public_key
)) {
129 DVLOG(1) << "Can't export public key.";
133 // TODO(thaidn): determine how large encrypted private key can be
134 uint16 private_key_size
= private_key
.size();
135 const size_t result_size
= sizeof(private_key_size
) +
138 vector
<char> result(result_size
);
139 char* resultp
= &result
[0];
140 // Export the key string.
141 // The first two bytes are the private key's size in little endian.
142 private_key_size
= base::ByteSwapToLE16(private_key_size
);
143 memcpy(resultp
, &private_key_size
, sizeof(private_key_size
));
144 resultp
+= sizeof(private_key_size
);
145 memcpy(resultp
, &private_key
[0], private_key
.size());
146 resultp
+= private_key
.size();
147 memcpy(resultp
, &public_key
[0], public_key
.size());
149 return string(&result
[0], result_size
);
152 KeyExchange
* P256KeyExchange::NewKeyPair(QuicRandom
* /*rand*/) const {
153 // TODO(agl): avoid the serialisation/deserialisation in this function.
154 const string private_value
= NewPrivateKey();
155 return P256KeyExchange::New(private_value
);
158 bool P256KeyExchange::CalculateSharedKey(const StringPiece
& peer_public_value
,
159 string
* out_result
) const {
160 if (peer_public_value
.size() != kUncompressedP256PointBytes
||
161 peer_public_value
[0] != kUncompressedECPointForm
) {
162 DVLOG(1) << "Peer public value is invalid.";
166 DCHECK(key_pair_
.get());
167 DCHECK(key_pair_
->public_key());
169 SECKEYPublicKey peer_public_key
;
170 memset(&peer_public_key
, 0, sizeof(peer_public_key
));
172 peer_public_key
.keyType
= ecKey
;
173 // Both sides of a ECDH key exchange need to use the same EC params.
174 peer_public_key
.u
.ec
.DEREncodedParams
.len
=
175 key_pair_
->public_key()->u
.ec
.DEREncodedParams
.len
;
176 peer_public_key
.u
.ec
.DEREncodedParams
.data
=
177 key_pair_
->public_key()->u
.ec
.DEREncodedParams
.data
;
179 peer_public_key
.u
.ec
.publicValue
.type
= siBuffer
;
180 peer_public_key
.u
.ec
.publicValue
.data
=
181 reinterpret_cast<uint8
*>(const_cast<char*>(peer_public_value
.data()));
182 peer_public_key
.u
.ec
.publicValue
.len
= peer_public_value
.size();
184 // The NSS function performing ECDH key exchange is PK11_PubDeriveWithKDF.
185 // As this function is used for SSL/TLS's ECDH key exchanges it has many
186 // arguments, most of which are not required in QUIC.
187 // Key derivation function CKD_NULL is used because the return value of
188 // |CalculateSharedKey| is the actual ECDH shared key, not any derived keys
190 crypto::ScopedPK11SymKey
premaster_secret(
191 PK11_PubDeriveWithKDF(
197 CKM_ECDH1_DERIVE
, /* mechanism */
198 CKM_GENERIC_SECRET_KEY_GEN
, /* target */
205 if (!premaster_secret
.get()) {
206 DVLOG(1) << "Can't derive ECDH shared key.";
210 if (PK11_ExtractKeyValue(premaster_secret
.get()) != SECSuccess
) {
211 DVLOG(1) << "Can't extract raw ECDH shared key.";
215 SECItem
* key_data
= PK11_GetKeyData(premaster_secret
.get());
216 if (!key_data
|| !key_data
->data
|| key_data
->len
!= kP256FieldBytes
) {
217 DVLOG(1) << "ECDH shared key is invalid.";
221 out_result
->assign(reinterpret_cast<char*>(key_data
->data
), key_data
->len
);
225 StringPiece
P256KeyExchange::public_value() const {
226 return StringPiece(reinterpret_cast<const char*>(public_key_
),
227 sizeof(public_key_
));
230 QuicTag
P256KeyExchange::tag() const { return kP256
; }