12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/quic/crypto/p256_key_exchange.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <openssl/ec.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <openssl/ecdh.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <openssl/evp.h>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::StringPiece;
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using std::string;
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace net {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8* public_key)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : private_key_(private_key) {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(public_key_, public_key, sizeof(public_key_));
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)P256KeyExchange::~P256KeyExchange() {}
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)P256KeyExchange* P256KeyExchange::New(StringPiece key) {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (key.empty()) {
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Private key is empty";
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const uint8* keyp = reinterpret_cast<const uint8*>(key.data());
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  crypto::ScopedEC_KEY private_key(d2i_ECPrivateKey(NULL, &keyp, key.size()));
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Private key is invalid.";
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 public_key[kUncompressedP256PointBytes];
40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()),
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                         EC_KEY_get0_public_key(private_key.get()),
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                         POINT_CONVERSION_UNCOMPRESSED, public_key,
43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                         sizeof(public_key), NULL) != sizeof(public_key)) {
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't get public key.";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new P256KeyExchange(private_key.release(), public_key);
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)string P256KeyExchange::NewPrivateKey() {
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  crypto::ScopedEC_KEY key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!key.get() || !EC_KEY_generate_key(key.get())) {
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't generate a new private key.";
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return string();
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key_len = i2d_ECPrivateKey(key.get(), NULL);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (key_len <= 0) {
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't convert private key to string";
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return string();
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<uint8[]> private_key(new uint8[key_len]);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8* keyp = private_key.get();
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!i2d_ECPrivateKey(key.get(), &keyp)) {
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't convert private key to string.";
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return string();
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return string(reinterpret_cast<char*>(private_key.get()), key_len);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const {
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // TODO(agl): avoid the serialisation/deserialisation in this function.
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const string private_value = NewPrivateKey();
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return P256KeyExchange::New(private_value);
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool P256KeyExchange::CalculateSharedKey(const StringPiece& peer_public_value,
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                         string* out_result) const {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (peer_public_value.size() != kUncompressedP256PointBytes) {
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Peer public value is invalid";
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  crypto::ScopedOpenSSL<EC_POINT, EC_POINT_free>::Type point(
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!point.get() ||
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !EC_POINT_oct2point( /* also test if point is on curve */
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          EC_KEY_get0_group(private_key_.get()),
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          point.get(),
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          reinterpret_cast<const uint8*>(peer_public_value.data()),
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          peer_public_value.size(), NULL)) {
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't convert peer public value to curve point.";
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 result[kP256FieldBytes];
99b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(),
100b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                       NULL) != sizeof(result)) {
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DVLOG(1) << "Can't compute ECDH shared key.";
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)StringPiece P256KeyExchange::public_value() const {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return StringPiece(reinterpret_cast<const char*>(public_key_),
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     sizeof(public_key_));
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
114b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)QuicTag P256KeyExchange::tag() const { return kP256; }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace net
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
118