Coverage Report

Created: 2025-06-24 07:00

/src/boringssl/ssl/ssl_key_share.cc
Line
Count
Source (jump to first uncovered line)
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 <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/mlkem.h>
32
#include <openssl/nid.h>
33
#include <openssl/rand.h>
34
#include <openssl/span.h>
35
36
#include "../crypto/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
32.0k
      : group_(group), group_id_(group_id) {}
47
48
18
  uint16_t GroupID() const override { return group_id_; }
49
50
31.5k
  bool Generate(CBB *out) override {
51
31.5k
    assert(!private_key_);
52
    // Generate a private key.
53
31.5k
    private_key_.reset(BN_new());
54
31.5k
    if (!private_key_ ||
55
31.5k
        !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.5k
    UniquePtr<EC_POINT> public_key(EC_POINT_new(group_));
61
31.5k
    if (!public_key ||
62
31.5k
        !EC_POINT_mul(group_, public_key.get(), private_key_.get(), nullptr,
63
31.5k
                      nullptr, /*ctx=*/nullptr) ||
64
31.5k
        !EC_POINT_point2cbb(out, group_, public_key.get(),
65
31.5k
                            POINT_CONVERSION_UNCOMPRESSED, /*ctx=*/nullptr)) {
66
0
      return false;
67
0
    }
68
69
31.5k
    return true;
70
31.5k
  }
71
72
  bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
73
30.0k
             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
30.0k
    *out_alert = SSL_AD_INTERNAL_ERROR;
77
30.0k
    return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
78
30.0k
  }
79
80
  bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
81
30.7k
             Span<const uint8_t> ciphertext) override {
82
30.7k
    assert(group_);
83
30.7k
    assert(private_key_);
84
30.7k
    *out_alert = SSL_AD_INTERNAL_ERROR;
85
86
30.7k
    UniquePtr<EC_POINT> peer_point(EC_POINT_new(group_));
87
30.7k
    UniquePtr<EC_POINT> result(EC_POINT_new(group_));
88
30.7k
    UniquePtr<BIGNUM> x(BN_new());
89
30.7k
    if (!peer_point || !result || !x) {
90
0
      return false;
91
0
    }
92
93
30.7k
    if (ciphertext.empty() || ciphertext[0] != POINT_CONVERSION_UNCOMPRESSED ||
94
30.7k
        !EC_POINT_oct2point(group_, peer_point.get(), ciphertext.data(),
95
30.6k
                            ciphertext.size(), /*ctx=*/nullptr)) {
96
321
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
97
321
      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
98
321
      return false;
99
321
    }
100
101
    // Compute the x-coordinate of |peer_key| * |private_key_|.
102
30.4k
    if (!EC_POINT_mul(group_, result.get(), nullptr, peer_point.get(),
103
30.4k
                      private_key_.get(), /*ctx=*/nullptr) ||
104
30.4k
        !EC_POINT_get_affine_coordinates_GFp(group_, result.get(), x.get(),
105
30.4k
                                             nullptr, /*ctx=*/nullptr)) {
106
4
      return false;
107
4
    }
108
109
    // Encode the x-coordinate left-padded with zeros.
110
30.4k
    Array<uint8_t> secret;
111
30.4k
    if (!secret.InitForOverwrite((EC_GROUP_get_degree(group_) + 7) / 8) ||
112
30.4k
        !BN_bn2bin_padded(secret.data(), secret.size(), x.get())) {
113
0
      return false;
114
0
    }
115
116
30.4k
    *out_secret = std::move(secret);
117
30.4k
    return true;
118
30.4k
  }
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
88.2k
  X25519KeyShare() {}
143
144
2.38k
  uint16_t GroupID() const override { return SSL_GROUP_X25519; }
145
146
88.1k
  bool Generate(CBB *out) override {
147
88.1k
    uint8_t public_key[32];
148
88.1k
    X25519_keypair(public_key, private_key_);
149
88.1k
    return !!CBB_add_bytes(out, public_key, sizeof(public_key));
150
88.1k
  }
151
152
  bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
153
21.1k
             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.1k
    *out_alert = SSL_AD_INTERNAL_ERROR;
157
21.1k
    return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
158
21.1k
  }
159
160
  bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
161
26.0k
             Span<const uint8_t> ciphertext) override {
162
26.0k
    *out_alert = SSL_AD_INTERNAL_ERROR;
163
164
26.0k
    Array<uint8_t> secret;
165
26.0k
    if (!secret.InitForOverwrite(32)) {
166
0
      return false;
167
0
    }
168
169
26.0k
    if (ciphertext.size() != 32 ||  //
170
26.0k
        !X25519(secret.data(), private_key_, ciphertext.data())) {
171
33
      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
172
33
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
173
33
      return false;
174
33
    }
175
176
26.0k
    *out_secret = std::move(secret);
177
26.0k
    return true;
178
26.0k
  }
179
180
0
  bool SerializePrivateKey(CBB *out) override {
181
0
    return CBB_add_bytes(out, private_key_, sizeof(private_key_));
182
0
  }
183
184
78
  bool DeserializePrivateKey(CBS *in) override {
185
78
    if (CBS_len(in) != sizeof(private_key_) ||
186
78
        !CBS_copy_bytes(in, private_key_, sizeof(private_key_))) {
187
17
      return false;
188
17
    }
189
61
    return true;
190
78
  }
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
215
  X25519Kyber768KeyShare() {}
200
201
1
  uint16_t GroupID() const override {
202
1
    return SSL_GROUP_X25519_KYBER768_DRAFT00;
203
1
  }
204
205
66
  bool Generate(CBB *out) override {
206
66
    uint8_t x25519_public_key[32];
207
66
    X25519_keypair(x25519_public_key, x25519_private_key_);
208
209
66
    uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES];
210
66
    KYBER_generate_key(kyber_public_key, &kyber_private_key_);
211
212
66
    if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
213
66
        !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) {
214
0
      return false;
215
0
    }
216
217
66
    return true;
218
66
  }
219
220
  bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
221
149
             uint8_t *out_alert, Span<const uint8_t> peer_key) override {
222
149
    Array<uint8_t> secret;
223
149
    if (!secret.InitForOverwrite(32 + KYBER_SHARED_SECRET_BYTES)) {
224
0
      return false;
225
0
    }
226
227
149
    uint8_t x25519_public_key[32];
228
149
    X25519_keypair(x25519_public_key, x25519_private_key_);
229
149
    KYBER_public_key peer_kyber_pub;
230
149
    CBS peer_key_cbs, peer_x25519_cbs, peer_kyber_cbs;
231
149
    CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size());
232
149
    if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) ||
233
149
        !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs,
234
147
                       KYBER_PUBLIC_KEY_BYTES) ||
235
149
        CBS_len(&peer_key_cbs) != 0 ||
236
149
        !X25519(secret.data(), x25519_private_key_,
237
141
                CBS_data(&peer_x25519_cbs)) ||
238
149
        !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) {
239
54
      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
240
54
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
241
54
      return false;
242
54
    }
243
244
95
    uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES];
245
95
    KYBER_encap(kyber_ciphertext, secret.data() + 32, &peer_kyber_pub);
246
247
95
    if (!CBB_add_bytes(out_ciphertext, x25519_public_key,
248
95
                       sizeof(x25519_public_key)) ||
249
95
        !CBB_add_bytes(out_ciphertext, kyber_ciphertext,
250
95
                       sizeof(kyber_ciphertext))) {
251
0
      return false;
252
0
    }
253
254
95
    *out_secret = std::move(secret);
255
95
    return true;
256
95
  }
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
63.3k
  X25519MLKEM768KeyShare() {}
289
290
2.41k
  uint16_t GroupID() const override { return SSL_GROUP_X25519_MLKEM768; }
291
292
63.0k
  bool Generate(CBB *out) override {
293
63.0k
    uint8_t mlkem_public_key[MLKEM768_PUBLIC_KEY_BYTES];
294
63.0k
    MLKEM768_generate_key(mlkem_public_key, /*optional_out_seed=*/nullptr,
295
63.0k
                          &mlkem_private_key_);
296
297
63.0k
    uint8_t x25519_public_key[X25519_PUBLIC_VALUE_LEN];
298
63.0k
    X25519_keypair(x25519_public_key, x25519_private_key_);
299
300
63.0k
    if (!CBB_add_bytes(out, mlkem_public_key, sizeof(mlkem_public_key)) ||
301
63.0k
        !CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key))) {
302
0
      return false;
303
0
    }
304
305
63.0k
    return true;
306
63.0k
  }
307
308
  bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
309
295
             uint8_t *out_alert, Span<const uint8_t> peer_key) override {
310
295
    Array<uint8_t> secret;
311
295
    if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES +
312
295
                                 X25519_SHARED_KEY_LEN)) {
313
0
      return false;
314
0
    }
315
316
295
    MLKEM768_public_key peer_mlkem_pub;
317
295
    uint8_t x25519_public_key[X25519_PUBLIC_VALUE_LEN];
318
295
    X25519_keypair(x25519_public_key, x25519_private_key_);
319
295
    CBS peer_key_cbs, peer_mlkem_cbs, peer_x25519_cbs;
320
295
    CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size());
321
295
    if (!CBS_get_bytes(&peer_key_cbs, &peer_mlkem_cbs,
322
295
                       MLKEM768_PUBLIC_KEY_BYTES) ||
323
295
        !MLKEM768_parse_public_key(&peer_mlkem_pub, &peer_mlkem_cbs) ||
324
295
        !CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs,
325
245
                       X25519_PUBLIC_VALUE_LEN) ||
326
295
        CBS_len(&peer_key_cbs) != 0 ||
327
295
        !X25519(secret.data() + MLKEM_SHARED_SECRET_BYTES, x25519_private_key_,
328
212
                CBS_data(&peer_x25519_cbs))) {
329
87
      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
330
87
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
331
87
      return false;
332
87
    }
333
334
208
    uint8_t mlkem_ciphertext[MLKEM768_CIPHERTEXT_BYTES];
335
208
    MLKEM768_encap(mlkem_ciphertext, secret.data(), &peer_mlkem_pub);
336
337
208
    if (!CBB_add_bytes(out_ciphertext, mlkem_ciphertext,
338
208
                       sizeof(mlkem_ciphertext)) ||
339
208
        !CBB_add_bytes(out_ciphertext, x25519_public_key,
340
208
                       sizeof(x25519_public_key))) {
341
0
      return false;
342
0
    }
343
344
208
    *out_secret = std::move(secret);
345
208
    return true;
346
208
  }
347
348
  bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
349
22
             Span<const uint8_t> ciphertext) override {
350
22
    *out_alert = SSL_AD_INTERNAL_ERROR;
351
352
22
    Array<uint8_t> secret;
353
22
    if (!secret.InitForOverwrite(MLKEM_SHARED_SECRET_BYTES +
354
22
                                 X25519_SHARED_KEY_LEN)) {
355
0
      return false;
356
0
    }
357
358
22
    if (ciphertext.size() !=
359
22
            MLKEM768_CIPHERTEXT_BYTES + X25519_PUBLIC_VALUE_LEN ||
360
22
        !MLKEM768_decap(secret.data(), ciphertext.data(),
361
21
                        MLKEM768_CIPHERTEXT_BYTES, &mlkem_private_key_) ||
362
22
        !X25519(secret.data() + MLKEM_SHARED_SECRET_BYTES, x25519_private_key_,
363
21
                ciphertext.data() + MLKEM768_CIPHERTEXT_BYTES)) {
364
7
      *out_alert = SSL_AD_ILLEGAL_PARAMETER;
365
7
      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
366
7
      return false;
367
7
    }
368
369
15
    *out_secret = std::move(secret);
370
15
    return true;
371
22
  }
372
373
 private:
374
  uint8_t x25519_private_key_[32];
375
  MLKEM768_private_key mlkem_private_key_;
376
};
377
378
constexpr NamedGroup kNamedGroups[] = {
379
    {NID_X9_62_prime256v1, SSL_GROUP_SECP256R1, "P-256", "prime256v1"},
380
    {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"},
381
    {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"},
382
    {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"},
383
    {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00,
384
     "X25519Kyber768Draft00", ""},
385
    {NID_X25519MLKEM768, SSL_GROUP_X25519_MLKEM768, "X25519MLKEM768", ""},
386
};
387
388
}  // namespace
389
390
0
Span<const NamedGroup> NamedGroups() { return kNamedGroups; }
391
392
183k
UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
393
183k
  switch (group_id) {
394
3.67k
    case SSL_GROUP_SECP256R1:
395
3.67k
      return MakeUnique<ECKeyShare>(EC_group_p256(), SSL_GROUP_SECP256R1);
396
28.0k
    case SSL_GROUP_SECP384R1:
397
28.0k
      return MakeUnique<ECKeyShare>(EC_group_p384(), SSL_GROUP_SECP384R1);
398
386
    case SSL_GROUP_SECP521R1:
399
386
      return MakeUnique<ECKeyShare>(EC_group_p521(), SSL_GROUP_SECP521R1);
400
88.2k
    case SSL_GROUP_X25519:
401
88.2k
      return MakeUnique<X25519KeyShare>();
402
215
    case SSL_GROUP_X25519_KYBER768_DRAFT00:
403
215
      return MakeUnique<X25519Kyber768KeyShare>();
404
63.3k
    case SSL_GROUP_X25519_MLKEM768:
405
63.3k
      return MakeUnique<X25519MLKEM768KeyShare>();
406
0
    default:
407
0
      return nullptr;
408
183k
  }
409
183k
}
410
411
20.2k
bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
412
45.3k
  for (const auto &group : kNamedGroups) {
413
45.3k
    if (group.nid == nid) {
414
15.4k
      *out_group_id = group.group_id;
415
15.4k
      return true;
416
15.4k
    }
417
45.3k
  }
418
4.81k
  return false;
419
20.2k
}
420
421
bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name,
422
6.55k
                          size_t len) {
423
34.4k
  for (const auto &group : kNamedGroups) {
424
34.4k
    if (len == strlen(group.name) &&  //
425
34.4k
        !strncmp(group.name, name, len)) {
426
1.06k
      *out_group_id = group.group_id;
427
1.06k
      return true;
428
1.06k
    }
429
33.3k
    if (strlen(group.alias) > 0 && len == strlen(group.alias) &&
430
33.3k
        !strncmp(group.alias, name, len)) {
431
296
      *out_group_id = group.group_id;
432
296
      return true;
433
296
    }
434
33.3k
  }
435
5.20k
  return false;
436
6.55k
}
437
438
3.04k
int ssl_group_id_to_nid(uint16_t group_id) {
439
14.6k
  for (const auto &group : kNamedGroups) {
440
14.6k
    if (group.group_id == group_id) {
441
942
      return group.nid;
442
942
    }
443
14.6k
  }
444
2.10k
  return NID_undef;
445
3.04k
}
446
447
BSSL_NAMESPACE_END
448
449
using namespace bssl;
450
451
0
const char *SSL_get_group_name(uint16_t group_id) {
452
0
  for (const auto &group : kNamedGroups) {
453
0
    if (group.group_id == group_id) {
454
0
      return group.name;
455
0
    }
456
0
  }
457
0
  return nullptr;
458
0
}
459
460
0
size_t SSL_get_all_group_names(const char **out, size_t max_out) {
461
0
  return GetAllNames(out, max_out, Span<const char *>(), &NamedGroup::name,
462
0
                     Span(kNamedGroups));
463
0
}