Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/ext/key_share.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
/* This file contains the code the Key Share TLS 1.3 extension.
24
 */
25
26
#include "gnutls_int.h"
27
#include "errors.h"
28
#include "num.h"
29
#include "ext/supported_groups.h"
30
#include "state.h"
31
#include "num.h"
32
#include "algorithms.h"
33
#include "auth/psk.h"
34
#include "auth/cert.h"
35
#include "handshake.h"
36
#include "../ecc.h"
37
#include "../algorithms.h"
38
#include "pk.h"
39
40
static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
41
         size_t data_size);
42
static int key_share_send_params(gnutls_session_t session,
43
         gnutls_buffer_st *extdata);
44
45
const hello_ext_entry_st ext_mod_key_share = {
46
  .name = "Key Share",
47
  .tls_id = 51,
48
  .gid = GNUTLS_EXTENSION_KEY_SHARE,
49
  .client_parse_point = _GNUTLS_EXT_TLS_POST_CS,
50
  .server_parse_point = _GNUTLS_EXT_TLS_POST_CS,
51
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
52
        GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO | GNUTLS_EXT_FLAG_HRR,
53
  .recv_func = key_share_recv_params,
54
  .send_func = key_share_send_params,
55
  .pack_func = NULL,
56
  .unpack_func = NULL,
57
  .deinit_func = NULL,
58
  .cannot_be_overriden = 1
59
};
60
61
static int client_gen_key_share_single(gnutls_session_t session,
62
               const gnutls_group_entry_st *group,
63
               gnutls_buffer_st *extdata)
64
0
{
65
0
  gnutls_datum_t tmp = { NULL, 0 };
66
0
  int ret;
67
68
0
  switch (group->pk) {
69
0
  case GNUTLS_PK_EC:
70
0
    gnutls_pk_params_release(&session->key.kshare.ecdh_params);
71
0
    gnutls_pk_params_init(&session->key.kshare.ecdh_params);
72
73
0
    ret = _gnutls_pk_generate_keys(group->pk, group->curve,
74
0
                 &session->key.kshare.ecdh_params,
75
0
                 1);
76
0
    if (ret < 0) {
77
0
      gnutls_assert();
78
0
      goto cleanup;
79
0
    }
80
81
0
    ret = _gnutls_ecc_ansi_x962_export(
82
0
      group->curve,
83
0
      session->key.kshare.ecdh_params.params[ECC_X],
84
0
      session->key.kshare.ecdh_params.params[ECC_Y], &tmp);
85
0
    if (ret < 0)
86
0
      return gnutls_assert_val(ret);
87
88
0
    ret = gnutls_buffer_append_data(extdata, tmp.data, tmp.size);
89
0
    if (ret < 0) {
90
0
      gnutls_assert();
91
0
      goto cleanup;
92
0
    }
93
94
0
    session->key.kshare.ecdh_params.algo = group->pk;
95
0
    session->key.kshare.ecdh_params.curve = group->curve;
96
97
0
    ret = 0;
98
0
    break;
99
100
0
  case GNUTLS_PK_ECDH_X25519:
101
0
  case GNUTLS_PK_ECDH_X448:
102
0
    gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
103
0
    gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
104
105
0
    ret = _gnutls_pk_generate_keys(
106
0
      group->pk, group->curve,
107
0
      &session->key.kshare.ecdhx_params, 1);
108
0
    if (ret < 0) {
109
0
      gnutls_assert();
110
0
      goto cleanup;
111
0
    }
112
113
0
    ret = gnutls_buffer_append_data(
114
0
      extdata, session->key.kshare.ecdhx_params.raw_pub.data,
115
0
      session->key.kshare.ecdhx_params.raw_pub.size);
116
0
    if (ret < 0) {
117
0
      gnutls_assert();
118
0
      goto cleanup;
119
0
    }
120
121
0
    session->key.kshare.ecdhx_params.algo = group->pk;
122
0
    session->key.kshare.ecdhx_params.curve = group->curve;
123
124
0
    ret = 0;
125
0
    break;
126
127
0
  case GNUTLS_PK_DH:
128
    /* we need to initialize the group parameters first */
129
0
    gnutls_pk_params_release(&session->key.kshare.dh_params);
130
0
    gnutls_pk_params_init(&session->key.kshare.dh_params);
131
132
0
    ret = _gnutls_mpi_init_scan_nz(
133
0
      &session->key.kshare.dh_params.params[DH_G],
134
0
      group->generator->data, group->generator->size);
135
0
    if (ret < 0) {
136
0
      ret = gnutls_assert_val(
137
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
138
0
      goto cleanup;
139
0
    }
140
141
0
    ret = _gnutls_mpi_init_scan_nz(
142
0
      &session->key.kshare.dh_params.params[DH_P],
143
0
      group->prime->data, group->prime->size);
144
0
    if (ret < 0) {
145
0
      ret = gnutls_assert_val(
146
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
147
0
      goto cleanup;
148
0
    }
149
150
0
    ret = _gnutls_mpi_init_scan_nz(
151
0
      &session->key.kshare.dh_params.params[DH_Q],
152
0
      group->q->data, group->q->size);
153
0
    if (ret < 0) {
154
0
      ret = gnutls_assert_val(
155
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
156
0
      goto cleanup;
157
0
    }
158
159
0
    session->key.kshare.dh_params.algo = group->pk;
160
0
    session->key.kshare.dh_params.dh_group =
161
0
      group->id; /* no curve in FFDH, we write the group */
162
0
    session->key.kshare.dh_params.qbits = *group->q_bits;
163
0
    session->key.kshare.dh_params.params_nr = 3;
164
165
0
    ret = _gnutls_pk_generate_keys(
166
0
      group->pk, 0, &session->key.kshare.dh_params, 1);
167
0
    if (ret < 0) {
168
0
      ret = gnutls_assert_val(ret);
169
0
      goto cleanup;
170
0
    }
171
172
0
    ret = _gnutls_buffer_append_fixed_mpi(
173
0
      extdata, session->key.kshare.dh_params.params[DH_Y],
174
0
      group->prime->size);
175
0
    if (ret < 0) {
176
0
      ret = gnutls_assert_val(ret);
177
0
      goto cleanup;
178
0
    }
179
180
0
    ret = 0;
181
0
    break;
182
183
0
  case GNUTLS_PK_MLKEM768:
184
0
  case GNUTLS_PK_MLKEM1024:
185
0
  case GNUTLS_PK_EXP_KYBER768:
186
0
    gnutls_pk_params_release(&session->key.kshare.kem_params);
187
0
    gnutls_pk_params_init(&session->key.kshare.kem_params);
188
189
0
    ret = _gnutls_pk_generate_keys(
190
0
      group->pk, 0, &session->key.kshare.kem_params, 1);
191
0
    if (ret < 0) {
192
0
      gnutls_assert();
193
0
      goto cleanup;
194
0
    }
195
196
0
    ret = gnutls_buffer_append_data(
197
0
      extdata, session->key.kshare.kem_params.raw_pub.data,
198
0
      session->key.kshare.kem_params.raw_pub.size);
199
0
    if (ret < 0) {
200
0
      gnutls_assert();
201
0
      goto cleanup;
202
0
    }
203
204
0
    ret = 0;
205
0
    break;
206
207
0
  default:
208
0
    _gnutls_debug_log("Cannot send key share for group %s!\n",
209
0
          group->name);
210
0
    return GNUTLS_E_INT_RET_0;
211
0
  }
212
213
0
cleanup:
214
0
  gnutls_free(tmp.data);
215
0
  return ret;
216
0
}
217
218
/*
219
 * Generates key exchange parameters, and stores them in
220
 * session->key.kshare_*_params.
221
 *
222
 * struct {
223
 *     NamedGroup group;
224
 *     opaque key_exchange<1..2^16-1>;
225
 * } KeyShareEntry;
226
 *
227
 */
228
static int client_gen_key_share(gnutls_session_t session,
229
        const gnutls_group_entry_st *group,
230
        gnutls_buffer_st *extdata)
231
0
{
232
0
  unsigned int length_pos;
233
0
  const gnutls_group_entry_st *groups[MAX_HYBRID_GROUPS + 1] = {
234
0
    NULL,
235
0
  };
236
0
  int ret;
237
238
0
  _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session,
239
0
            group->name);
240
241
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
242
0
  if (ret < 0)
243
0
    return gnutls_assert_val(ret);
244
245
  /* save the position of length field */
246
0
  length_pos = extdata->length;
247
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
248
0
  if (ret < 0)
249
0
    return gnutls_assert_val(ret);
250
251
0
  ret = _gnutls_group_expand(group, groups);
252
0
  if (ret < 0)
253
0
    return gnutls_assert_val(ret);
254
255
0
  for (size_t i = 0; groups[i]; i++) {
256
0
    ret = client_gen_key_share_single(session, groups[i], extdata);
257
0
    if (ret < 0)
258
0
      return gnutls_assert_val(ret);
259
0
  }
260
261
  /* copy actual length */
262
0
  _gnutls_write_uint16(extdata->length - length_pos - 2,
263
0
           &extdata->data[length_pos]);
264
265
0
  return 0;
266
0
}
267
268
static int server_gen_key_share_single(gnutls_session_t session,
269
               const gnutls_group_entry_st *group,
270
               gnutls_buffer_st *extdata)
271
0
{
272
0
  gnutls_datum_t tmp = { NULL, 0 };
273
0
  int ret;
274
275
0
  switch (group->pk) {
276
0
  case GNUTLS_PK_EC:
277
0
    ret = _gnutls_ecc_ansi_x962_export(
278
0
      group->curve,
279
0
      session->key.kshare.ecdh_params.params[ECC_X],
280
0
      session->key.kshare.ecdh_params.params[ECC_Y], &tmp);
281
0
    if (ret < 0) {
282
0
      gnutls_assert();
283
0
      goto cleanup;
284
0
    }
285
286
0
    ret = gnutls_buffer_append_data(extdata, tmp.data, tmp.size);
287
0
    if (ret < 0) {
288
0
      gnutls_assert();
289
0
      goto cleanup;
290
0
    }
291
292
0
    ret = 0;
293
0
    break;
294
295
0
  case GNUTLS_PK_ECDH_X25519:
296
0
  case GNUTLS_PK_ECDH_X448:
297
0
    ret = gnutls_buffer_append_data(
298
0
      extdata, session->key.kshare.ecdhx_params.raw_pub.data,
299
0
      session->key.kshare.ecdhx_params.raw_pub.size);
300
0
    if (ret < 0) {
301
0
      gnutls_assert();
302
0
      goto cleanup;
303
0
    }
304
305
0
    ret = 0;
306
0
    break;
307
308
0
  case GNUTLS_PK_DH:
309
0
    ret = _gnutls_buffer_append_fixed_mpi(
310
0
      extdata, session->key.kshare.dh_params.params[DH_Y],
311
0
      group->prime->size);
312
0
    if (ret < 0) {
313
0
      gnutls_assert();
314
0
      goto cleanup;
315
0
    }
316
317
0
    ret = 0;
318
0
    break;
319
320
0
  case GNUTLS_PK_MLKEM768:
321
0
  case GNUTLS_PK_MLKEM1024:
322
0
  case GNUTLS_PK_EXP_KYBER768:
323
0
    ret = gnutls_buffer_append_data(
324
0
      extdata, session->key.kshare.kem_params.raw_pub.data,
325
0
      session->key.kshare.kem_params.raw_pub.size);
326
0
    if (ret < 0) {
327
0
      gnutls_assert();
328
0
      goto cleanup;
329
0
    }
330
331
0
    ret = 0;
332
0
    break;
333
334
0
  default:
335
0
    _gnutls_debug_log("Cannot send key share for group %s!\n",
336
0
          group->name);
337
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
338
0
  }
339
340
0
cleanup:
341
0
  gnutls_free(tmp.data);
342
0
  return ret;
343
0
}
344
345
/*
346
 * Sends server key exchange parameters
347
 *
348
 */
349
static int server_gen_key_share(gnutls_session_t session,
350
        const gnutls_group_entry_st *group,
351
        gnutls_buffer_st *extdata)
352
0
{
353
0
  unsigned int length_pos;
354
0
  const gnutls_group_entry_st *groups[MAX_HYBRID_GROUPS + 1] = {
355
0
    NULL,
356
0
  };
357
0
  int ret;
358
359
0
  _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session,
360
0
            group->name);
361
362
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
363
0
  if (ret < 0)
364
0
    return gnutls_assert_val(ret);
365
366
  /* save the position of length field */
367
0
  length_pos = extdata->length;
368
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
369
0
  if (ret < 0)
370
0
    return gnutls_assert_val(ret);
371
372
0
  ret = _gnutls_group_expand(group, groups);
373
0
  if (ret < 0)
374
0
    return gnutls_assert_val(ret);
375
376
0
  for (size_t i = 0; groups[i]; i++) {
377
0
    ret = server_gen_key_share_single(session, groups[i], extdata);
378
0
    if (ret < 0)
379
0
      return gnutls_assert_val(ret);
380
0
  }
381
382
  /* copy actual length */
383
0
  _gnutls_write_uint16(extdata->length - length_pos - 2,
384
0
           &extdata->data[length_pos]);
385
386
0
  return 0;
387
0
}
388
389
static int append_key_datum(gnutls_datum_t *dst, const gnutls_datum_t *src)
390
0
{
391
0
  dst->data = gnutls_realloc_fast(dst->data, dst->size + src->size);
392
0
  if (!dst->data)
393
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
394
395
0
  memcpy(dst->data + dst->size, src->data, src->size);
396
0
  dst->size += src->size;
397
0
  return 0;
398
0
}
399
400
static int server_use_key_share_single(gnutls_session_t session,
401
               const gnutls_group_entry_st *group,
402
               gnutls_buffer_st *buffer)
403
0
{
404
0
  gnutls_datum_t key = { NULL, 0 };
405
0
  gnutls_datum_t data;
406
0
  gnutls_pk_params_st pub;
407
0
  const gnutls_ecc_curve_entry_st *curve;
408
0
  int ret;
409
410
0
  switch (group->pk) {
411
0
  case GNUTLS_PK_EC:
412
0
    gnutls_pk_params_release(&session->key.kshare.ecdh_params);
413
0
    gnutls_pk_params_init(&session->key.kshare.ecdh_params);
414
415
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
416
417
0
    gnutls_pk_params_init(&pub);
418
419
0
    if (curve->size * 2 + 1 > buffer->length)
420
0
      return gnutls_assert_val(
421
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
422
0
    _gnutls_buffer_pop_datum(buffer, &data, curve->size * 2 + 1);
423
424
    /* generate our key */
425
0
    ret = _gnutls_pk_generate_keys(curve->pk, curve->id,
426
0
                 &session->key.kshare.ecdh_params,
427
0
                 1);
428
0
    if (ret < 0)
429
0
      return gnutls_assert_val(ret);
430
431
    /* read the public key */
432
0
    ret = _gnutls_ecc_ansi_x962_import(data.data, data.size,
433
0
               &pub.params[ECC_X],
434
0
               &pub.params[ECC_Y]);
435
0
    if (ret < 0)
436
0
      return gnutls_assert_val(
437
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
438
439
0
    pub.algo = group->pk;
440
0
    pub.curve = curve->id;
441
0
    pub.params_nr = 2;
442
443
    /* generate shared */
444
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &key,
445
0
                &session->key.kshare.ecdh_params,
446
0
                &pub);
447
0
    gnutls_pk_params_release(&pub);
448
0
    if (ret < 0)
449
0
      return gnutls_assert_val(ret);
450
451
0
    ret = append_key_datum(&session->key.key, &key);
452
0
    _gnutls_free_datum(&key);
453
0
    if (ret < 0)
454
0
      return gnutls_assert_val(ret);
455
456
0
    return 0;
457
458
0
  case GNUTLS_PK_ECDH_X25519:
459
0
  case GNUTLS_PK_ECDH_X448:
460
0
    gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
461
0
    gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
462
463
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
464
465
0
    if (curve->size > buffer->length)
466
0
      return gnutls_assert_val(
467
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
468
0
    _gnutls_buffer_pop_datum(buffer, &data, curve->size);
469
470
    /* generate our key */
471
0
    ret = _gnutls_pk_generate_keys(
472
0
      curve->pk, curve->id, &session->key.kshare.ecdhx_params,
473
0
      1);
474
0
    if (ret < 0)
475
0
      return gnutls_assert_val(ret);
476
477
    /* read the public key and generate shared */
478
0
    gnutls_pk_params_init(&pub);
479
480
0
    pub.algo = group->pk;
481
0
    pub.curve = curve->id;
482
483
0
    pub.raw_pub.data = data.data;
484
0
    pub.raw_pub.size = data.size;
485
486
    /* We don't mask the MSB in the final byte as required
487
     * by RFC7748. This will be done internally by nettle 3.3 or later.
488
     */
489
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &key,
490
0
                &session->key.kshare.ecdhx_params,
491
0
                &pub);
492
0
    if (ret < 0)
493
0
      return gnutls_assert_val(ret);
494
495
0
    ret = append_key_datum(&session->key.key, &key);
496
0
    _gnutls_free_datum(&key);
497
0
    if (ret < 0)
498
0
      return gnutls_assert_val(ret);
499
500
0
    return 0;
501
502
0
  case GNUTLS_PK_DH:
503
    /* we need to initialize the group parameters first */
504
0
    gnutls_pk_params_release(&session->key.kshare.dh_params);
505
0
    gnutls_pk_params_init(&session->key.kshare.dh_params);
506
507
0
    if (group->prime->size > buffer->length)
508
0
      return gnutls_assert_val(
509
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
510
0
    _gnutls_buffer_pop_datum(buffer, &data, group->prime->size);
511
512
    /* set group params */
513
0
    ret = _gnutls_mpi_init_scan_nz(
514
0
      &session->key.kshare.dh_params.params[DH_G],
515
0
      group->generator->data, group->generator->size);
516
0
    if (ret < 0)
517
0
      return gnutls_assert_val(
518
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
519
520
0
    ret = _gnutls_mpi_init_scan_nz(
521
0
      &session->key.kshare.dh_params.params[DH_P],
522
0
      group->prime->data, group->prime->size);
523
0
    if (ret < 0)
524
0
      return gnutls_assert_val(
525
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
526
527
0
    ret = _gnutls_mpi_init_scan_nz(
528
0
      &session->key.kshare.dh_params.params[DH_Q],
529
0
      group->q->data, group->q->size);
530
0
    if (ret < 0)
531
0
      return gnutls_assert_val(
532
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
533
534
0
    session->key.kshare.dh_params.algo = GNUTLS_PK_DH;
535
0
    session->key.kshare.dh_params.qbits = *group->q_bits;
536
0
    session->key.kshare.dh_params.params_nr = 3;
537
538
    /* generate our keys */
539
0
    ret = _gnutls_pk_generate_keys(
540
0
      group->pk, 0, &session->key.kshare.dh_params, 1);
541
0
    if (ret < 0)
542
0
      return gnutls_assert_val(ret);
543
544
    /* read the public key and generate shared */
545
0
    gnutls_pk_params_init(&pub);
546
547
0
    ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y], data.data,
548
0
                 data.size);
549
0
    if (ret < 0)
550
0
      return gnutls_assert_val(
551
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
552
553
0
    pub.algo = group->pk;
554
555
    /* generate shared key */
556
0
    ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key,
557
0
                &session->key.kshare.dh_params,
558
0
                &pub);
559
0
    _gnutls_mpi_release(&pub.params[DH_Y]);
560
0
    if (ret < 0)
561
0
      return gnutls_assert_val(ret);
562
563
0
    return 0;
564
565
0
  case GNUTLS_PK_EXP_KYBER768:
566
0
  case GNUTLS_PK_MLKEM768:
567
0
  case GNUTLS_PK_MLKEM1024:
568
0
    gnutls_pk_params_release(&session->key.kshare.kem_params);
569
0
    gnutls_pk_params_init(&session->key.kshare.kem_params);
570
571
    /* generate our key */
572
0
    ret = _gnutls_pk_generate_keys(
573
0
      group->pk, 0, &session->key.kshare.kem_params, 1);
574
0
    if (ret < 0)
575
0
      return gnutls_assert_val(ret);
576
577
    /* server's public key is unused, but the raw_pub field
578
    * is used to store ciphertext */
579
0
    gnutls_free(session->key.kshare.kem_params.raw_pub.data);
580
581
0
    if (group->pubkey_size > buffer->length)
582
0
      return gnutls_assert_val(
583
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
584
0
    _gnutls_buffer_pop_datum(buffer, &data, group->pubkey_size);
585
586
0
    ret = _gnutls_pk_encaps(group->pk,
587
0
          &session->key.kshare.kem_params.raw_pub,
588
0
          &key, &data);
589
0
    if (ret < 0)
590
0
      return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
591
592
0
    ret = append_key_datum(&session->key.key, &key);
593
0
    _gnutls_free_datum(&key);
594
0
    if (ret < 0)
595
0
      return gnutls_assert_val(ret);
596
597
0
    return 0;
598
599
0
  default:
600
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
601
0
  }
602
0
}
603
604
/* Generates shared key and stores it in session->key.key
605
 */
606
static int server_use_key_share(gnutls_session_t session,
607
        const gnutls_group_entry_st *group,
608
        const uint8_t *data, size_t data_size)
609
0
{
610
0
  gnutls_buffer_st buffer;
611
0
  const gnutls_group_entry_st *groups[MAX_HYBRID_GROUPS + 1] = {
612
0
    NULL,
613
0
  };
614
0
  int ret;
615
616
0
  _gnutls_ro_buffer_init(&buffer, data, data_size);
617
618
0
  ret = _gnutls_group_expand(group, groups);
619
0
  if (ret < 0)
620
0
    return gnutls_assert_val(ret);
621
622
0
  for (size_t i = 0; groups[i]; i++) {
623
0
    ret = server_use_key_share_single(session, groups[i], &buffer);
624
0
    if (ret < 0)
625
0
      return gnutls_assert_val(ret);
626
0
  }
627
628
0
  if (buffer.length > 0)
629
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
630
631
0
  _gnutls_debug_log("EXT[%p]: server generated %s shared key\n", session,
632
0
        group->name);
633
634
0
  return 0;
635
0
}
636
637
static int client_use_key_share_single(gnutls_session_t session,
638
               const gnutls_group_entry_st *group,
639
               gnutls_buffer_st *buffer)
640
0
{
641
0
  gnutls_datum_t key = { NULL, 0 };
642
0
  gnutls_datum_t data;
643
0
  gnutls_pk_params_st pub;
644
0
  const gnutls_ecc_curve_entry_st *curve;
645
0
  int ret;
646
647
0
  switch (group->pk) {
648
0
  case GNUTLS_PK_EC:
649
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
650
651
0
    gnutls_pk_params_init(&pub);
652
653
0
    if (session->key.kshare.ecdh_params.algo != group->pk ||
654
0
        session->key.kshare.ecdh_params.curve != curve->id)
655
0
      return gnutls_assert_val(
656
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
657
658
0
    if (curve->size * 2 + 1 > buffer->length)
659
0
      return gnutls_assert_val(
660
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
661
0
    _gnutls_buffer_pop_datum(buffer, &data, curve->size * 2 + 1);
662
663
    /* read the server's public key */
664
0
    ret = _gnutls_ecc_ansi_x962_import(data.data, data.size,
665
0
               &pub.params[ECC_X],
666
0
               &pub.params[ECC_Y]);
667
0
    if (ret < 0)
668
0
      return gnutls_assert_val(
669
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
670
671
0
    pub.algo = group->pk;
672
0
    pub.curve = curve->id;
673
0
    pub.params_nr = 2;
674
675
    /* generate shared key */
676
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &key,
677
0
                &session->key.kshare.ecdh_params,
678
0
                &pub);
679
0
    gnutls_pk_params_release(&pub);
680
0
    if (ret < 0)
681
0
      return gnutls_assert_val(ret);
682
683
0
    ret = append_key_datum(&session->key.key, &key);
684
0
    _gnutls_free_datum(&key);
685
0
    if (ret < 0)
686
0
      return gnutls_assert_val(ret);
687
688
0
    return 0;
689
690
0
  case GNUTLS_PK_ECDH_X25519:
691
0
  case GNUTLS_PK_ECDH_X448:
692
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
693
694
0
    if (session->key.kshare.ecdhx_params.algo != group->pk ||
695
0
        session->key.kshare.ecdhx_params.curve != curve->id)
696
0
      return gnutls_assert_val(
697
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
698
699
0
    if (curve->size > buffer->length)
700
0
      return gnutls_assert_val(
701
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
702
0
    _gnutls_buffer_pop_datum(buffer, &data, curve->size);
703
704
    /* read the public key and generate shared */
705
0
    gnutls_pk_params_init(&pub);
706
707
0
    pub.algo = group->pk;
708
0
    pub.curve = curve->id;
709
710
0
    pub.raw_pub.data = data.data;
711
0
    pub.raw_pub.size = data.size;
712
713
    /* We don't mask the MSB in the final byte as required
714
     * by RFC7748. This will be done internally by nettle 3.3 or later.
715
     */
716
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &key,
717
0
                &session->key.kshare.ecdhx_params,
718
0
                &pub);
719
0
    if (ret < 0)
720
0
      return gnutls_assert_val(ret);
721
722
0
    ret = append_key_datum(&session->key.key, &key);
723
0
    _gnutls_free_datum(&key);
724
0
    if (ret < 0)
725
0
      return gnutls_assert_val(ret);
726
727
0
    return 0;
728
729
0
  case GNUTLS_PK_DH:
730
0
    if (session->key.kshare.dh_params.algo != group->pk ||
731
0
        session->key.kshare.dh_params.dh_group != group->id)
732
0
      return gnutls_assert_val(
733
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
734
735
0
    if (group->prime->size > buffer->length)
736
0
      return gnutls_assert_val(
737
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
738
0
    _gnutls_buffer_pop_datum(buffer, &data, group->prime->size);
739
740
    /* read the public key and generate shared */
741
0
    gnutls_pk_params_init(&pub);
742
743
0
    ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y], data.data,
744
0
                 data.size);
745
0
    if (ret < 0)
746
0
      return gnutls_assert_val(
747
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
748
749
0
    pub.algo = group->pk;
750
751
    /* generate shared key */
752
0
    ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &key,
753
0
                &session->key.kshare.dh_params,
754
0
                &pub);
755
0
    _gnutls_mpi_release(&pub.params[DH_Y]);
756
0
    if (ret < 0)
757
0
      return gnutls_assert_val(ret);
758
759
0
    ret = append_key_datum(&session->key.key, &key);
760
0
    _gnutls_free_datum(&key);
761
0
    if (ret < 0)
762
0
      return gnutls_assert_val(ret);
763
764
0
    return 0;
765
766
0
  case GNUTLS_PK_EXP_KYBER768:
767
0
  case GNUTLS_PK_MLKEM768:
768
0
  case GNUTLS_PK_MLKEM1024:
769
0
    if (group->ciphertext_size > buffer->length)
770
0
      return gnutls_assert_val(
771
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
772
0
    _gnutls_buffer_pop_datum(buffer, &data, group->ciphertext_size);
773
774
0
    ret = _gnutls_pk_decaps(
775
0
      group->pk, &key, &data,
776
0
      &session->key.kshare.kem_params.raw_priv);
777
0
    if (ret < 0)
778
0
      return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
779
780
0
    ret = append_key_datum(&session->key.key, &key);
781
0
    _gnutls_free_datum(&key);
782
0
    if (ret < 0)
783
0
      return gnutls_assert_val(ret);
784
785
0
    return 0;
786
787
0
  default:
788
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
789
0
  }
790
0
}
791
792
/* Generates shared key and stores it in session->key.key
793
 */
794
static int client_use_key_share(gnutls_session_t session,
795
        const gnutls_group_entry_st *group,
796
        const uint8_t *data, size_t data_size)
797
0
{
798
0
  gnutls_buffer_st buffer;
799
0
  const gnutls_group_entry_st *groups[MAX_HYBRID_GROUPS + 1] = {
800
0
    NULL,
801
0
  };
802
0
  int ret;
803
804
0
  _gnutls_ro_buffer_init(&buffer, data, data_size);
805
806
0
  ret = _gnutls_group_expand(group, groups);
807
0
  if (ret < 0)
808
0
    return gnutls_assert_val(ret);
809
810
0
  for (size_t i = 0; groups[i]; i++) {
811
0
    ret = client_use_key_share_single(session, groups[i], &buffer);
812
0
    if (ret < 0)
813
0
      return gnutls_assert_val(ret);
814
0
  }
815
816
0
  if (buffer.length > 0)
817
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
818
819
0
  _gnutls_debug_log("EXT[%p]: client generated %s shared key\n", session,
820
0
        group->name);
821
822
0
  return 0;
823
0
}
824
825
static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
826
         size_t data_size)
827
0
{
828
0
  int ret;
829
0
  size_t size;
830
0
  unsigned gid;
831
0
  const version_entry_st *ver;
832
0
  const gnutls_group_entry_st *group;
833
0
  unsigned used_share = 0;
834
835
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
836
0
    ver = get_version(session);
837
0
    if (ver == NULL || ver->key_shares == 0)
838
0
      return gnutls_assert_val(0);
839
840
0
    DECR_LEN(data_size, 2);
841
0
    size = _gnutls_read_uint16(data);
842
0
    data += 2;
843
844
0
    if (data_size != size)
845
0
      return gnutls_assert_val(
846
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
847
848
    /* if we do PSK without DH ignore that share */
849
0
    if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
850
0
        (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK)) {
851
0
      reset_cand_groups(session);
852
0
      return 0;
853
0
    }
854
855
0
    while (data_size > 0) {
856
0
      DECR_LEN(data_size, 2);
857
0
      gid = _gnutls_read_uint16(data);
858
0
      data += 2;
859
860
0
      DECR_LEN(data_size, 2);
861
0
      size = _gnutls_read_uint16(data);
862
0
      data += 2;
863
864
0
      DECR_LEN(data_size, size);
865
866
      /* at this point we have already negotiated a group;
867
       * find the group's share. */
868
0
      group = _gnutls_tls_id_to_group(gid);
869
870
0
      if (group != NULL)
871
0
        _gnutls_handshake_log(
872
0
          "EXT[%p]: Received key share for %s\n",
873
0
          session, group->name);
874
875
0
      if (group != NULL &&
876
0
          group == session->internals.cand_group) {
877
0
        _gnutls_session_group_set(session, group);
878
879
0
        ret = server_use_key_share(session, group, data,
880
0
                 size);
881
0
        if (ret < 0)
882
0
          return gnutls_assert_val(ret);
883
884
0
        used_share = 1;
885
0
        break;
886
0
      }
887
888
0
      data += size;
889
0
      continue;
890
0
    }
891
892
    /* we utilize GNUTLS_E_NO_COMMON_KEY_SHARE for:
893
     * 1. signal for hello-retry-request in the handshake
894
     *    layer during first client hello parsing (server side - here).
895
     *    This does not result to error code being
896
     *    propagated to app layer.
897
     * 2. Propagate to application error code that no
898
     *    common key share was found after an HRR was
899
     *    received (client side)
900
     * 3. Propagate to application error code that no
901
     *    common key share was found after an HRR was
902
     *    sent (server side).
903
     * In cases (2,3) the error is translated to illegal
904
     * parameter alert.
905
     */
906
0
    if (used_share == 0) {
907
0
      return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
908
0
    }
909
910
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
911
0
  } else { /* Client */
912
0
    ver = get_version(session);
913
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
914
0
      return gnutls_assert_val(
915
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
916
917
0
    if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
918
0
      if (unlikely(!(session->internals.hsk_flags &
919
0
               HSK_HRR_RECEIVED)))
920
0
        return gnutls_assert_val(
921
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
922
923
0
      DECR_LEN(data_size, 2);
924
0
      gid = _gnutls_read_uint16(data);
925
926
0
      group = _gnutls_tls_id_to_group(gid);
927
0
      if (group == NULL)
928
0
        return gnutls_assert_val(
929
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
930
931
0
      _gnutls_handshake_log(
932
0
        "EXT[%p]: HRR key share with %s\n", session,
933
0
        group->name);
934
935
      /* check if we support it */
936
0
      if (!_gnutls_session_supports_group(session,
937
0
                  group->id)) {
938
0
        _gnutls_handshake_log(
939
0
          "EXT[%p]: received share for %s which is disabled\n",
940
0
          session, group->name);
941
0
        return gnutls_assert_val(
942
0
          GNUTLS_E_ECC_UNSUPPORTED_CURVE);
943
0
      }
944
945
0
      _gnutls_session_group_set(session, group);
946
947
0
      return 0;
948
0
    }
949
    /* else */
950
951
0
    DECR_LEN(data_size, 2);
952
0
    gid = _gnutls_read_uint16(data);
953
0
    data += 2;
954
955
0
    DECR_LEN(data_size, 2);
956
0
    size = _gnutls_read_uint16(data);
957
0
    data += 2;
958
959
0
    if (data_size != size)
960
0
      return gnutls_assert_val(
961
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
962
963
0
    group = _gnutls_tls_id_to_group(gid);
964
0
    if (group == NULL)
965
0
      return gnutls_assert_val(
966
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
967
968
    /* check if we support it */
969
0
    if (!_gnutls_session_supports_group(session, group->id)) {
970
0
      _gnutls_handshake_log(
971
0
        "EXT[%p]: received share for %s which is disabled\n",
972
0
        session, group->name);
973
0
      return gnutls_assert_val(
974
0
        GNUTLS_E_ECC_UNSUPPORTED_CURVE);
975
0
    }
976
977
0
    _gnutls_session_group_set(session, group);
978
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
979
980
0
    ret = client_use_key_share(session, group, data, size);
981
0
    if (ret < 0)
982
0
      return gnutls_assert_val(ret);
983
0
  }
984
985
0
  return 0;
986
0
}
987
988
static inline bool pk_types_overlap_single(const gnutls_group_entry_st *a,
989
             const gnutls_group_entry_st *b)
990
0
{
991
0
  return a->pk == b->pk || (IS_ECDHX(a->pk) && IS_ECDHX(b->pk)) ||
992
0
         (IS_KEM(a->pk) && IS_KEM(b->pk));
993
0
}
994
995
static inline bool pk_types_overlap(const gnutls_group_entry_st *a,
996
            const gnutls_group_entry_st *b)
997
0
{
998
0
  const gnutls_group_entry_st *sa[MAX_HYBRID_GROUPS + 1] = {
999
0
    NULL,
1000
0
  };
1001
0
  const gnutls_group_entry_st *sb[MAX_HYBRID_GROUPS + 1] = {
1002
0
    NULL,
1003
0
  };
1004
0
  int ret;
1005
1006
0
  ret = _gnutls_group_expand(a, sa);
1007
0
  if (ret < 0) {
1008
0
    gnutls_assert();
1009
0
    return false;
1010
0
  }
1011
1012
0
  ret = _gnutls_group_expand(b, sb);
1013
0
  if (ret < 0) {
1014
0
    gnutls_assert();
1015
0
    return false;
1016
0
  }
1017
1018
0
  for (size_t i = 0; sa[i]; i++) {
1019
0
    for (size_t j = 0; sb[j]; j++) {
1020
0
      if (pk_types_overlap_single(sa[i], sb[j]))
1021
0
        return true;
1022
0
    }
1023
0
  }
1024
1025
0
  return false;
1026
0
}
1027
1028
/* returns data_size or a negative number on failure
1029
 */
1030
static int key_share_send_params(gnutls_session_t session,
1031
         gnutls_buffer_st *extdata)
1032
0
{
1033
0
  unsigned i;
1034
0
  int ret;
1035
0
  unsigned int generated = 0;
1036
0
  const gnutls_group_entry_st *group;
1037
0
  const version_entry_st *ver;
1038
1039
  /* this extension is only being sent on client side */
1040
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
1041
0
    unsigned int length_pos;
1042
1043
0
    ver = _gnutls_version_max(session);
1044
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
1045
0
      return 0;
1046
1047
0
    if (!have_creds_for_tls13(session))
1048
0
      return 0;
1049
1050
0
    length_pos = extdata->length;
1051
1052
0
    ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
1053
0
    if (ret < 0)
1054
0
      return gnutls_assert_val(ret);
1055
1056
0
    if (session->internals.hsk_flags &
1057
0
        HSK_HRR_RECEIVED) { /* we know the group */
1058
0
      group = get_group(session);
1059
0
      if (unlikely(group == NULL))
1060
0
        return gnutls_assert_val(
1061
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
1062
1063
0
      ret = client_gen_key_share(session, group, extdata);
1064
0
      if (ret == GNUTLS_E_INT_RET_0)
1065
0
        return gnutls_assert_val(
1066
0
          GNUTLS_E_NO_COMMON_KEY_SHARE);
1067
0
      if (ret < 0)
1068
0
        return gnutls_assert_val(ret);
1069
0
    } else {
1070
0
      const gnutls_group_entry_st *selected_groups[3] = {
1071
0
        NULL,
1072
0
      };
1073
0
      unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */
1074
1075
0
      if (session->internals.flags & GNUTLS_KEY_SHARE_TOP)
1076
0
        max_groups = 1;
1077
0
      else if (session->internals.flags &
1078
0
         GNUTLS_KEY_SHARE_TOP3)
1079
0
        max_groups = 3;
1080
1081
0
      assert(max_groups <=
1082
0
             sizeof(selected_groups) /
1083
0
               sizeof(selected_groups[0]));
1084
1085
      /* generate key shares for out top-(max_groups) groups
1086
       * if they are of different PK type. */
1087
0
      for (i = 0;
1088
0
           i < session->internals.priorities->groups.size;
1089
0
           i++) {
1090
0
        unsigned int j;
1091
1092
0
        group = session->internals.priorities->groups
1093
0
            .entry[i];
1094
1095
0
        for (j = 0; j < generated; j++) {
1096
0
          if (pk_types_overlap(
1097
0
                group,
1098
0
                selected_groups[j])) {
1099
0
            break;
1100
0
          }
1101
0
        }
1102
0
        if (j < generated) {
1103
0
          continue;
1104
0
        }
1105
1106
0
        selected_groups[generated] = group;
1107
1108
0
        ret = client_gen_key_share(session, group,
1109
0
                 extdata);
1110
0
        if (ret == GNUTLS_E_INT_RET_0)
1111
0
          continue; /* no key share for this algorithm */
1112
0
        if (ret < 0)
1113
0
          return gnutls_assert_val(ret);
1114
1115
0
        generated++;
1116
1117
0
        if (generated >= max_groups)
1118
0
          break;
1119
0
      }
1120
0
    }
1121
1122
    /* copy actual length */
1123
0
    _gnutls_write_uint16(extdata->length - length_pos - 2,
1124
0
             &extdata->data[length_pos]);
1125
1126
0
  } else { /* server */
1127
0
    ver = get_version(session);
1128
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
1129
0
      return gnutls_assert_val(0);
1130
1131
0
    if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
1132
0
      group = session->internals.cand_group;
1133
1134
0
      if (group == NULL)
1135
0
        return gnutls_assert_val(
1136
0
          GNUTLS_E_NO_COMMON_KEY_SHARE);
1137
1138
0
      _gnutls_session_group_set(session, group);
1139
1140
0
      _gnutls_handshake_log(
1141
0
        "EXT[%p]: requesting retry with group %s\n",
1142
0
        session, group->name);
1143
0
      ret = _gnutls_buffer_append_prefix(extdata, 16,
1144
0
                 group->tls_id);
1145
0
      if (ret < 0)
1146
0
        return gnutls_assert_val(ret);
1147
0
    } else {
1148
      /* if we are negotiating PSK without DH, do not send a key share */
1149
0
      if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
1150
0
          (session->internals.hsk_flags &
1151
0
           HSK_PSK_KE_MODE_PSK))
1152
0
        return gnutls_assert_val(0);
1153
1154
0
      group = get_group(session);
1155
0
      if (unlikely(group == NULL))
1156
0
        return gnutls_assert_val(
1157
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
1158
1159
0
      ret = server_gen_key_share(session, group, extdata);
1160
0
      if (ret < 0)
1161
0
        return gnutls_assert_val(ret);
1162
0
    }
1163
1164
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_SENT;
1165
0
  }
1166
1167
0
  return 0;
1168
0
}