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/numerics/safe_conversions.h"
9 #include "base/sys_byteorder.h"
11 using base::StringPiece
;
19 // Password used by |NewPrivateKey| to encrypt exported EC private keys.
20 // This is not used to provide any security, but to workaround NSS being
21 // unwilling to export unencrypted EC keys. Note that SPDY and ChannelID
22 // use the same approach.
23 const char kExportPassword
[] = "";
25 // Convert StringPiece to vector of uint8.
26 static vector
<uint8
> StringPieceToVector(StringPiece piece
) {
27 return vector
<uint8
>(piece
.data(), piece
.data() + piece
.length());
32 P256KeyExchange::P256KeyExchange(crypto::ECPrivateKey
* key_pair
,
33 const uint8
* public_key
)
34 : key_pair_(key_pair
) {
35 memcpy(public_key_
, public_key
, sizeof(public_key_
));
38 P256KeyExchange::~P256KeyExchange() {
42 P256KeyExchange
* P256KeyExchange::New(StringPiece key
) {
44 DVLOG(1) << "Key pair is too small.";
48 const uint8
* data
= reinterpret_cast<const uint8
*>(key
.data());
49 size_t size
= static_cast<size_t>(data
[0]) |
50 (static_cast<size_t>(data
[1]) << 8);
52 if (key
.size() < size
) {
53 DVLOG(1) << "Key pair does not contain key material.";
57 StringPiece
private_piece(key
.data(), size
);
58 key
.remove_prefix(size
);
60 DVLOG(1) << "Key pair does not contain public key.";
64 StringPiece
public_piece(key
);
66 scoped_ptr
<crypto::ECPrivateKey
> key_pair(
67 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
69 // TODO(thaidn): fix this interface to avoid copying secrets.
70 StringPieceToVector(private_piece
),
71 StringPieceToVector(public_piece
)));
73 if (!key_pair
.get()) {
74 DVLOG(1) << "Can't decrypt private key.";
78 // Perform some sanity checks on the public key.
79 SECKEYPublicKey
* public_key
= key_pair
->public_key();
80 if (public_key
->keyType
!= ecKey
||
81 public_key
->u
.ec
.publicValue
.len
!= kUncompressedP256PointBytes
||
82 !public_key
->u
.ec
.publicValue
.data
||
83 public_key
->u
.ec
.publicValue
.data
[0] != kUncompressedECPointForm
) {
84 DVLOG(1) << "Key is invalid.";
88 // Ensure that the key is using the correct curve, i.e., NIST P-256.
89 const SECOidData
* oid_data
= SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1
);
91 DVLOG(1) << "Can't get P-256's OID.";
95 if (public_key
->u
.ec
.DEREncodedParams
.len
!= oid_data
->oid
.len
+ 2 ||
96 !public_key
->u
.ec
.DEREncodedParams
.data
||
97 public_key
->u
.ec
.DEREncodedParams
.data
[0] != SEC_ASN1_OBJECT_ID
||
98 public_key
->u
.ec
.DEREncodedParams
.data
[1] != oid_data
->oid
.len
||
99 memcmp(public_key
->u
.ec
.DEREncodedParams
.data
+ 2,
100 oid_data
->oid
.data
, oid_data
->oid
.len
) != 0) {
101 DVLOG(1) << "Key is invalid.";
104 return new P256KeyExchange(key_pair
.release(),
105 public_key
->u
.ec
.publicValue
.data
);
109 string
P256KeyExchange::NewPrivateKey() {
110 scoped_ptr
<crypto::ECPrivateKey
> key_pair(crypto::ECPrivateKey::Create());
112 if (!key_pair
.get()) {
113 DVLOG(1) << "Can't generate new key pair.";
117 vector
<uint8
> private_key
;
118 if (!key_pair
->ExportEncryptedPrivateKey(kExportPassword
,
121 DVLOG(1) << "Can't export private key.";
125 // NSS lacks the ability to import an ECC private key without
126 // also importing the public key, so it is necessary to also
127 // store the public key.
128 vector
<uint8
> public_key
;
129 if (!key_pair
->ExportPublicKey(&public_key
)) {
130 DVLOG(1) << "Can't export public key.";
134 // TODO(thaidn): determine how large encrypted private key can be
135 uint16 private_key_size
= base::checked_cast
<uint16
>(private_key
.size());
136 const size_t result_size
= sizeof(private_key_size
) +
139 vector
<char> result(result_size
);
140 char* resultp
= &result
[0];
141 // Export the key string.
142 // The first two bytes are the private key's size in little endian.
143 private_key_size
= base::ByteSwapToLE16(private_key_size
);
144 memcpy(resultp
, &private_key_size
, sizeof(private_key_size
));
145 resultp
+= sizeof(private_key_size
);
146 memcpy(resultp
, &private_key
[0], private_key
.size());
147 resultp
+= private_key
.size();
148 memcpy(resultp
, &public_key
[0], public_key
.size());
150 return string(&result
[0], result_size
);
153 KeyExchange
* P256KeyExchange::NewKeyPair(QuicRandom
* /*rand*/) const {
154 // TODO(agl): avoid the serialisation/deserialisation in this function.
155 const string private_value
= NewPrivateKey();
156 return P256KeyExchange::New(private_value
);
159 bool P256KeyExchange::CalculateSharedKey(const StringPiece
& peer_public_value
,
160 string
* out_result
) const {
161 if (peer_public_value
.size() != kUncompressedP256PointBytes
||
162 peer_public_value
[0] != kUncompressedECPointForm
) {
163 DVLOG(1) << "Peer public value is invalid.";
167 DCHECK(key_pair_
.get());
168 DCHECK(key_pair_
->public_key());
170 SECKEYPublicKey peer_public_key
;
171 memset(&peer_public_key
, 0, sizeof(peer_public_key
));
173 peer_public_key
.keyType
= ecKey
;
174 // Both sides of a ECDH key exchange need to use the same EC params.
175 peer_public_key
.u
.ec
.DEREncodedParams
.len
=
176 key_pair_
->public_key()->u
.ec
.DEREncodedParams
.len
;
177 peer_public_key
.u
.ec
.DEREncodedParams
.data
=
178 key_pair_
->public_key()->u
.ec
.DEREncodedParams
.data
;
180 peer_public_key
.u
.ec
.publicValue
.type
= siBuffer
;
181 peer_public_key
.u
.ec
.publicValue
.data
=
182 reinterpret_cast<uint8
*>(const_cast<char*>(peer_public_value
.data()));
183 peer_public_key
.u
.ec
.publicValue
.len
= peer_public_value
.size();
185 // The NSS function performing ECDH key exchange is PK11_PubDeriveWithKDF.
186 // As this function is used for SSL/TLS's ECDH key exchanges it has many
187 // arguments, most of which are not required in QUIC.
188 // Key derivation function CKD_NULL is used because the return value of
189 // |CalculateSharedKey| is the actual ECDH shared key, not any derived keys
191 crypto::ScopedPK11SymKey
premaster_secret(
192 PK11_PubDeriveWithKDF(
198 CKM_ECDH1_DERIVE
, /* mechanism */
199 CKM_GENERIC_SECRET_KEY_GEN
, /* target */
206 if (!premaster_secret
.get()) {
207 DVLOG(1) << "Can't derive ECDH shared key.";
211 if (PK11_ExtractKeyValue(premaster_secret
.get()) != SECSuccess
) {
212 DVLOG(1) << "Can't extract raw ECDH shared key.";
216 SECItem
* key_data
= PK11_GetKeyData(premaster_secret
.get());
217 if (!key_data
|| !key_data
->data
|| key_data
->len
!= kP256FieldBytes
) {
218 DVLOG(1) << "ECDH shared key is invalid.";
222 out_result
->assign(reinterpret_cast<char*>(key_data
->data
), key_data
->len
);
226 StringPiece
P256KeyExchange::public_value() const {
227 return StringPiece(reinterpret_cast<const char*>(public_key_
),
228 sizeof(public_key_
));
231 QuicTag
P256KeyExchange::tag() const { return kP256
; }