/src/boringssl/ssl/ssl_key_share.cc
Line | Count | Source |
1 | | // Copyright 2015 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/ssl.h> |
16 | | |
17 | | #include <assert.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include <iterator> |
21 | | #include <utility> |
22 | | |
23 | | #include <openssl/bn.h> |
24 | | #include <openssl/bytestring.h> |
25 | | #include <openssl/curve25519.h> |
26 | | #include <openssl/ec.h> |
27 | | #include <openssl/err.h> |
28 | | #include <openssl/hrss.h> |
29 | | #include <openssl/mem.h> |
30 | | #include <openssl/mlkem.h> |
31 | | #include <openssl/nid.h> |
32 | | #include <openssl/rand.h> |
33 | | #include <openssl/span.h> |
34 | | |
35 | | #include "../crypto/internal.h" |
36 | | #include "../crypto/kyber/internal.h" |
37 | | #include "internal.h" |
38 | | |
39 | | BSSL_NAMESPACE_BEGIN |
40 | | |
41 | | namespace { |
42 | | |
43 | | class ECKeyShare : public SSLKeyShare { |
44 | | public: |
45 | | ECKeyShare(const EC_GROUP *group, uint16_t group_id) |
46 | 31.8k | : group_(group), group_id_(group_id) {} |
47 | | |
48 | 41 | uint16_t GroupID() const override { return group_id_; } |
49 | | |
50 | 31.2k | bool Generate(CBB *out) override { |
51 | 31.2k | assert(!private_key_); |
52 | | // Generate a private key. |
53 | 31.2k | private_key_.reset(BN_new()); |
54 | 31.2k | if (!private_key_ || |
55 | 31.2k | !BN_rand_range_ex(private_key_.get(), 1, EC_GROUP_get0_order(group_))) { |
56 | 0 | return false; |
57 | 0 | } |
58 | | |
59 | | // Compute the corresponding public key and serialize it. |
60 | 31.2k | UniquePtr<EC_POINT> public_key(EC_POINT_new(group_)); |
61 | 31.2k | if (!public_key || |
62 | 31.2k | !EC_POINT_mul(group_, public_key.get(), private_key_.get(), nullptr, |
63 | 31.2k | nullptr, /*ctx=*/nullptr) || |
64 | 31.2k | !EC_POINT_point2cbb(out, group_, public_key.get(), |
65 | 31.2k | POINT_CONVERSION_UNCOMPRESSED, /*ctx=*/nullptr)) { |
66 | 0 | return false; |
67 | 0 | } |
68 | | |
69 | 31.2k | return true; |
70 | 31.2k | } |
71 | | |
72 | | bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret, |
73 | 29.5k | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
74 | | // ECDH may be fit into a KEM-like abstraction by using a second keypair's |
75 | | // public key as the ciphertext. |
76 | 29.5k | *out_alert = SSL_AD_INTERNAL_ERROR; |
77 | 29.5k | return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key); |
78 | 29.5k | } |
79 | | |
80 | | bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert, |
81 | 30.3k | Span<const uint8_t> ciphertext) override { |
82 | 30.3k | assert(group_); |
83 | 30.3k | assert(private_key_); |
84 | 30.3k | *out_alert = SSL_AD_INTERNAL_ERROR; |
85 | | |
86 | 30.3k | UniquePtr<EC_POINT> peer_point(EC_POINT_new(group_)); |
87 | 30.3k | UniquePtr<EC_POINT> result(EC_POINT_new(group_)); |
88 | 30.3k | UniquePtr<BIGNUM> x(BN_new()); |
89 | 30.3k | if (!peer_point || !result || !x) { |
90 | 0 | return false; |
91 | 0 | } |
92 | | |
93 | 30.3k | if (ciphertext.empty() || ciphertext[0] != POINT_CONVERSION_UNCOMPRESSED || |
94 | 30.2k | !EC_POINT_oct2point(group_, peer_point.get(), ciphertext.data(), |
95 | 30.2k | ciphertext.size(), /*ctx=*/nullptr)) { |
96 | 368 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
97 | 368 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
98 | 368 | return false; |
99 | 368 | } |
100 | | |
101 | | // Compute the x-coordinate of |peer_key| * |private_key_|. |
102 | 29.9k | if (!EC_POINT_mul(group_, result.get(), nullptr, peer_point.get(), |
103 | 29.9k | private_key_.get(), /*ctx=*/nullptr) || |
104 | 29.9k | !EC_POINT_get_affine_coordinates_GFp(group_, result.get(), x.get(), |
105 | 29.9k | nullptr, /*ctx=*/nullptr)) { |
106 | 4 | return false; |
107 | 4 | } |
108 | | |
109 | | // Encode the x-coordinate left-padded with zeros. |
110 | 29.9k | Array<uint8_t> secret; |
111 | 29.9k | if (!secret.InitForOverwrite((EC_GROUP_get_degree(group_) + 7) / 8) || |
112 | 29.9k | !BN_bn2bin_padded(secret.data(), secret.size(), x.get())) { |
113 | 0 | return false; |
114 | 0 | } |
115 | | |
116 | 29.9k | *out_secret = std::move(secret); |
117 | 29.9k | return true; |
118 | 29.9k | } |
119 | | |
120 | 0 | bool SerializePrivateKey(CBB *out) override { |
121 | 0 | assert(group_); |
122 | 0 | assert(private_key_); |
123 | | // Padding is added to avoid leaking the length. |
124 | 0 | size_t len = BN_num_bytes(EC_GROUP_get0_order(group_)); |
125 | 0 | return BN_bn2cbb_padded(out, len, private_key_.get()); |
126 | 0 | } |
127 | | |
128 | 564 | bool DeserializePrivateKey(CBS *in) override { |
129 | 564 | assert(!private_key_); |
130 | 564 | private_key_.reset(BN_bin2bn(CBS_data(in), CBS_len(in), nullptr)); |
131 | 564 | return private_key_ != nullptr; |
132 | 564 | } |
133 | | |
134 | | private: |
135 | | UniquePtr<BIGNUM> private_key_; |
136 | | const EC_GROUP *const group_ = nullptr; |
137 | | uint16_t group_id_; |
138 | | }; |
139 | | |
140 | | class X25519KeyShare : public SSLKeyShare { |
141 | | public: |
142 | 87.8k | X25519KeyShare() {} |
143 | | |
144 | 2.54k | uint16_t GroupID() const override { return SSL_GROUP_X25519; } |
145 | | |
146 | 87.7k | bool Generate(CBB *out) override { |
147 | 87.7k | uint8_t public_key[32]; |
148 | 87.7k | X25519_keypair(public_key, private_key_); |
149 | 87.7k | return !!CBB_add_bytes(out, public_key, sizeof(public_key)); |
150 | 87.7k | } |
151 | | |
152 | | bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret, |
153 | 21.3k | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
154 | | // X25519 may be fit into a KEM-like abstraction by using a second keypair's |
155 | | // public key as the ciphertext. |
156 | 21.3k | *out_alert = SSL_AD_INTERNAL_ERROR; |
157 | 21.3k | return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key); |
158 | 21.3k | } |
159 | | |
160 | | bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert, |
161 | 26.1k | Span<const uint8_t> ciphertext) override { |
162 | 26.1k | *out_alert = SSL_AD_INTERNAL_ERROR; |
163 | | |
164 | 26.1k | Array<uint8_t> secret; |
165 | 26.1k | if (!secret.InitForOverwrite(32)) { |
166 | 0 | return false; |
167 | 0 | } |
168 | | |
169 | 26.1k | if (ciphertext.size() != 32 || // |
170 | 26.1k | !X25519(secret.data(), private_key_, ciphertext.data())) { |
171 | 19 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
172 | 19 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
173 | 19 | return false; |
174 | 19 | } |
175 | | |
176 | 26.1k | *out_secret = std::move(secret); |
177 | 26.1k | return true; |
178 | 26.1k | } |
179 | | |
180 | 0 | bool SerializePrivateKey(CBB *out) override { |
181 | 0 | return CBB_add_bytes(out, private_key_, sizeof(private_key_)); |
182 | 0 | } |
183 | | |
184 | 89 | bool DeserializePrivateKey(CBS *in) override { |
185 | 89 | if (CBS_len(in) != sizeof(private_key_) || |
186 | 79 | !CBS_copy_bytes(in, private_key_, sizeof(private_key_))) { |
187 | 10 | return false; |
188 | 10 | } |
189 | 79 | return true; |
190 | 89 | } |
191 | | |
192 | | private: |
193 | | uint8_t private_key_[32]; |
194 | | }; |
195 | | |
196 | | // draft-tls-westerbaan-xyber768d00-03 |
197 | | class X25519Kyber768KeyShare : public SSLKeyShare { |
198 | | public: |
199 | 255 | X25519Kyber768KeyShare() {} |
200 | | |
201 | 2 | uint16_t GroupID() const override { |
202 | 2 | return SSL_GROUP_X25519_KYBER768_DRAFT00; |
203 | 2 | } |
204 | | |
205 | 132 | bool Generate(CBB *out) override { |
206 | 132 | uint8_t x25519_public_key[32]; |
207 | 132 | X25519_keypair(x25519_public_key, x25519_private_key_); |
208 | | |
209 | 132 | uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; |
210 | 132 | KYBER_generate_key(kyber_public_key, &kyber_private_key_); |
211 | | |
212 | 132 | if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || |
213 | 132 | !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { |
214 | 0 | return false; |
215 | 0 | } |
216 | | |
217 | 132 | return true; |
218 | 132 | } |
219 | | |
220 | | bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret, |
221 | 123 | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
222 | 123 | Array<uint8_t> secret; |
223 | 123 | if (!secret.InitForOverwrite(32 + KYBER_SHARED_SECRET_BYTES)) { |
224 | 0 | return false; |
225 | 0 | } |
226 | | |
227 | 123 | uint8_t x25519_public_key[32]; |
228 | 123 | X25519_keypair(x25519_public_key, x25519_private_key_); |
229 | 123 | KYBER_public_key peer_kyber_pub; |
230 | 123 | CBS peer_key_cbs, peer_x25519_cbs, peer_kyber_cbs; |
231 | 123 | CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); |
232 | 123 | if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) || |
233 | 121 | !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs, |
234 | 121 | KYBER_PUBLIC_KEY_BYTES) || |
235 | 118 | CBS_len(&peer_key_cbs) != 0 || |
236 | 115 | !X25519(secret.data(), x25519_private_key_, |
237 | 115 | CBS_data(&peer_x25519_cbs)) || |
238 | 112 | !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { |
239 | 49 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
240 | 49 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
241 | 49 | return false; |
242 | 49 | } |
243 | | |
244 | 74 | uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; |
245 | 74 | KYBER_encap(kyber_ciphertext, secret.data() + 32, &peer_kyber_pub); |
246 | | |
247 | 74 | if (!CBB_add_bytes(out_ciphertext, x25519_public_key, |
248 | 74 | sizeof(x25519_public_key)) || |
249 | 74 | !CBB_add_bytes(out_ciphertext, kyber_ciphertext, |
250 | 74 | sizeof(kyber_ciphertext))) { |
251 | 0 | return false; |
252 | 0 | } |
253 | | |
254 | 74 | *out_secret = std::move(secret); |
255 | 74 | return true; |
256 | 74 | } |
257 | | |
258 | | bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert, |
259 | 0 | Span<const uint8_t> ciphertext) override { |
260 | 0 | *out_alert = SSL_AD_INTERNAL_ERROR; |
261 | |
|
262 | 0 | Array<uint8_t> secret; |
263 | 0 | if (!secret.InitForOverwrite(32 + KYBER_SHARED_SECRET_BYTES)) { |
264 | 0 | return false; |
265 | 0 | } |
266 | | |
267 | 0 | if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || |
268 | 0 | !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { |
269 | 0 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
270 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
271 | 0 | return false; |
272 | 0 | } |
273 | | |
274 | 0 | KYBER_decap(secret.data() + 32, ciphertext.data() + 32, |
275 | 0 | &kyber_private_key_); |
276 | 0 | *out_secret = std::move(secret); |
277 | 0 | return true; |
278 | 0 | } |
279 | | |
280 | | private: |
281 | | uint8_t x25519_private_key_[32]; |
282 | | KYBER_private_key kyber_private_key_; |
283 | | }; |
284 | | |
285 | | // draft-ietf-tls-ecdhe-mlkem-00 |
286 | | class X25519MLKEM768KeyShare : public SSLKeyShare { |
287 | | public: |
288 | 62.5k | X25519MLKEM768KeyShare() {} |
289 | | |
290 | 2.56k | uint16_t GroupID() const override { return SSL_GROUP_X25519_MLKEM768; } |
291 | | |
292 | 62.2k | bool Generate(CBB *out) override { |
293 | 62.2k | uint8_t mlkem_public_key[MLKEM768_PUBLIC_KEY_BYTES]; |
294 | 62.2k | MLKEM768_generate_key(mlkem_public_key, /*optional_out_seed=*/nullptr, |
295 | 62.2k | &mlkem_private_key_); |
296 | | |
297 | 62.2k | uint8_t x25519_public_key[X25519_PUBLIC_VALUE_LEN]; |
298 | 62.2k | X25519_keypair(x25519_public_key, x25519_private_key_); |
299 | | |
300 | 62.2k | if (!CBB_add_bytes(out, mlkem_public_key, sizeof(mlkem_public_key)) || |
301 | 62.2k | !CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key))) { |
302 | 0 | return false; |
303 | 0 | } |
304 | | |
305 | 62.2k | return true; |
306 | 62.2k | } |
307 | | |
308 | | bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret, |
309 | 256 | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
310 | 256 | Array<uint8_t> secret; |
311 | 256 | if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES + |
312 | 256 | X25519_SHARED_KEY_LEN)) { |
313 | 0 | return false; |
314 | 0 | } |
315 | | |
316 | 256 | MLKEM768_public_key peer_mlkem_pub; |
317 | 256 | uint8_t x25519_public_key[X25519_PUBLIC_VALUE_LEN]; |
318 | 256 | X25519_keypair(x25519_public_key, x25519_private_key_); |
319 | 256 | CBS peer_key_cbs, peer_mlkem_cbs, peer_x25519_cbs; |
320 | 256 | CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size()); |
321 | 256 | if (!CBS_get_bytes(&peer_key_cbs, &peer_mlkem_cbs, |
322 | 256 | MLKEM768_PUBLIC_KEY_BYTES) || |
323 | 253 | !MLKEM768_parse_public_key(&peer_mlkem_pub, &peer_mlkem_cbs) || |
324 | 214 | !CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, |
325 | 214 | X25519_PUBLIC_VALUE_LEN) || |
326 | 185 | CBS_len(&peer_key_cbs) != 0 || |
327 | 182 | !X25519(secret.data() + MLKEM_SHARED_SECRET_BYTES, x25519_private_key_, |
328 | 182 | CBS_data(&peer_x25519_cbs))) { |
329 | 77 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
330 | 77 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
331 | 77 | return false; |
332 | 77 | } |
333 | | |
334 | 179 | uint8_t mlkem_ciphertext[MLKEM768_CIPHERTEXT_BYTES]; |
335 | 179 | MLKEM768_encap(mlkem_ciphertext, secret.data(), &peer_mlkem_pub); |
336 | | |
337 | 179 | if (!CBB_add_bytes(out_ciphertext, mlkem_ciphertext, |
338 | 179 | sizeof(mlkem_ciphertext)) || |
339 | 179 | !CBB_add_bytes(out_ciphertext, x25519_public_key, |
340 | 179 | sizeof(x25519_public_key))) { |
341 | 0 | return false; |
342 | 0 | } |
343 | | |
344 | 179 | *out_secret = std::move(secret); |
345 | 179 | return true; |
346 | 179 | } |
347 | | |
348 | | bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert, |
349 | 19 | Span<const uint8_t> ciphertext) override { |
350 | 19 | *out_alert = SSL_AD_INTERNAL_ERROR; |
351 | | |
352 | 19 | Array<uint8_t> secret; |
353 | 19 | if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES + |
354 | 19 | X25519_SHARED_KEY_LEN)) { |
355 | 0 | return false; |
356 | 0 | } |
357 | | |
358 | 19 | if (ciphertext.size() != |
359 | 19 | MLKEM768_CIPHERTEXT_BYTES + X25519_PUBLIC_VALUE_LEN || |
360 | 17 | !MLKEM768_decap(secret.data(), ciphertext.data(), |
361 | 17 | MLKEM768_CIPHERTEXT_BYTES, &mlkem_private_key_) || |
362 | 17 | !X25519(secret.data() + MLKEM_SHARED_SECRET_BYTES, x25519_private_key_, |
363 | 17 | ciphertext.data() + MLKEM768_CIPHERTEXT_BYTES)) { |
364 | 5 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
365 | 5 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
366 | 5 | return false; |
367 | 5 | } |
368 | | |
369 | 14 | *out_secret = std::move(secret); |
370 | 14 | return true; |
371 | 19 | } |
372 | | |
373 | | private: |
374 | | uint8_t x25519_private_key_[32]; |
375 | | MLKEM768_private_key mlkem_private_key_; |
376 | | }; |
377 | | |
378 | | // draft-ietf-tls-mlkem-04 |
379 | | class MLKEM1024KeyShare : public SSLKeyShare { |
380 | | public: |
381 | 7 | MLKEM1024KeyShare() = default; |
382 | | |
383 | 1 | uint16_t GroupID() const override { return SSL_GROUP_MLKEM1024; } |
384 | | |
385 | 7 | bool Generate(CBB *out_public_key) override { |
386 | 7 | uint8_t public_key[MLKEM1024_PUBLIC_KEY_BYTES]; |
387 | 7 | MLKEM1024_generate_key(public_key, /*optional_out_seed=*/nullptr, |
388 | 7 | &private_key_); |
389 | 7 | return CBB_add_bytes(out_public_key, public_key, sizeof(public_key)); |
390 | 7 | } |
391 | | |
392 | | bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret, |
393 | 0 | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
394 | 0 | MLKEM1024_public_key peer_pub; |
395 | 0 | CBS peer_pub_cbs; |
396 | 0 | CBS_init(&peer_pub_cbs, peer_key.data(), peer_key.size()); |
397 | 0 | if (!MLKEM1024_parse_public_key(&peer_pub, &peer_pub_cbs)) { |
398 | 0 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
399 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
400 | 0 | return false; |
401 | 0 | } |
402 | | |
403 | 0 | Array<uint8_t> secret; |
404 | 0 | if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES)) { |
405 | 0 | return false; |
406 | 0 | } |
407 | 0 | uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; |
408 | 0 | MLKEM1024_encap(ciphertext, secret.data(), &peer_pub); |
409 | 0 | if (!CBB_add_bytes(out_ciphertext, ciphertext, sizeof(ciphertext))) { |
410 | 0 | return false; |
411 | 0 | } |
412 | 0 | *out_secret = std::move(secret); |
413 | 0 | return true; |
414 | 0 | } |
415 | | |
416 | | bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert, |
417 | 0 | Span<const uint8_t> ciphertext) override { |
418 | 0 | Array<uint8_t> secret; |
419 | 0 | if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES)) { |
420 | 0 | *out_alert = SSL_AD_INTERNAL_ERROR; |
421 | 0 | return false; |
422 | 0 | } |
423 | | |
424 | 0 | if (!MLKEM1024_decap(secret.data(), ciphertext.data(), ciphertext.size(), |
425 | 0 | &private_key_)) { |
426 | 0 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
427 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
428 | 0 | return false; |
429 | 0 | } |
430 | 0 | *out_secret = std::move(secret); |
431 | 0 | return true; |
432 | 0 | } |
433 | | |
434 | | private: |
435 | | MLKEM1024_private_key private_key_; |
436 | | }; |
437 | | |
438 | | constexpr NamedGroup kNamedGroups[] = { |
439 | | {NID_X9_62_prime256v1, SSL_GROUP_SECP256R1, "P-256", "prime256v1"}, |
440 | | {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"}, |
441 | | {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"}, |
442 | | {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"}, |
443 | | {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00, |
444 | | "X25519Kyber768Draft00", ""}, |
445 | | {NID_X25519MLKEM768, SSL_GROUP_X25519_MLKEM768, "X25519MLKEM768", ""}, |
446 | | {NID_ML_KEM_1024, SSL_GROUP_MLKEM1024, "MLKEM1024", ""}, |
447 | | }; |
448 | | |
449 | | static_assert(std::size(kNamedGroups) == kNumNamedGroups, |
450 | | "kNamedGroups size mismatch"); |
451 | | |
452 | | } // namespace |
453 | | |
454 | 0 | Span<const NamedGroup> NamedGroups() { return kNamedGroups; } |
455 | | |
456 | 7.66k | Span<const uint16_t> DefaultSupportedGroupIds() { |
457 | 7.66k | static const uint16_t kDefaultSupportedGroupIds[] = { |
458 | 7.66k | SSL_GROUP_X25519, |
459 | 7.66k | SSL_GROUP_SECP256R1, |
460 | 7.66k | SSL_GROUP_SECP384R1, |
461 | 7.66k | }; |
462 | 7.66k | return Span(kDefaultSupportedGroupIds); |
463 | 7.66k | } |
464 | | |
465 | 182k | UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { |
466 | 182k | switch (group_id) { |
467 | 3.89k | case SSL_GROUP_SECP256R1: |
468 | 3.89k | return MakeUnique<ECKeyShare>(EC_group_p256(), SSL_GROUP_SECP256R1); |
469 | 27.5k | case SSL_GROUP_SECP384R1: |
470 | 27.5k | return MakeUnique<ECKeyShare>(EC_group_p384(), SSL_GROUP_SECP384R1); |
471 | 395 | case SSL_GROUP_SECP521R1: |
472 | 395 | return MakeUnique<ECKeyShare>(EC_group_p521(), SSL_GROUP_SECP521R1); |
473 | 87.8k | case SSL_GROUP_X25519: |
474 | 87.8k | return MakeUnique<X25519KeyShare>(); |
475 | 255 | case SSL_GROUP_X25519_KYBER768_DRAFT00: |
476 | 255 | return MakeUnique<X25519Kyber768KeyShare>(); |
477 | 62.5k | case SSL_GROUP_X25519_MLKEM768: |
478 | 62.5k | return MakeUnique<X25519MLKEM768KeyShare>(); |
479 | 7 | case SSL_GROUP_MLKEM1024: |
480 | 7 | return MakeUnique<MLKEM1024KeyShare>(); |
481 | 0 | default: |
482 | 0 | return nullptr; |
483 | 182k | } |
484 | 182k | } |
485 | | |
486 | 19.6k | bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { |
487 | 49.7k | for (const auto &group : kNamedGroups) { |
488 | 49.7k | if (group.nid == nid) { |
489 | 16.0k | *out_group_id = group.group_id; |
490 | 16.0k | return true; |
491 | 16.0k | } |
492 | 49.7k | } |
493 | 3.56k | return false; |
494 | 19.6k | } |
495 | | |
496 | | bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name, |
497 | 6.31k | size_t len) { |
498 | 31.3k | for (const auto &group : kNamedGroups) { |
499 | 31.3k | if (len == strlen(group.name) && // |
500 | 4.88k | !strncmp(group.name, name, len)) { |
501 | 2.25k | *out_group_id = group.group_id; |
502 | 2.25k | return true; |
503 | 2.25k | } |
504 | 29.0k | if (strlen(group.alias) > 0 && len == strlen(group.alias) && |
505 | 809 | !strncmp(group.alias, name, len)) { |
506 | 235 | *out_group_id = group.group_id; |
507 | 235 | return true; |
508 | 235 | } |
509 | 29.0k | } |
510 | 3.82k | return false; |
511 | 6.31k | } |
512 | | |
513 | 7.84k | int ssl_group_id_to_nid(uint16_t group_id) { |
514 | 27.8k | for (const auto &group : kNamedGroups) { |
515 | 27.8k | if (group.group_id == group_id) { |
516 | 6.11k | return group.nid; |
517 | 6.11k | } |
518 | 27.8k | } |
519 | 1.72k | return NID_undef; |
520 | 7.84k | } |
521 | | |
522 | | BSSL_NAMESPACE_END |
523 | | |
524 | | using namespace bssl; |
525 | | |
526 | 0 | const char *SSL_get_group_name(uint16_t group_id) { |
527 | 0 | for (const auto &group : kNamedGroups) { |
528 | 0 | if (group.group_id == group_id) { |
529 | 0 | return group.name; |
530 | 0 | } |
531 | 0 | } |
532 | 0 | return nullptr; |
533 | 0 | } |
534 | | |
535 | 0 | size_t SSL_get_all_group_names(const char **out, size_t max_out) { |
536 | 0 | return GetAllNames(out, max_out, Span<const char *const>(), &NamedGroup::name, |
537 | 0 | Span(kNamedGroups)); |
538 | 0 | } |