Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/auth/ecdhe.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2017 Red Hat, Inc.
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
9
 * The GnuTLS is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/* This file contains common stuff in Ephemeral Diffie-Hellman (DHE)
25
 * and Anonymous DH key exchange(DHA). These are used in the handshake
26
 * procedure of the certificate and anonymous authentication.
27
 */
28
29
#include "gnutls_int.h"
30
#include "auth.h"
31
#include "errors.h"
32
#include "dh.h"
33
#include "num.h"
34
#include "tls-sig.h"
35
#include <state.h>
36
#include <datum.h>
37
#include <x509.h>
38
#include <auth/ecdhe.h>
39
#include <ecc.h>
40
#include <ext/supported_groups.h>
41
#include <algorithms.h>
42
#include <auth/psk.h>
43
#include <auth/cert.h>
44
#include <pk.h>
45
46
static int gen_ecdhe_server_kx(gnutls_session_t, gnutls_buffer_st *);
47
static int
48
proc_ecdhe_server_kx(gnutls_session_t session,
49
         uint8_t * data, size_t _data_size);
50
static int
51
proc_ecdhe_client_kx(gnutls_session_t session,
52
         uint8_t * data, size_t _data_size);
53
54
#if defined(ENABLE_ECDHE)
55
const mod_auth_st ecdhe_ecdsa_auth_struct = {
56
  "ECDHE_ECDSA",
57
  _gnutls_gen_cert_server_crt,
58
  _gnutls_gen_cert_client_crt,
59
  gen_ecdhe_server_kx,
60
  _gnutls_gen_ecdh_common_client_kx,  /* This is the only difference */
61
  _gnutls_gen_cert_client_crt_vrfy,
62
  _gnutls_gen_cert_server_cert_req,
63
64
  _gnutls_proc_crt,
65
  _gnutls_proc_crt,
66
  proc_ecdhe_server_kx,
67
  proc_ecdhe_client_kx,
68
  _gnutls_proc_cert_client_crt_vrfy,
69
  _gnutls_proc_cert_cert_req
70
};
71
72
const mod_auth_st ecdhe_rsa_auth_struct = {
73
  "ECDHE_RSA",
74
  _gnutls_gen_cert_server_crt,
75
  _gnutls_gen_cert_client_crt,
76
  gen_ecdhe_server_kx,
77
  _gnutls_gen_ecdh_common_client_kx,  /* This is the only difference */
78
  _gnutls_gen_cert_client_crt_vrfy,
79
  _gnutls_gen_cert_server_cert_req,
80
81
  _gnutls_proc_crt,
82
  _gnutls_proc_crt,
83
  proc_ecdhe_server_kx,
84
  proc_ecdhe_client_kx,
85
  _gnutls_proc_cert_client_crt_vrfy,
86
  _gnutls_proc_cert_cert_req
87
};
88
89
static int calc_ecdh_key(gnutls_session_t session,
90
       gnutls_datum_t * psk_key,
91
       const gnutls_ecc_curve_entry_st * ecurve)
92
0
{
93
0
  gnutls_pk_params_st pub;
94
0
  int ret;
95
0
  gnutls_datum_t tmp_dh_key;
96
97
0
  gnutls_pk_params_init(&pub);
98
0
  pub.params[ECC_X] = session->key.proto.tls12.ecdh.x;
99
0
  pub.params[ECC_Y] = session->key.proto.tls12.ecdh.y;
100
0
  pub.raw_pub.data = session->key.proto.tls12.ecdh.raw.data;
101
0
  pub.raw_pub.size = session->key.proto.tls12.ecdh.raw.size;
102
0
  pub.curve = ecurve->id;
103
104
0
  ret =
105
0
      _gnutls_pk_derive(ecurve->pk, &tmp_dh_key,
106
0
            &session->key.proto.tls12.ecdh.params, &pub);
107
0
  if (ret < 0) {
108
0
    ret = gnutls_assert_val(ret);
109
0
    goto cleanup;
110
0
  }
111
112
0
  if (psk_key == NULL) {
113
0
    memcpy(&session->key.key, &tmp_dh_key, sizeof(gnutls_datum_t));
114
0
    tmp_dh_key.data = NULL; /* no longer needed */
115
0
  } else {
116
0
    ret =
117
0
        _gnutls_set_psk_session_key(session, psk_key, &tmp_dh_key);
118
0
    _gnutls_free_temp_key_datum(&tmp_dh_key);
119
120
0
    if (ret < 0) {
121
0
      ret = gnutls_assert_val(ret);
122
0
      goto cleanup;
123
0
    }
124
0
  }
125
126
0
  ret = 0;
127
128
0
 cleanup:
129
  /* no longer needed */
130
0
  _gnutls_mpi_release(&session->key.proto.tls12.ecdh.x);
131
0
  _gnutls_mpi_release(&session->key.proto.tls12.ecdh.y);
132
0
  _gnutls_free_datum(&session->key.proto.tls12.ecdh.raw);
133
0
  gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
134
0
  return ret;
135
0
}
136
137
int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
138
               uint8_t * data, size_t _data_size,
139
               const struct gnutls_group_entry_st
140
               *group, gnutls_datum_t * psk_key)
141
0
{
142
0
  ssize_t data_size = _data_size;
143
0
  int ret, i = 0;
144
0
  unsigned point_size;
145
0
  const gnutls_ecc_curve_entry_st *ecurve;
146
147
0
  if (group == NULL)
148
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
149
150
0
  ecurve = _gnutls_ecc_curve_get_params(group->curve);
151
0
  if (ecurve == NULL)
152
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
153
154
0
  DECR_LEN(data_size, 1);
155
0
  point_size = data[i];
156
0
  i += 1;
157
158
0
  if (point_size == 0) {
159
0
    ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
160
0
    goto cleanup;
161
0
  }
162
163
0
  DECR_LEN(data_size, point_size);
164
165
0
  if (ecurve->pk == GNUTLS_PK_EC) {
166
0
    ret =
167
0
        _gnutls_ecc_ansi_x962_import(&data[i], point_size,
168
0
             &session->key.proto.tls12.
169
0
             ecdh.x,
170
0
             &session->key.proto.tls12.
171
0
             ecdh.y);
172
0
    if (ret < 0) {
173
0
      gnutls_assert();
174
0
      goto cleanup;
175
0
    }
176
0
  } else if (ecurve->pk == GNUTLS_PK_ECDH_X25519 ||
177
0
       ecurve->pk == GNUTLS_PK_ECDH_X448) {
178
0
    if (ecurve->size != point_size)
179
0
      return
180
0
          gnutls_assert_val
181
0
          (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
182
183
0
    ret = _gnutls_set_datum(&session->key.proto.tls12.ecdh.raw,
184
0
          &data[i], point_size);
185
0
    if (ret < 0) {
186
0
      gnutls_assert();
187
0
      goto cleanup;
188
0
    }
189
190
    /* RFC7748 requires to mask the MSB in the final byte
191
     * for X25519 (not X448) */
192
0
    if (ecurve->id == GNUTLS_ECC_CURVE_X25519) {
193
0
      session->key.proto.tls12.ecdh.raw.data[point_size -
194
0
                     1] &= 0x7f;
195
0
    }
196
0
  } else {
197
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
198
0
  }
199
200
0
  if (data_size != 0) {
201
0
    ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
202
0
    goto cleanup;
203
0
  }
204
205
  /* generate pre-shared key */
206
0
  ret = calc_ecdh_key(session, psk_key, ecurve);
207
0
  if (ret < 0) {
208
0
    gnutls_assert();
209
0
    goto cleanup;
210
0
  }
211
0
 cleanup:
212
0
  _gnutls_mpi_release(&session->key.proto.tls12.ecdh.x);
213
0
  _gnutls_mpi_release(&session->key.proto.tls12.ecdh.y);
214
0
  _gnutls_free_datum(&session->key.proto.tls12.ecdh.raw);
215
0
  gnutls_pk_params_clear(&session->key.proto.tls12.ecdh.params);
216
0
  return ret;
217
0
}
218
219
static int
220
proc_ecdhe_client_kx(gnutls_session_t session,
221
         uint8_t * data, size_t _data_size)
222
0
{
223
0
  gnutls_certificate_credentials_t cred;
224
225
0
  cred = (gnutls_certificate_credentials_t)
226
0
      _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
227
0
  if (cred == NULL) {
228
0
    gnutls_assert();
229
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
230
0
  }
231
232
0
  return _gnutls_proc_ecdh_common_client_kx(session, data,
233
0
              _data_size,
234
0
              get_group(session), NULL);
235
0
}
236
237
int
238
_gnutls_gen_ecdh_common_client_kx(gnutls_session_t session,
239
          gnutls_buffer_st * data)
240
0
{
241
0
  return _gnutls_gen_ecdh_common_client_kx_int(session, data, NULL);
242
0
}
243
244
int
245
_gnutls_gen_ecdh_common_client_kx_int(gnutls_session_t session,
246
              gnutls_buffer_st * data,
247
              gnutls_datum_t * psk_key)
248
0
{
249
0
  int ret;
250
0
  gnutls_datum_t out;
251
0
  const gnutls_group_entry_st *group = get_group(session);
252
0
  const gnutls_ecc_curve_entry_st *ecurve;
253
0
  int pk;
254
0
  unsigned init_pos = data->length;
255
256
0
  if (group == NULL)
257
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
258
259
0
  ecurve = _gnutls_ecc_curve_get_params(group->curve);
260
0
  if (ecurve == NULL)
261
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
262
263
0
  pk = ecurve->pk;
264
265
  /* generate temporal key */
266
0
  ret =
267
0
      _gnutls_pk_generate_keys(pk, ecurve->id,
268
0
             &session->key.proto.tls12.ecdh.params, 1);
269
0
  if (ret < 0)
270
0
    return gnutls_assert_val(ret);
271
272
0
  if (pk == GNUTLS_PK_EC) {
273
0
    ret =
274
0
        _gnutls_ecc_ansi_x962_export(ecurve->id,
275
0
             session->key.proto.tls12.
276
0
             ecdh.params.
277
0
             params[ECC_X] /* x */ ,
278
0
             session->key.proto.tls12.
279
0
             ecdh.params.
280
0
             params[ECC_Y] /* y */ ,
281
0
             &out);
282
283
0
    if (ret < 0) {
284
0
      gnutls_assert();
285
0
      goto cleanup;
286
0
    }
287
288
0
    ret =
289
0
        _gnutls_buffer_append_data_prefix(data, 8, out.data,
290
0
                  out.size);
291
292
0
    _gnutls_free_datum(&out);
293
294
0
    if (ret < 0) {
295
0
      gnutls_assert();
296
0
      goto cleanup;
297
0
    }
298
0
  } else if (pk == GNUTLS_PK_ECDH_X25519 || pk == GNUTLS_PK_ECDH_X448) {
299
0
    ret =
300
0
        _gnutls_buffer_append_data_prefix(data, 8,
301
0
                  session->key.proto.
302
0
                  tls12.ecdh.params.raw_pub.
303
0
                  data,
304
0
                  session->key.proto.
305
0
                  tls12.ecdh.params.raw_pub.
306
0
                  size);
307
0
    if (ret < 0) {
308
0
      gnutls_assert();
309
0
      goto cleanup;
310
0
    }
311
0
  }
312
313
  /* generate pre-shared key */
314
0
  ret = calc_ecdh_key(session, psk_key, ecurve);
315
0
  if (ret < 0) {
316
0
    gnutls_assert();
317
0
    goto cleanup;
318
0
  }
319
320
0
  ret = data->length - init_pos;
321
0
 cleanup:
322
0
  gnutls_pk_params_clear(&session->key.proto.tls12.ecdh.params);
323
0
  return ret;
324
0
}
325
326
static int
327
proc_ecdhe_server_kx(gnutls_session_t session,
328
         uint8_t * data, size_t _data_size)
329
0
{
330
0
  int ret;
331
0
  gnutls_datum_t vparams;
332
333
0
  ret = _gnutls_proc_ecdh_common_server_kx(session, data, _data_size);
334
0
  if (ret < 0)
335
0
    return gnutls_assert_val(ret);
336
337
0
  vparams.data = data;
338
0
  vparams.size = ret;
339
340
0
  return _gnutls_proc_dhe_signature(session, data + ret,
341
0
            _data_size - ret, &vparams);
342
0
}
343
344
int
345
_gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
346
           uint8_t * data, size_t _data_size)
347
0
{
348
0
  int i, ret;
349
0
  unsigned point_size;
350
0
  const gnutls_group_entry_st *group;
351
0
  ssize_t data_size = _data_size;
352
0
  const gnutls_ecc_curve_entry_st *ecurve;
353
354
  /* just in case we are resuming a session */
355
0
  gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
356
357
0
  gnutls_pk_params_init(&session->key.proto.tls12.ecdh.params);
358
359
0
  i = 0;
360
0
  DECR_LEN(data_size, 1);
361
0
  if (data[i++] != 3)
362
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
363
364
0
  DECR_LEN(data_size, 2);
365
366
0
  group = _gnutls_tls_id_to_group(_gnutls_read_uint16(&data[i]));
367
0
  if (group == NULL || group->curve == 0) {
368
0
    _gnutls_debug_log("received unknown curve %u.%u\n",
369
0
          (unsigned)data[i], (unsigned)data[i + 1]);
370
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
371
0
  } else {
372
0
    _gnutls_debug_log("received curve %s\n", group->name);
373
0
  }
374
375
0
  i += 2;
376
377
0
  ret = _gnutls_session_supports_group(session, group->id);
378
0
  if (ret < 0)
379
0
    return gnutls_assert_val(ret);
380
381
0
  ecurve = _gnutls_ecc_curve_get_params(group->curve);
382
0
  if (ecurve == NULL) {
383
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
384
0
  }
385
386
0
  _gnutls_session_group_set(session, group);
387
388
0
  DECR_LEN(data_size, 1);
389
0
  point_size = data[i];
390
0
  i++;
391
392
0
  DECR_LEN(data_size, point_size);
393
394
0
  if (ecurve->pk == GNUTLS_PK_EC) {
395
0
    ret =
396
0
        _gnutls_ecc_ansi_x962_import(&data[i], point_size,
397
0
             &session->key.proto.tls12.
398
0
             ecdh.x,
399
0
             &session->key.proto.tls12.
400
0
             ecdh.y);
401
0
    if (ret < 0)
402
0
      return gnutls_assert_val(ret);
403
404
0
  } else if (ecurve->pk == GNUTLS_PK_ECDH_X25519 ||
405
0
       ecurve->pk == GNUTLS_PK_ECDH_X448) {
406
0
    if (ecurve->size != point_size)
407
0
      return
408
0
          gnutls_assert_val
409
0
          (GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
410
411
0
    ret = _gnutls_set_datum(&session->key.proto.tls12.ecdh.raw,
412
0
          &data[i], point_size);
413
0
    if (ret < 0)
414
0
      return gnutls_assert_val(ret);
415
416
    /* RFC7748 requires to mask the MSB in the final byte
417
     * for X25519 (not X448) */
418
0
    if (ecurve->id == GNUTLS_ECC_CURVE_X25519) {
419
0
      session->key.proto.tls12.ecdh.raw.data[point_size -
420
0
                     1] &= 0x7f;
421
0
    }
422
0
  } else {
423
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
424
0
  }
425
426
0
  i += point_size;
427
428
0
  return i;
429
0
}
430
431
/* If the psk flag is set, then an empty psk_identity_hint will
432
 * be inserted */
433
int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session,
434
          gnutls_buffer_st * data,
435
          const gnutls_group_entry_st * group)
436
0
{
437
0
  uint8_t p;
438
0
  int ret;
439
0
  gnutls_datum_t out;
440
0
  unsigned init_pos = data->length;
441
442
0
  if (group == NULL || group->curve == 0)
443
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
444
445
  /* just in case we are resuming a session */
446
0
  gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
447
448
0
  gnutls_pk_params_init(&session->key.proto.tls12.ecdh.params);
449
450
  /* curve type */
451
0
  p = 3;
452
453
0
  ret = _gnutls_buffer_append_data(data, &p, 1);
454
0
  if (ret < 0)
455
0
    return gnutls_assert_val(ret);
456
457
0
  ret = _gnutls_buffer_append_prefix(data, 16, group->tls_id);
458
0
  if (ret < 0)
459
0
    return gnutls_assert_val(ret);
460
461
  /* generate temporal key */
462
0
  ret =
463
0
      _gnutls_pk_generate_keys(group->pk, group->curve,
464
0
             &session->key.proto.tls12.ecdh.params, 1);
465
0
  if (ret < 0)
466
0
    return gnutls_assert_val(ret);
467
468
0
  if (group->pk == GNUTLS_PK_EC) {
469
0
    ret =
470
0
        _gnutls_ecc_ansi_x962_export(group->curve,
471
0
             session->key.proto.tls12.
472
0
             ecdh.params.
473
0
             params[ECC_X] /* x */ ,
474
0
             session->key.proto.tls12.
475
0
             ecdh.params.
476
0
             params[ECC_Y] /* y */ ,
477
0
             &out);
478
0
    if (ret < 0)
479
0
      return gnutls_assert_val(ret);
480
481
0
    ret =
482
0
        _gnutls_buffer_append_data_prefix(data, 8, out.data,
483
0
                  out.size);
484
485
0
    _gnutls_free_datum(&out);
486
487
0
    if (ret < 0)
488
0
      return gnutls_assert_val(ret);
489
490
0
  } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
491
0
       group->pk == GNUTLS_PK_ECDH_X448) {
492
0
    ret =
493
0
        _gnutls_buffer_append_data_prefix(data, 8,
494
0
                  session->key.proto.
495
0
                  tls12.ecdh.params.raw_pub.
496
0
                  data,
497
0
                  session->key.proto.
498
0
                  tls12.ecdh.params.raw_pub.
499
0
                  size);
500
0
    if (ret < 0)
501
0
      return gnutls_assert_val(ret);
502
0
  } else {
503
0
    return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
504
0
  }
505
506
0
  return data->length - init_pos;
507
0
}
508
509
static int
510
gen_ecdhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
511
0
{
512
0
  int ret = 0;
513
0
  gnutls_certificate_credentials_t cred;
514
0
  unsigned sig_pos;
515
516
0
  cred = (gnutls_certificate_credentials_t)
517
0
      _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
518
0
  if (cred == NULL) {
519
0
    gnutls_assert();
520
0
    return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
521
0
  }
522
523
0
  if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
524
0
            sizeof(cert_auth_info_st), 1)) < 0) {
525
0
    gnutls_assert();
526
0
    return ret;
527
0
  }
528
529
0
  sig_pos = data->length;
530
531
0
  ret =
532
0
      _gnutls_ecdh_common_print_server_kx(session, data,
533
0
            get_group(session));
534
0
  if (ret < 0) {
535
0
    gnutls_assert();
536
0
    return ret;
537
0
  }
538
539
  /* Generate the signature. */
540
0
  return _gnutls_gen_dhe_signature(session, data, &data->data[sig_pos],
541
0
           data->length - sig_pos);
542
0
}
543
544
#endif