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