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 "quiche/quic/core/crypto/p256_key_exchange.h"
6
7 #include <cstdint>
8 #include <cstring>
9 #include <memory>
10 #include <string>
11 #include <utility>
12
13 #include "absl/memory/memory.h"
14 #include "absl/strings/string_view.h"
15 #include "openssl/ec.h"
16 #include "openssl/ecdh.h"
17 #include "openssl/err.h"
18 #include "openssl/evp.h"
19 #include "quiche/quic/platform/api/quic_logging.h"
20
21 namespace quic {
22
P256KeyExchange(bssl::UniquePtr<EC_KEY> private_key,const uint8_t * public_key)23 P256KeyExchange::P256KeyExchange(bssl::UniquePtr<EC_KEY> private_key,
24 const uint8_t* public_key)
25 : private_key_(std::move(private_key)) {
26 memcpy(public_key_, public_key, sizeof(public_key_));
27 }
28
~P256KeyExchange()29 P256KeyExchange::~P256KeyExchange() {}
30
31 // static
New()32 std::unique_ptr<P256KeyExchange> P256KeyExchange::New() {
33 return New(P256KeyExchange::NewPrivateKey());
34 }
35
36 // static
New(absl::string_view key)37 std::unique_ptr<P256KeyExchange> P256KeyExchange::New(absl::string_view key) {
38 if (key.empty()) {
39 QUIC_DLOG(INFO) << "Private key is empty";
40 return nullptr;
41 }
42
43 const uint8_t* keyp = reinterpret_cast<const uint8_t*>(key.data());
44 bssl::UniquePtr<EC_KEY> private_key(
45 d2i_ECPrivateKey(nullptr, &keyp, key.size()));
46 if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
47 QUIC_DLOG(INFO) << "Private key is invalid.";
48 return nullptr;
49 }
50
51 uint8_t public_key[kUncompressedP256PointBytes];
52 if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()),
53 EC_KEY_get0_public_key(private_key.get()),
54 POINT_CONVERSION_UNCOMPRESSED, public_key,
55 sizeof(public_key), nullptr) != sizeof(public_key)) {
56 QUIC_DLOG(INFO) << "Can't get public key.";
57 return nullptr;
58 }
59
60 return absl::WrapUnique(
61 new P256KeyExchange(std::move(private_key), public_key));
62 }
63
64 // static
NewPrivateKey()65 std::string P256KeyExchange::NewPrivateKey() {
66 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
67 if (!key.get() || !EC_KEY_generate_key(key.get())) {
68 QUIC_DLOG(INFO) << "Can't generate a new private key.";
69 return std::string();
70 }
71
72 int key_len = i2d_ECPrivateKey(key.get(), nullptr);
73 if (key_len <= 0) {
74 QUIC_DLOG(INFO) << "Can't convert private key to string";
75 return std::string();
76 }
77 std::unique_ptr<uint8_t[]> private_key(new uint8_t[key_len]);
78 uint8_t* keyp = private_key.get();
79 if (!i2d_ECPrivateKey(key.get(), &keyp)) {
80 QUIC_DLOG(INFO) << "Can't convert private key to string.";
81 return std::string();
82 }
83 return std::string(reinterpret_cast<char*>(private_key.get()), key_len);
84 }
85
CalculateSharedKeySync(absl::string_view peer_public_value,std::string * shared_key) const86 bool P256KeyExchange::CalculateSharedKeySync(
87 absl::string_view peer_public_value, std::string* shared_key) const {
88 if (peer_public_value.size() != kUncompressedP256PointBytes) {
89 QUIC_DLOG(INFO) << "Peer public value is invalid";
90 return false;
91 }
92
93 bssl::UniquePtr<EC_POINT> point(
94 EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
95 if (!point.get() ||
96 !EC_POINT_oct2point(/* also test if point is on curve */
97 EC_KEY_get0_group(private_key_.get()), point.get(),
98 reinterpret_cast<const uint8_t*>(
99 peer_public_value.data()),
100 peer_public_value.size(), nullptr)) {
101 QUIC_DLOG(INFO) << "Can't convert peer public value to curve point.";
102 return false;
103 }
104
105 uint8_t result[kP256FieldBytes];
106 if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(),
107 nullptr) != sizeof(result)) {
108 QUIC_DLOG(INFO) << "Can't compute ECDH shared key.";
109 return false;
110 }
111
112 shared_key->assign(reinterpret_cast<char*>(result), sizeof(result));
113 return true;
114 }
115
public_value() const116 absl::string_view P256KeyExchange::public_value() const {
117 return absl::string_view(reinterpret_cast<const char*>(public_key_),
118 sizeof(public_key_));
119 }
120
121 } // namespace quic
122