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. 4 5 #include "net/quic/crypto/p256_key_exchange.h" 6 7 #include "base/logging.h" 8 #include "base/sys_byteorder.h" 9 10 using base::StringPiece; 11 using std::string; 12 using std::vector; 13 14 namespace net { 15 16 namespace { 17 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[] = ""; 23 24 // Convert StringPiece to vector of uint8. 25 static vector<uint8> StringPieceToVector(StringPiece piece) { 26 return vector<uint8>(piece.data(), piece.data() + piece.length()); 27 } 28 29 } // namespace 30 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_)); 35 } 36 37 P256KeyExchange::~P256KeyExchange() { 38 } 39 40 // static 41 P256KeyExchange* P256KeyExchange::New(StringPiece key) { 42 if (key.size() < 2) { 43 DVLOG(1) << "Key pair is too small."; 44 return NULL; 45 } 46 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); 50 key.remove_prefix(2); 51 if (key.size() < size) { 52 DVLOG(1) << "Key pair does not contain key material."; 53 return NULL; 54 } 55 56 StringPiece private_piece(key.data(), size); 57 key.remove_prefix(size); 58 if (key.empty()) { 59 DVLOG(1) << "Key pair does not contain public key."; 60 return NULL; 61 } 62 63 StringPiece public_piece(key); 64 65 scoped_ptr<crypto::ECPrivateKey> key_pair( 66 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( 67 kExportPassword, 68 // TODO(thaidn): fix this interface to avoid copying secrets. 69 StringPieceToVector(private_piece), 70 StringPieceToVector(public_piece))); 71 72 if (!key_pair.get()) { 73 DVLOG(1) << "Can't decrypt private key."; 74 return NULL; 75 } 76 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."; 84 return NULL; 85 } 86 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); 89 if (!oid_data) { 90 DVLOG(1) << "Can't get P-256's OID."; 91 return NULL; 92 } 93 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."; 101 } 102 103 return new P256KeyExchange(key_pair.release(), 104 public_key->u.ec.publicValue.data); 105 } 106 107 // static 108 string P256KeyExchange::NewPrivateKey() { 109 scoped_ptr<crypto::ECPrivateKey> key_pair(crypto::ECPrivateKey::Create()); 110 111 if (!key_pair.get()) { 112 DVLOG(1) << "Can't generate new key pair."; 113 return string(); 114 } 115 116 vector<uint8> private_key; 117 if (!key_pair->ExportEncryptedPrivateKey(kExportPassword, 118 1 /* iteration */, 119 &private_key)) { 120 DVLOG(1) << "Can't export private key."; 121 return string(); 122 } 123 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."; 130 return string(); 131 } 132 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) + 136 private_key_size + 137 public_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()); 148 149 return string(&result[0], result_size); 150 } 151 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); 156 } 157 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."; 163 return false; 164 } 165 166 DCHECK(key_pair_.get()); 167 DCHECK(key_pair_->public_key()); 168 169 SECKEYPublicKey peer_public_key; 170 memset(&peer_public_key, 0, sizeof(peer_public_key)); 171 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; 178 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(); 183 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 189 // from it. 190 crypto::ScopedPK11SymKey premaster_secret( 191 PK11_PubDeriveWithKDF( 192 key_pair_->key(), 193 &peer_public_key, 194 PR_FALSE, 195 NULL, 196 NULL, 197 CKM_ECDH1_DERIVE, /* mechanism */ 198 CKM_GENERIC_SECRET_KEY_GEN, /* target */ 199 CKA_DERIVE, 200 0, 201 CKD_NULL, /* kdf */ 202 NULL, 203 NULL)); 204 205 if (!premaster_secret.get()) { 206 DVLOG(1) << "Can't derive ECDH shared key."; 207 return false; 208 } 209 210 if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) { 211 DVLOG(1) << "Can't extract raw ECDH shared key."; 212 return false; 213 } 214 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."; 218 return false; 219 } 220 221 out_result->assign(reinterpret_cast<char*>(key_data->data), key_data->len); 222 return true; 223 } 224 225 StringPiece P256KeyExchange::public_value() const { 226 return StringPiece(reinterpret_cast<const char*>(public_key_), 227 sizeof(public_key_)); 228 } 229 230 QuicTag P256KeyExchange::tag() const { return kP256; } 231 232 } // namespace net 233 234