Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / quic / crypto / p256_key_exchange_nss.cc
blob3296a6f566b8b34005a993b2c77ee44c7c624f17
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;
12 using std::string;
13 using std::vector;
15 namespace net {
17 namespace {
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());
30 } // namespace
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() {
41 // static
42 P256KeyExchange* P256KeyExchange::New(StringPiece key) {
43 if (key.size() < 2) {
44 DVLOG(1) << "Key pair is too small.";
45 return nullptr;
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);
51 key.remove_prefix(2);
52 if (key.size() < size) {
53 DVLOG(1) << "Key pair does not contain key material.";
54 return nullptr;
57 StringPiece private_piece(key.data(), size);
58 key.remove_prefix(size);
59 if (key.empty()) {
60 DVLOG(1) << "Key pair does not contain public key.";
61 return nullptr;
64 StringPiece public_piece(key);
66 scoped_ptr<crypto::ECPrivateKey> key_pair(
67 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
68 kExportPassword,
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.";
75 return nullptr;
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.";
85 return nullptr;
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);
90 if (!oid_data) {
91 DVLOG(1) << "Can't get P-256's OID.";
92 return nullptr;
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);
108 // static
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.";
114 return string();
117 vector<uint8> private_key;
118 if (!key_pair->ExportEncryptedPrivateKey(kExportPassword,
119 1 /* iteration */,
120 &private_key)) {
121 DVLOG(1) << "Can't export private key.";
122 return string();
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.";
131 return string();
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) +
137 private_key_size +
138 public_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.";
164 return false;
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
190 // from it.
191 crypto::ScopedPK11SymKey premaster_secret(
192 PK11_PubDeriveWithKDF(
193 key_pair_->key(),
194 &peer_public_key,
195 PR_FALSE,
196 nullptr,
197 nullptr,
198 CKM_ECDH1_DERIVE, /* mechanism */
199 CKM_GENERIC_SECRET_KEY_GEN, /* target */
200 CKA_DERIVE,
202 CKD_NULL, /* kdf */
203 nullptr,
204 nullptr));
206 if (!premaster_secret.get()) {
207 DVLOG(1) << "Can't derive ECDH shared key.";
208 return false;
211 if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) {
212 DVLOG(1) << "Can't extract raw ECDH shared key.";
213 return false;
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.";
219 return false;
222 out_result->assign(reinterpret_cast<char*>(key_data->data), key_data->len);
223 return true;
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; }
233 } // namespace net