Coverage Report

Created: 2024-07-23 07:36

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