Home | History | Annotate | Download | only in crypto
      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