blob: 1cabc6459ef58b512ce4595ffea8e55ddf241e72 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h"
6
7#include <cstdint>
8#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07009#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include <utility>
11
12#include "third_party/boringssl/src/include/openssl/ec.h"
13#include "third_party/boringssl/src/include/openssl/ecdh.h"
14#include "third_party/boringssl/src/include/openssl/err.h"
15#include "third_party/boringssl/src/include/openssl/evp.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050018
19namespace quic {
QUICHE teama6ef0a62019-03-07 20:34:33 -050020
21P256KeyExchange::P256KeyExchange(bssl::UniquePtr<EC_KEY> private_key,
22 const uint8_t* public_key)
23 : private_key_(std::move(private_key)) {
24 memcpy(public_key_, public_key, sizeof(public_key_));
25}
26
27P256KeyExchange::~P256KeyExchange() {}
28
29// static
QUICHE teamfe1aca62019-03-14 13:39:01 -070030std::unique_ptr<P256KeyExchange> P256KeyExchange::New() {
31 return New(P256KeyExchange::NewPrivateKey());
32}
33
34// static
QUICHE teama6ef0a62019-03-07 20:34:33 -050035std::unique_ptr<P256KeyExchange> P256KeyExchange::New(QuicStringPiece key) {
36 if (key.empty()) {
37 QUIC_DLOG(INFO) << "Private key is empty";
38 return nullptr;
39 }
40
41 const uint8_t* keyp = reinterpret_cast<const uint8_t*>(key.data());
42 bssl::UniquePtr<EC_KEY> private_key(
43 d2i_ECPrivateKey(nullptr, &keyp, key.size()));
44 if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
45 QUIC_DLOG(INFO) << "Private key is invalid.";
46 return nullptr;
47 }
48
49 uint8_t public_key[kUncompressedP256PointBytes];
50 if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()),
51 EC_KEY_get0_public_key(private_key.get()),
52 POINT_CONVERSION_UNCOMPRESSED, public_key,
53 sizeof(public_key), nullptr) != sizeof(public_key)) {
54 QUIC_DLOG(INFO) << "Can't get public key.";
55 return nullptr;
56 }
57
58 return QuicWrapUnique(
59 new P256KeyExchange(std::move(private_key), public_key));
60}
61
62// static
vasilvvc48c8712019-03-11 13:38:16 -070063std::string P256KeyExchange::NewPrivateKey() {
QUICHE teama6ef0a62019-03-07 20:34:33 -050064 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
65 if (!key.get() || !EC_KEY_generate_key(key.get())) {
66 QUIC_DLOG(INFO) << "Can't generate a new private key.";
vasilvvc48c8712019-03-11 13:38:16 -070067 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 }
69
70 int key_len = i2d_ECPrivateKey(key.get(), nullptr);
71 if (key_len <= 0) {
72 QUIC_DLOG(INFO) << "Can't convert private key to string";
vasilvvc48c8712019-03-11 13:38:16 -070073 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 }
75 std::unique_ptr<uint8_t[]> private_key(new uint8_t[key_len]);
76 uint8_t* keyp = private_key.get();
77 if (!i2d_ECPrivateKey(key.get(), &keyp)) {
78 QUIC_DLOG(INFO) << "Can't convert private key to string.";
vasilvvc48c8712019-03-11 13:38:16 -070079 return std::string();
QUICHE teama6ef0a62019-03-07 20:34:33 -050080 }
vasilvvc48c8712019-03-11 13:38:16 -070081 return std::string(reinterpret_cast<char*>(private_key.get()), key_len);
QUICHE teama6ef0a62019-03-07 20:34:33 -050082}
83
QUICHE teamfe1aca62019-03-14 13:39:01 -070084bool P256KeyExchange::CalculateSharedKeySync(QuicStringPiece peer_public_value,
85 std::string* shared_key) const {
QUICHE teama6ef0a62019-03-07 20:34:33 -050086 if (peer_public_value.size() != kUncompressedP256PointBytes) {
87 QUIC_DLOG(INFO) << "Peer public value is invalid";
88 return false;
89 }
90
91 bssl::UniquePtr<EC_POINT> point(
92 EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
93 if (!point.get() ||
94 !EC_POINT_oct2point(/* also test if point is on curve */
95 EC_KEY_get0_group(private_key_.get()), point.get(),
96 reinterpret_cast<const uint8_t*>(
97 peer_public_value.data()),
98 peer_public_value.size(), nullptr)) {
99 QUIC_DLOG(INFO) << "Can't convert peer public value to curve point.";
100 return false;
101 }
102
103 uint8_t result[kP256FieldBytes];
104 if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(),
105 nullptr) != sizeof(result)) {
106 QUIC_DLOG(INFO) << "Can't compute ECDH shared key.";
107 return false;
108 }
109
QUICHE teamfe1aca62019-03-14 13:39:01 -0700110 shared_key->assign(reinterpret_cast<char*>(result), sizeof(result));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 return true;
112}
113
QUICHE teama6ef0a62019-03-07 20:34:33 -0500114QuicStringPiece P256KeyExchange::public_value() const {
115 return QuicStringPiece(reinterpret_cast<const char*>(public_key_),
116 sizeof(public_key_));
117}
118
119} // namespace quic