xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/crypto/p256_key_exchange.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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