Coverage Report

Created: 2023-03-26 08:33

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