xref: /aosp_15_r20/external/boringssl/src/ssl/ssl_key_share.cc (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (c) 2015, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/ssl.h>
16 
17 #include <assert.h>
18 #include <string.h>
19 
20 #include <utility>
21 
22 #include <openssl/bn.h>
23 #include <openssl/bytestring.h>
24 #include <openssl/curve25519.h>
25 #include <openssl/ec.h>
26 #include <openssl/err.h>
27 #define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER
28 #include <openssl/experimental/kyber.h>
29 #include <openssl/hrss.h>
30 #include <openssl/mem.h>
31 #include <openssl/nid.h>
32 #include <openssl/rand.h>
33 #include <openssl/span.h>
34 
35 #include "internal.h"
36 #include "../crypto/internal.h"
37 
38 BSSL_NAMESPACE_BEGIN
39 
40 namespace {
41 
42 class ECKeyShare : public SSLKeyShare {
43  public:
ECKeyShare(const EC_GROUP * group,uint16_t group_id)44   ECKeyShare(const EC_GROUP *group, uint16_t group_id)
45       : group_(group), group_id_(group_id) {}
46 
GroupID() const47   uint16_t GroupID() const override { return group_id_; }
48 
Generate(CBB * out)49   bool Generate(CBB *out) override {
50     assert(!private_key_);
51     // Generate a private key.
52     private_key_.reset(BN_new());
53     if (!private_key_ ||
54         !BN_rand_range_ex(private_key_.get(), 1, EC_GROUP_get0_order(group_))) {
55       return false;
56     }
57 
58     // Compute the corresponding public key and serialize it.
59     UniquePtr<EC_POINT> public_key(EC_POINT_new(group_));
60     if (!public_key ||
61         !EC_POINT_mul(group_, public_key.get(), private_key_.get(), nullptr,
62                       nullptr, /*ctx=*/nullptr) ||
63         !EC_POINT_point2cbb(out, group_, public_key.get(),
64                             POINT_CONVERSION_UNCOMPRESSED, /*ctx=*/nullptr)) {
65       return false;
66     }
67 
68     return true;
69   }
70 
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)71   bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
72              uint8_t *out_alert, Span<const uint8_t> peer_key) override {
73     // ECDH may be fit into a KEM-like abstraction by using a second keypair's
74     // public key as the ciphertext.
75     *out_alert = SSL_AD_INTERNAL_ERROR;
76     return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
77   }
78 
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)79   bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
80              Span<const uint8_t> ciphertext) override {
81     assert(group_);
82     assert(private_key_);
83     *out_alert = SSL_AD_INTERNAL_ERROR;
84 
85     UniquePtr<EC_POINT> peer_point(EC_POINT_new(group_));
86     UniquePtr<EC_POINT> result(EC_POINT_new(group_));
87     UniquePtr<BIGNUM> x(BN_new());
88     if (!peer_point || !result || !x) {
89       return false;
90     }
91 
92     if (ciphertext.empty() || ciphertext[0] != POINT_CONVERSION_UNCOMPRESSED ||
93         !EC_POINT_oct2point(group_, peer_point.get(), ciphertext.data(),
94                             ciphertext.size(), /*ctx=*/nullptr)) {
95       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
96       *out_alert = SSL_AD_DECODE_ERROR;
97       return false;
98     }
99 
100     // Compute the x-coordinate of |peer_key| * |private_key_|.
101     if (!EC_POINT_mul(group_, result.get(), nullptr, peer_point.get(),
102                       private_key_.get(), /*ctx=*/nullptr) ||
103         !EC_POINT_get_affine_coordinates_GFp(group_, result.get(), x.get(),
104                                              nullptr, /*ctx=*/nullptr)) {
105       return false;
106     }
107 
108     // Encode the x-coordinate left-padded with zeros.
109     Array<uint8_t> secret;
110     if (!secret.Init((EC_GROUP_get_degree(group_) + 7) / 8) ||
111         !BN_bn2bin_padded(secret.data(), secret.size(), x.get())) {
112       return false;
113     }
114 
115     *out_secret = std::move(secret);
116     return true;
117   }
118 
SerializePrivateKey(CBB * out)119   bool SerializePrivateKey(CBB *out) override {
120     assert(group_);
121     assert(private_key_);
122     // Padding is added to avoid leaking the length.
123     size_t len = BN_num_bytes(EC_GROUP_get0_order(group_));
124     return BN_bn2cbb_padded(out, len, private_key_.get());
125   }
126 
DeserializePrivateKey(CBS * in)127   bool DeserializePrivateKey(CBS *in) override {
128     assert(!private_key_);
129     private_key_.reset(BN_bin2bn(CBS_data(in), CBS_len(in), nullptr));
130     return private_key_ != nullptr;
131   }
132 
133  private:
134   UniquePtr<BIGNUM> private_key_;
135   const EC_GROUP *const group_ = nullptr;
136   uint16_t group_id_;
137 };
138 
139 class X25519KeyShare : public SSLKeyShare {
140  public:
X25519KeyShare()141   X25519KeyShare() {}
142 
GroupID() const143   uint16_t GroupID() const override { return SSL_GROUP_X25519; }
144 
Generate(CBB * out)145   bool Generate(CBB *out) override {
146     uint8_t public_key[32];
147     X25519_keypair(public_key, private_key_);
148     return !!CBB_add_bytes(out, public_key, sizeof(public_key));
149   }
150 
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)151   bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
152              uint8_t *out_alert, Span<const uint8_t> peer_key) override {
153     // X25519 may be fit into a KEM-like abstraction by using a second keypair's
154     // public key as the ciphertext.
155     *out_alert = SSL_AD_INTERNAL_ERROR;
156     return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
157   }
158 
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)159   bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
160              Span<const uint8_t> ciphertext) override {
161     *out_alert = SSL_AD_INTERNAL_ERROR;
162 
163     Array<uint8_t> secret;
164     if (!secret.Init(32)) {
165       return false;
166     }
167 
168     if (ciphertext.size() != 32 ||  //
169         !X25519(secret.data(), private_key_, ciphertext.data())) {
170       *out_alert = SSL_AD_DECODE_ERROR;
171       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
172       return false;
173     }
174 
175     *out_secret = std::move(secret);
176     return true;
177   }
178 
SerializePrivateKey(CBB * out)179   bool SerializePrivateKey(CBB *out) override {
180     return CBB_add_bytes(out, private_key_, sizeof(private_key_));
181   }
182 
DeserializePrivateKey(CBS * in)183   bool DeserializePrivateKey(CBS *in) override {
184     if (CBS_len(in) != sizeof(private_key_) ||
185         !CBS_copy_bytes(in, private_key_, sizeof(private_key_))) {
186       return false;
187     }
188     return true;
189   }
190 
191  private:
192   uint8_t private_key_[32];
193 };
194 
195 class X25519Kyber768KeyShare : public SSLKeyShare {
196  public:
X25519Kyber768KeyShare()197   X25519Kyber768KeyShare() {}
198 
GroupID() const199   uint16_t GroupID() const override {
200     return SSL_GROUP_X25519_KYBER768_DRAFT00;
201   }
202 
Generate(CBB * out)203   bool Generate(CBB *out) override {
204     uint8_t x25519_public_key[32];
205     X25519_keypair(x25519_public_key, x25519_private_key_);
206 
207     uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES];
208     KYBER_generate_key(kyber_public_key, &kyber_private_key_);
209 
210     if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
211         !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) {
212       return false;
213     }
214 
215     return true;
216   }
217 
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)218   bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
219              uint8_t *out_alert, Span<const uint8_t> peer_key) override {
220     Array<uint8_t> secret;
221     if (!secret.Init(32 + KYBER_SHARED_SECRET_BYTES)) {
222       return false;
223     }
224 
225     uint8_t x25519_public_key[32];
226     X25519_keypair(x25519_public_key, x25519_private_key_);
227     KYBER_public_key peer_kyber_pub;
228     CBS peer_key_cbs;
229     CBS peer_x25519_cbs;
230     CBS peer_kyber_cbs;
231     CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size());
232     if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) ||
233         !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs,
234                        KYBER_PUBLIC_KEY_BYTES) ||
235         CBS_len(&peer_key_cbs) != 0 ||
236         !X25519(secret.data(), x25519_private_key_,
237                 CBS_data(&peer_x25519_cbs)) ||
238         !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) {
239       *out_alert = SSL_AD_DECODE_ERROR;
240       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
241       return false;
242     }
243 
244     uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES];
245     KYBER_encap(kyber_ciphertext, secret.data() + 32, &peer_kyber_pub);
246 
247     if (!CBB_add_bytes(out_ciphertext, x25519_public_key,
248                        sizeof(x25519_public_key)) ||
249         !CBB_add_bytes(out_ciphertext, kyber_ciphertext,
250                        sizeof(kyber_ciphertext))) {
251       return false;
252     }
253 
254     *out_secret = std::move(secret);
255     return true;
256   }
257 
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)258   bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
259              Span<const uint8_t> ciphertext) override {
260     *out_alert = SSL_AD_INTERNAL_ERROR;
261 
262     Array<uint8_t> secret;
263     if (!secret.Init(32 + KYBER_SHARED_SECRET_BYTES)) {
264       return false;
265     }
266 
267     if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES ||
268         !X25519(secret.data(), x25519_private_key_, ciphertext.data())) {
269       *out_alert = SSL_AD_DECODE_ERROR;
270       OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
271       return false;
272     }
273 
274     KYBER_decap(secret.data() + 32, ciphertext.data() + 32,
275                 &kyber_private_key_);
276     *out_secret = std::move(secret);
277     return true;
278   }
279 
280  private:
281   uint8_t x25519_private_key_[32];
282   KYBER_private_key kyber_private_key_;
283 };
284 
285 constexpr NamedGroup kNamedGroups[] = {
286     {NID_secp224r1, SSL_GROUP_SECP224R1, "P-224", "secp224r1"},
287     {NID_X9_62_prime256v1, SSL_GROUP_SECP256R1, "P-256", "prime256v1"},
288     {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"},
289     {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"},
290     {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"},
291     {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00,
292      "X25519Kyber768Draft00", ""},
293 };
294 
295 }  // namespace
296 
NamedGroups()297 Span<const NamedGroup> NamedGroups() {
298   return MakeConstSpan(kNamedGroups, OPENSSL_ARRAY_SIZE(kNamedGroups));
299 }
300 
Create(uint16_t group_id)301 UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
302   switch (group_id) {
303     case SSL_GROUP_SECP224R1:
304       return MakeUnique<ECKeyShare>(EC_group_p224(), SSL_GROUP_SECP224R1);
305     case SSL_GROUP_SECP256R1:
306       return MakeUnique<ECKeyShare>(EC_group_p256(), SSL_GROUP_SECP256R1);
307     case SSL_GROUP_SECP384R1:
308       return MakeUnique<ECKeyShare>(EC_group_p384(), SSL_GROUP_SECP384R1);
309     case SSL_GROUP_SECP521R1:
310       return MakeUnique<ECKeyShare>(EC_group_p521(), SSL_GROUP_SECP521R1);
311     case SSL_GROUP_X25519:
312       return MakeUnique<X25519KeyShare>();
313     case SSL_GROUP_X25519_KYBER768_DRAFT00:
314       return MakeUnique<X25519Kyber768KeyShare>();
315     default:
316       return nullptr;
317   }
318 }
319 
ssl_nid_to_group_id(uint16_t * out_group_id,int nid)320 bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
321   for (const auto &group : kNamedGroups) {
322     if (group.nid == nid) {
323       *out_group_id = group.group_id;
324       return true;
325     }
326   }
327   return false;
328 }
329 
ssl_name_to_group_id(uint16_t * out_group_id,const char * name,size_t len)330 bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) {
331   for (const auto &group : kNamedGroups) {
332     if (len == strlen(group.name) &&
333         !strncmp(group.name, name, len)) {
334       *out_group_id = group.group_id;
335       return true;
336     }
337     if (strlen(group.alias) > 0 && len == strlen(group.alias) &&
338         !strncmp(group.alias, name, len)) {
339       *out_group_id = group.group_id;
340       return true;
341     }
342   }
343   return false;
344 }
345 
ssl_group_id_to_nid(uint16_t group_id)346 int ssl_group_id_to_nid(uint16_t group_id) {
347   for (const auto &group : kNamedGroups) {
348     if (group.group_id == group_id) {
349       return group.nid;
350     }
351   }
352   return NID_undef;
353 }
354 
355 BSSL_NAMESPACE_END
356 
357 using namespace bssl;
358 
SSL_get_group_name(uint16_t group_id)359 const char* SSL_get_group_name(uint16_t group_id) {
360   for (const auto &group : kNamedGroups) {
361     if (group.group_id == group_id) {
362       return group.name;
363     }
364   }
365   return nullptr;
366 }
367 
SSL_get_all_group_names(const char ** out,size_t max_out)368 size_t SSL_get_all_group_names(const char **out, size_t max_out) {
369   return GetAllNames(out, max_out, Span<const char *>(), &NamedGroup::name,
370                      MakeConstSpan(kNamedGroups));
371 }
372