Coverage Report

Created: 2024-06-20 06:28

/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
/*
62
 * Generates key exchange parameters, and stores them in
63
 * session->key.kshare_*_params.
64
 *
65
 * struct {
66
 *     NamedGroup group;
67
 *     opaque key_exchange<1..2^16-1>;
68
 * } KeyShareEntry;
69
 *
70
 */
71
static int client_gen_key_share(gnutls_session_t session,
72
        const gnutls_group_entry_st *group,
73
        gnutls_buffer_st *extdata)
74
0
{
75
0
  gnutls_datum_t tmp = { NULL, 0 };
76
0
  int ret;
77
78
0
  if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
79
0
      group->pk != GNUTLS_PK_ECDH_X448 && group->pk != GNUTLS_PK_DH) {
80
0
    _gnutls_debug_log("Cannot send key share for group %s!\n",
81
0
          group->name);
82
0
    return GNUTLS_E_INT_RET_0;
83
0
  }
84
85
0
  _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session,
86
0
            group->name);
87
88
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
89
0
  if (ret < 0)
90
0
    return gnutls_assert_val(ret);
91
92
0
  if (group->pk == GNUTLS_PK_EC) {
93
0
    gnutls_pk_params_release(&session->key.kshare.ecdh_params);
94
0
    gnutls_pk_params_init(&session->key.kshare.ecdh_params);
95
96
0
    ret = _gnutls_pk_generate_keys(group->pk, group->curve,
97
0
                 &session->key.kshare.ecdh_params,
98
0
                 1);
99
0
    if (ret < 0)
100
0
      return gnutls_assert_val(ret);
101
102
0
    ret = _gnutls_ecc_ansi_x962_export(
103
0
      group->curve,
104
0
      session->key.kshare.ecdh_params.params[ECC_X],
105
0
      session->key.kshare.ecdh_params.params[ECC_Y], &tmp);
106
0
    if (ret < 0)
107
0
      return gnutls_assert_val(ret);
108
109
0
    ret = _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data,
110
0
              tmp.size);
111
0
    if (ret < 0) {
112
0
      gnutls_assert();
113
0
      goto cleanup;
114
0
    }
115
116
0
    session->key.kshare.ecdh_params.algo = group->pk;
117
0
    session->key.kshare.ecdh_params.curve = group->curve;
118
119
0
    ret = 0;
120
121
0
  } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
122
0
       group->pk == GNUTLS_PK_ECDH_X448) {
123
0
    gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
124
0
    gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
125
126
0
    ret = _gnutls_pk_generate_keys(
127
0
      group->pk, group->curve,
128
0
      &session->key.kshare.ecdhx_params, 1);
129
0
    if (ret < 0)
130
0
      return gnutls_assert_val(ret);
131
132
0
    ret = _gnutls_buffer_append_data_prefix(
133
0
      extdata, 16,
134
0
      session->key.kshare.ecdhx_params.raw_pub.data,
135
0
      session->key.kshare.ecdhx_params.raw_pub.size);
136
0
    if (ret < 0) {
137
0
      gnutls_assert();
138
0
      goto cleanup;
139
0
    }
140
141
0
    session->key.kshare.ecdhx_params.algo = group->pk;
142
0
    session->key.kshare.ecdhx_params.curve = group->curve;
143
144
0
    ret = 0;
145
146
0
  } else if (group->pk == GNUTLS_PK_DH) {
147
    /* we need to initialize the group parameters first */
148
0
    gnutls_pk_params_release(&session->key.kshare.dh_params);
149
0
    gnutls_pk_params_init(&session->key.kshare.dh_params);
150
151
0
    ret = _gnutls_mpi_init_scan_nz(
152
0
      &session->key.kshare.dh_params.params[DH_G],
153
0
      group->generator->data, group->generator->size);
154
0
    if (ret < 0)
155
0
      return gnutls_assert_val(
156
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
157
158
0
    ret = _gnutls_mpi_init_scan_nz(
159
0
      &session->key.kshare.dh_params.params[DH_P],
160
0
      group->prime->data, group->prime->size);
161
0
    if (ret < 0)
162
0
      return gnutls_assert_val(
163
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
164
165
0
    ret = _gnutls_mpi_init_scan_nz(
166
0
      &session->key.kshare.dh_params.params[DH_Q],
167
0
      group->q->data, group->q->size);
168
0
    if (ret < 0)
169
0
      return gnutls_assert_val(
170
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
171
172
0
    session->key.kshare.dh_params.algo = group->pk;
173
0
    session->key.kshare.dh_params.dh_group =
174
0
      group->id; /* no curve in FFDH, we write the group */
175
0
    session->key.kshare.dh_params.qbits = *group->q_bits;
176
0
    session->key.kshare.dh_params.params_nr = 3;
177
178
0
    ret = _gnutls_pk_generate_keys(
179
0
      group->pk, 0, &session->key.kshare.dh_params, 1);
180
0
    if (ret < 0)
181
0
      return gnutls_assert_val(ret);
182
183
0
    ret = _gnutls_buffer_append_prefix(extdata, 16,
184
0
               group->prime->size);
185
0
    if (ret < 0)
186
0
      return gnutls_assert_val(ret);
187
188
0
    ret = _gnutls_buffer_append_fixed_mpi(
189
0
      extdata, session->key.kshare.dh_params.params[DH_Y],
190
0
      group->prime->size);
191
0
    if (ret < 0)
192
0
      return gnutls_assert_val(ret);
193
194
0
    ret = 0;
195
0
  }
196
197
0
cleanup:
198
0
  gnutls_free(tmp.data);
199
0
  return ret;
200
0
}
201
202
/*
203
 * Sends server key exchange parameters
204
 *
205
 */
206
static int server_gen_key_share(gnutls_session_t session,
207
        const gnutls_group_entry_st *group,
208
        gnutls_buffer_st *extdata)
209
0
{
210
0
  gnutls_datum_t tmp = { NULL, 0 };
211
0
  int ret;
212
213
0
  if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
214
0
      group->pk != GNUTLS_PK_ECDH_X448 && group->pk != GNUTLS_PK_DH) {
215
0
    _gnutls_debug_log("Cannot send key share for group %s!\n",
216
0
          group->name);
217
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
218
0
  }
219
220
0
  _gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session,
221
0
            group->name);
222
223
0
  ret = _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
224
0
  if (ret < 0)
225
0
    return gnutls_assert_val(ret);
226
227
0
  if (group->pk == GNUTLS_PK_EC) {
228
0
    ret = _gnutls_ecc_ansi_x962_export(
229
0
      group->curve,
230
0
      session->key.kshare.ecdh_params.params[ECC_X],
231
0
      session->key.kshare.ecdh_params.params[ECC_Y], &tmp);
232
0
    if (ret < 0)
233
0
      return gnutls_assert_val(ret);
234
235
0
    ret = _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data,
236
0
              tmp.size);
237
0
    if (ret < 0) {
238
0
      gnutls_assert();
239
0
      goto cleanup;
240
0
    }
241
242
0
    ret = 0;
243
244
0
  } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
245
0
       group->pk == GNUTLS_PK_ECDH_X448) {
246
0
    ret = _gnutls_buffer_append_data_prefix(
247
0
      extdata, 16,
248
0
      session->key.kshare.ecdhx_params.raw_pub.data,
249
0
      session->key.kshare.ecdhx_params.raw_pub.size);
250
0
    if (ret < 0)
251
0
      return gnutls_assert_val(ret);
252
253
0
    ret = 0;
254
255
0
  } else if (group->pk == GNUTLS_PK_DH) {
256
0
    ret = _gnutls_buffer_append_prefix(extdata, 16,
257
0
               group->prime->size);
258
0
    if (ret < 0)
259
0
      return gnutls_assert_val(ret);
260
261
0
    ret = _gnutls_buffer_append_fixed_mpi(
262
0
      extdata, session->key.kshare.dh_params.params[DH_Y],
263
0
      group->prime->size);
264
0
    if (ret < 0)
265
0
      return gnutls_assert_val(ret);
266
267
0
    ret = 0;
268
0
  }
269
270
0
cleanup:
271
0
  gnutls_free(tmp.data);
272
0
  return ret;
273
0
}
274
275
/* Generates shared key and stores it in session->key.key
276
 */
277
static int server_use_key_share(gnutls_session_t session,
278
        const gnutls_group_entry_st *group,
279
        const uint8_t *data, size_t data_size)
280
0
{
281
0
  const gnutls_ecc_curve_entry_st *curve;
282
0
  int ret;
283
284
0
  if (group->pk == GNUTLS_PK_EC) {
285
0
    gnutls_pk_params_st pub;
286
287
0
    gnutls_pk_params_release(&session->key.kshare.ecdh_params);
288
0
    gnutls_pk_params_init(&session->key.kshare.ecdh_params);
289
290
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
291
292
0
    gnutls_pk_params_init(&pub);
293
294
0
    if (curve->size * 2 + 1 != data_size)
295
0
      return gnutls_assert_val(
296
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
297
298
    /* generate our key */
299
0
    ret = _gnutls_pk_generate_keys(curve->pk, curve->id,
300
0
                 &session->key.kshare.ecdh_params,
301
0
                 1);
302
0
    if (ret < 0)
303
0
      return gnutls_assert_val(ret);
304
305
    /* read the public key */
306
0
    ret = _gnutls_ecc_ansi_x962_import(data, data_size,
307
0
               &pub.params[ECC_X],
308
0
               &pub.params[ECC_Y]);
309
0
    if (ret < 0)
310
0
      return gnutls_assert_val(ret);
311
312
0
    pub.algo = group->pk;
313
0
    pub.curve = curve->id;
314
0
    pub.params_nr = 2;
315
316
    /* generate shared */
317
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key,
318
0
                &session->key.kshare.ecdh_params,
319
0
                &pub);
320
0
    gnutls_pk_params_release(&pub);
321
0
    if (ret < 0) {
322
0
      return gnutls_assert_val(ret);
323
0
    }
324
325
0
    ret = 0;
326
327
0
  } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
328
0
       group->pk == GNUTLS_PK_ECDH_X448) {
329
0
    gnutls_pk_params_st pub;
330
331
0
    gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
332
0
    gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
333
334
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
335
336
0
    if (curve->size != data_size)
337
0
      return gnutls_assert_val(
338
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
339
340
    /* generate our key */
341
0
    ret = _gnutls_pk_generate_keys(
342
0
      curve->pk, curve->id, &session->key.kshare.ecdhx_params,
343
0
      1);
344
0
    if (ret < 0)
345
0
      return gnutls_assert_val(ret);
346
347
    /* read the public key and generate shared */
348
0
    gnutls_pk_params_init(&pub);
349
350
0
    pub.algo = group->pk;
351
0
    pub.curve = curve->id;
352
353
0
    pub.raw_pub.data = (void *)data;
354
0
    pub.raw_pub.size = data_size;
355
356
    /* We don't mask the MSB in the final byte as required
357
     * by RFC7748. This will be done internally by nettle 3.3 or later.
358
     */
359
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key,
360
0
                &session->key.kshare.ecdhx_params,
361
0
                &pub);
362
0
    if (ret < 0) {
363
0
      return gnutls_assert_val(ret);
364
0
    }
365
366
0
    ret = 0;
367
368
0
  } else if (group->pk == GNUTLS_PK_DH) {
369
0
    gnutls_pk_params_st pub;
370
371
    /* we need to initialize the group parameters first */
372
0
    gnutls_pk_params_release(&session->key.kshare.dh_params);
373
0
    gnutls_pk_params_init(&session->key.kshare.dh_params);
374
375
0
    if (data_size != group->prime->size)
376
0
      return gnutls_assert_val(
377
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
378
379
    /* set group params */
380
0
    ret = _gnutls_mpi_init_scan_nz(
381
0
      &session->key.kshare.dh_params.params[DH_G],
382
0
      group->generator->data, group->generator->size);
383
0
    if (ret < 0)
384
0
      return gnutls_assert_val(
385
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
386
387
0
    ret = _gnutls_mpi_init_scan_nz(
388
0
      &session->key.kshare.dh_params.params[DH_P],
389
0
      group->prime->data, group->prime->size);
390
0
    if (ret < 0)
391
0
      return gnutls_assert_val(
392
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
393
394
0
    ret = _gnutls_mpi_init_scan_nz(
395
0
      &session->key.kshare.dh_params.params[DH_Q],
396
0
      group->q->data, group->q->size);
397
0
    if (ret < 0)
398
0
      return gnutls_assert_val(
399
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
400
401
0
    session->key.kshare.dh_params.algo = GNUTLS_PK_DH;
402
0
    session->key.kshare.dh_params.qbits = *group->q_bits;
403
0
    session->key.kshare.dh_params.params_nr = 3;
404
405
    /* generate our keys */
406
0
    ret = _gnutls_pk_generate_keys(
407
0
      group->pk, 0, &session->key.kshare.dh_params, 1);
408
0
    if (ret < 0)
409
0
      return gnutls_assert_val(ret);
410
411
    /* read the public key and generate shared */
412
0
    gnutls_pk_params_init(&pub);
413
414
0
    ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y], data,
415
0
                 data_size);
416
0
    if (ret < 0)
417
0
      return gnutls_assert_val(
418
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
419
420
0
    pub.algo = group->pk;
421
422
    /* generate shared key */
423
0
    ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key,
424
0
                &session->key.kshare.dh_params,
425
0
                &pub);
426
0
    _gnutls_mpi_release(&pub.params[DH_Y]);
427
0
    if (ret < 0)
428
0
      return gnutls_assert_val(ret);
429
430
0
    ret = 0;
431
0
  } else {
432
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
433
0
  }
434
435
0
  _gnutls_debug_log("EXT[%p]: server generated %s shared key\n", session,
436
0
        group->name);
437
438
0
  return ret;
439
0
}
440
441
/* Generates shared key and stores it in session->key.key
442
 */
443
static int client_use_key_share(gnutls_session_t session,
444
        const gnutls_group_entry_st *group,
445
        const uint8_t *data, size_t data_size)
446
0
{
447
0
  const gnutls_ecc_curve_entry_st *curve;
448
0
  int ret;
449
450
0
  if (group->pk == GNUTLS_PK_EC) {
451
0
    gnutls_pk_params_st pub;
452
453
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
454
455
0
    gnutls_pk_params_init(&pub);
456
457
0
    if (session->key.kshare.ecdh_params.algo != group->pk ||
458
0
        session->key.kshare.ecdh_params.curve != curve->id)
459
0
      return gnutls_assert_val(
460
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
461
462
0
    if (curve->size * 2 + 1 != data_size)
463
0
      return gnutls_assert_val(
464
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
465
466
    /* read the server's public key */
467
0
    ret = _gnutls_ecc_ansi_x962_import(data, data_size,
468
0
               &pub.params[ECC_X],
469
0
               &pub.params[ECC_Y]);
470
0
    if (ret < 0)
471
0
      return gnutls_assert_val(ret);
472
473
0
    pub.algo = group->pk;
474
0
    pub.curve = curve->id;
475
0
    pub.params_nr = 2;
476
477
    /* generate shared key */
478
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key,
479
0
                &session->key.kshare.ecdh_params,
480
0
                &pub);
481
0
    gnutls_pk_params_release(&pub);
482
0
    if (ret < 0) {
483
0
      return gnutls_assert_val(ret);
484
0
    }
485
486
0
    ret = 0;
487
488
0
  } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
489
0
       group->pk == GNUTLS_PK_ECDH_X448) {
490
0
    gnutls_pk_params_st pub;
491
492
0
    curve = _gnutls_ecc_curve_get_params(group->curve);
493
494
0
    if (session->key.kshare.ecdhx_params.algo != group->pk ||
495
0
        session->key.kshare.ecdhx_params.curve != curve->id)
496
0
      return gnutls_assert_val(
497
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
498
499
0
    if (curve->size != data_size)
500
0
      return gnutls_assert_val(
501
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
502
503
    /* read the public key and generate shared */
504
0
    gnutls_pk_params_init(&pub);
505
506
0
    pub.algo = group->pk;
507
0
    pub.curve = curve->id;
508
509
0
    pub.raw_pub.data = (void *)data;
510
0
    pub.raw_pub.size = data_size;
511
512
    /* We don't mask the MSB in the final byte as required
513
     * by RFC7748. This will be done internally by nettle 3.3 or later.
514
     */
515
0
    ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key,
516
0
                &session->key.kshare.ecdhx_params,
517
0
                &pub);
518
0
    if (ret < 0) {
519
0
      return gnutls_assert_val(ret);
520
0
    }
521
522
0
    ret = 0;
523
524
0
  } else if (group->pk == GNUTLS_PK_DH) {
525
0
    gnutls_pk_params_st pub;
526
527
0
    if (session->key.kshare.dh_params.algo != group->pk ||
528
0
        session->key.kshare.dh_params.dh_group != group->id)
529
0
      return gnutls_assert_val(
530
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
531
532
0
    if (data_size != group->prime->size)
533
0
      return gnutls_assert_val(
534
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
535
536
    /* read the public key and generate shared */
537
0
    gnutls_pk_params_init(&pub);
538
539
0
    ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y], data,
540
0
                 data_size);
541
0
    if (ret < 0)
542
0
      return gnutls_assert_val(
543
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
544
545
0
    pub.algo = group->pk;
546
547
    /* generate shared key */
548
0
    ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key,
549
0
                &session->key.kshare.dh_params,
550
0
                &pub);
551
0
    _gnutls_mpi_release(&pub.params[DH_Y]);
552
0
    if (ret < 0)
553
0
      return gnutls_assert_val(ret);
554
555
0
    ret = 0;
556
0
  } else {
557
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
558
0
  }
559
560
0
  _gnutls_debug_log("EXT[%p]: client generated %s shared key\n", session,
561
0
        group->name);
562
563
0
  return ret;
564
0
}
565
566
static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
567
         size_t data_size)
568
0
{
569
0
  int ret;
570
0
  size_t size;
571
0
  unsigned gid;
572
0
  const version_entry_st *ver;
573
0
  const gnutls_group_entry_st *group;
574
0
  unsigned used_share = 0;
575
576
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
577
0
    ver = get_version(session);
578
0
    if (ver == NULL || ver->key_shares == 0)
579
0
      return gnutls_assert_val(0);
580
581
0
    DECR_LEN(data_size, 2);
582
0
    size = _gnutls_read_uint16(data);
583
0
    data += 2;
584
585
0
    if (data_size != size)
586
0
      return gnutls_assert_val(
587
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
588
589
    /* if we do PSK without DH ignore that share */
590
0
    if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
591
0
        (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK)) {
592
0
      reset_cand_groups(session);
593
0
      return 0;
594
0
    }
595
596
0
    while (data_size > 0) {
597
0
      DECR_LEN(data_size, 2);
598
0
      gid = _gnutls_read_uint16(data);
599
0
      data += 2;
600
601
0
      DECR_LEN(data_size, 2);
602
0
      size = _gnutls_read_uint16(data);
603
0
      data += 2;
604
605
0
      DECR_LEN(data_size, size);
606
607
      /* at this point we have already negotiated a group;
608
       * find the group's share. */
609
0
      group = _gnutls_tls_id_to_group(gid);
610
611
0
      if (group != NULL)
612
0
        _gnutls_handshake_log(
613
0
          "EXT[%p]: Received key share for %s\n",
614
0
          session, group->name);
615
616
0
      if (group != NULL &&
617
0
          group == session->internals.cand_group) {
618
0
        _gnutls_session_group_set(session, group);
619
620
0
        ret = server_use_key_share(session, group, data,
621
0
                 size);
622
0
        if (ret < 0)
623
0
          return gnutls_assert_val(ret);
624
625
0
        used_share = 1;
626
0
        break;
627
0
      }
628
629
0
      data += size;
630
0
      continue;
631
0
    }
632
633
    /* we utilize GNUTLS_E_NO_COMMON_KEY_SHARE for:
634
     * 1. signal for hello-retry-request in the handshake
635
     *    layer during first client hello parsing (server side - here).
636
     *    This does not result to error code being
637
     *    propagated to app layer.
638
     * 2. Propagate to application error code that no
639
     *    common key share was found after an HRR was
640
     *    received (client side)
641
     * 3. Propagate to application error code that no
642
     *    common key share was found after an HRR was
643
     *    sent (server side).
644
     * In cases (2,3) the error is translated to illegal
645
     * parameter alert.
646
     */
647
0
    if (used_share == 0) {
648
0
      return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
649
0
    }
650
651
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
652
0
  } else { /* Client */
653
0
    ver = get_version(session);
654
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
655
0
      return gnutls_assert_val(
656
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
657
658
0
    if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
659
0
      if (unlikely(!(session->internals.hsk_flags &
660
0
               HSK_HRR_RECEIVED)))
661
0
        return gnutls_assert_val(
662
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
663
664
0
      DECR_LEN(data_size, 2);
665
0
      gid = _gnutls_read_uint16(data);
666
667
0
      group = _gnutls_tls_id_to_group(gid);
668
0
      if (group == NULL)
669
0
        return gnutls_assert_val(
670
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
671
672
0
      _gnutls_handshake_log(
673
0
        "EXT[%p]: HRR key share with %s\n", session,
674
0
        group->name);
675
676
      /* check if we support it */
677
0
      ret = _gnutls_session_supports_group(session,
678
0
                   group->id);
679
0
      if (ret < 0) {
680
0
        _gnutls_handshake_log(
681
0
          "EXT[%p]: received share for %s which is disabled\n",
682
0
          session, group->name);
683
0
        return gnutls_assert_val(ret);
684
0
      }
685
686
0
      _gnutls_session_group_set(session, group);
687
688
0
      return 0;
689
0
    }
690
    /* else */
691
692
0
    DECR_LEN(data_size, 2);
693
0
    gid = _gnutls_read_uint16(data);
694
0
    data += 2;
695
696
0
    DECR_LEN(data_size, 2);
697
0
    size = _gnutls_read_uint16(data);
698
0
    data += 2;
699
700
0
    if (data_size != size)
701
0
      return gnutls_assert_val(
702
0
        GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
703
704
0
    group = _gnutls_tls_id_to_group(gid);
705
0
    if (group == NULL)
706
0
      return gnutls_assert_val(
707
0
        GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
708
709
    /* check if we support it */
710
0
    ret = _gnutls_session_supports_group(session, group->id);
711
0
    if (ret < 0) {
712
0
      _gnutls_handshake_log(
713
0
        "EXT[%p]: received share for %s which is disabled\n",
714
0
        session, group->name);
715
0
      return gnutls_assert_val(ret);
716
0
    }
717
718
0
    _gnutls_session_group_set(session, group);
719
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
720
721
0
    ret = client_use_key_share(session, group, data, size);
722
0
    if (ret < 0)
723
0
      return gnutls_assert_val(ret);
724
0
  }
725
726
0
  return 0;
727
0
}
728
729
static inline bool pk_type_is_ecdhx(gnutls_pk_algorithm_t pk)
730
0
{
731
0
  return pk == GNUTLS_PK_ECDH_X25519 || pk == GNUTLS_PK_ECDH_X448;
732
0
}
733
734
static inline bool pk_type_equal(gnutls_pk_algorithm_t a,
735
         gnutls_pk_algorithm_t b)
736
0
{
737
0
  return a == b || (pk_type_is_ecdhx(a) && pk_type_is_ecdhx(b));
738
0
}
739
740
/* returns data_size or a negative number on failure
741
 */
742
static int key_share_send_params(gnutls_session_t session,
743
         gnutls_buffer_st *extdata)
744
0
{
745
0
  unsigned i;
746
0
  int ret;
747
0
  unsigned int generated = 0;
748
0
  const gnutls_group_entry_st *group;
749
0
  const version_entry_st *ver;
750
751
  /* this extension is only being sent on client side */
752
0
  if (session->security_parameters.entity == GNUTLS_CLIENT) {
753
0
    unsigned int length_pos;
754
755
0
    ver = _gnutls_version_max(session);
756
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
757
0
      return 0;
758
759
0
    if (!have_creds_for_tls13(session))
760
0
      return 0;
761
762
0
    length_pos = extdata->length;
763
764
0
    ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
765
0
    if (ret < 0)
766
0
      return gnutls_assert_val(ret);
767
768
0
    if (session->internals.hsk_flags &
769
0
        HSK_HRR_RECEIVED) { /* we know the group */
770
0
      group = get_group(session);
771
0
      if (unlikely(group == NULL))
772
0
        return gnutls_assert_val(
773
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
774
775
0
      ret = client_gen_key_share(session, group, extdata);
776
0
      if (ret == GNUTLS_E_INT_RET_0)
777
0
        return gnutls_assert_val(
778
0
          GNUTLS_E_NO_COMMON_KEY_SHARE);
779
0
      if (ret < 0)
780
0
        return gnutls_assert_val(ret);
781
0
    } else {
782
0
      gnutls_pk_algorithm_t selected_groups[3];
783
0
      unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */
784
785
0
      if (session->internals.flags & GNUTLS_KEY_SHARE_TOP)
786
0
        max_groups = 1;
787
0
      else if (session->internals.flags &
788
0
         GNUTLS_KEY_SHARE_TOP3)
789
0
        max_groups = 3;
790
791
0
      assert(max_groups <=
792
0
             sizeof(selected_groups) /
793
0
               sizeof(selected_groups[0]));
794
795
      /* generate key shares for out top-(max_groups) groups
796
       * if they are of different PK type. */
797
0
      for (i = 0;
798
0
           i < session->internals.priorities->groups.size;
799
0
           i++) {
800
0
        unsigned int j;
801
802
0
        group = session->internals.priorities->groups
803
0
            .entry[i];
804
805
0
        for (j = 0; j < generated; j++) {
806
0
          if (pk_type_equal(group->pk,
807
0
                selected_groups[j])) {
808
0
            break;
809
0
          }
810
0
        }
811
0
        if (j < generated) {
812
0
          continue;
813
0
        }
814
815
0
        selected_groups[generated] = group->pk;
816
817
0
        ret = client_gen_key_share(session, group,
818
0
                 extdata);
819
0
        if (ret == GNUTLS_E_INT_RET_0)
820
0
          continue; /* no key share for this algorithm */
821
0
        if (ret < 0)
822
0
          return gnutls_assert_val(ret);
823
824
0
        generated++;
825
826
0
        if (generated >= max_groups)
827
0
          break;
828
0
      }
829
0
    }
830
831
    /* copy actual length */
832
0
    _gnutls_write_uint16(extdata->length - length_pos - 2,
833
0
             &extdata->data[length_pos]);
834
835
0
  } else { /* server */
836
0
    ver = get_version(session);
837
0
    if (unlikely(ver == NULL || ver->key_shares == 0))
838
0
      return gnutls_assert_val(0);
839
840
0
    if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
841
0
      group = session->internals.cand_group;
842
843
0
      if (group == NULL)
844
0
        return gnutls_assert_val(
845
0
          GNUTLS_E_NO_COMMON_KEY_SHARE);
846
847
0
      _gnutls_session_group_set(session, group);
848
849
0
      _gnutls_handshake_log(
850
0
        "EXT[%p]: requesting retry with group %s\n",
851
0
        session, group->name);
852
0
      ret = _gnutls_buffer_append_prefix(extdata, 16,
853
0
                 group->tls_id);
854
0
      if (ret < 0)
855
0
        return gnutls_assert_val(ret);
856
0
    } else {
857
      /* if we are negotiating PSK without DH, do not send a key share */
858
0
      if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
859
0
          (session->internals.hsk_flags &
860
0
           HSK_PSK_KE_MODE_PSK))
861
0
        return gnutls_assert_val(0);
862
863
0
      group = get_group(session);
864
0
      if (unlikely(group == NULL))
865
0
        return gnutls_assert_val(
866
0
          GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
867
868
0
      ret = server_gen_key_share(session, group, extdata);
869
0
      if (ret < 0)
870
0
        return gnutls_assert_val(ret);
871
0
    }
872
873
0
    session->internals.hsk_flags |= HSK_KEY_SHARE_SENT;
874
0
  }
875
876
0
  return 0;
877
0
}