Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/auth/dh_common.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2002-2012 Free Software Foundation, 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 common stuff in Ephemeral Diffie-Hellman (DHE)
24
 * and Anonymous DH key exchange(DHA). These are used in the handshake
25
 * procedure of the certificate and anonymous authentication.
26
 */
27
28
#include "gnutls_int.h"
29
#include "auth.h"
30
#include "errors.h"
31
#include "dh.h"
32
#include "num.h"
33
#include "tls-sig.h"
34
#include "datum.h"
35
#include "x509.h"
36
#include "state.h"
37
#include "pk.h"
38
#include "auth/dh_common.h"
39
#include "algorithms.h"
40
#include "auth/psk.h"
41
42
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
43
44
/* Frees the dh_info_st structure.
45
 */
46
void _gnutls_free_dh_info(dh_info_st *dh)
47
0
{
48
0
  dh->secret_bits = 0;
49
0
  _gnutls_free_datum(&dh->prime);
50
0
  _gnutls_free_datum(&dh->generator);
51
0
  _gnutls_free_datum(&dh->public_key);
52
0
}
53
54
int _gnutls_proc_dh_common_client_kx(gnutls_session_t session, uint8_t *data,
55
             size_t _data_size, gnutls_datum_t *psk_key)
56
0
{
57
0
  uint16_t n_Y;
58
0
  size_t _n_Y;
59
0
  int ret;
60
0
  ssize_t data_size = _data_size;
61
0
  gnutls_datum_t tmp_dh_key = { NULL, 0 };
62
0
  gnutls_pk_params_st peer_pub;
63
64
0
  gnutls_pk_params_init(&peer_pub);
65
66
0
  DECR_LEN(data_size, 2);
67
0
  n_Y = _gnutls_read_uint16(&data[0]);
68
0
  _n_Y = n_Y;
69
70
0
  DECR_LEN(data_size, n_Y);
71
72
0
  if (data_size != 0)
73
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
74
75
0
  if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.client_Y,
76
0
             &data[2], _n_Y)) {
77
0
    gnutls_assert();
78
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; /* most likely zero or illegal size */
79
0
  }
80
81
0
  _gnutls_dh_set_peer_public(session,
82
0
           session->key.proto.tls12.dh.client_Y);
83
84
0
  peer_pub.params[DH_Y] = session->key.proto.tls12.dh.client_Y;
85
86
  /* calculate the key after calculating the message */
87
0
  ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key,
88
0
        &session->key.proto.tls12.dh.params, &peer_pub);
89
0
  if (ret < 0) {
90
0
    gnutls_assert();
91
0
    goto error;
92
0
  }
93
94
0
  if (psk_key == NULL) {
95
0
    session->key.key.data = tmp_dh_key.data;
96
0
    session->key.key.size = tmp_dh_key.size;
97
0
  } else { /* In DHE_PSK the key is set differently */
98
0
    ret = _gnutls_set_psk_session_key(session, psk_key,
99
0
              &tmp_dh_key);
100
0
    _gnutls_free_temp_key_datum(&tmp_dh_key);
101
0
  }
102
103
0
  if (ret < 0) {
104
0
    gnutls_assert();
105
0
    goto error;
106
0
  }
107
108
0
  ret = 0;
109
0
error:
110
0
  _gnutls_mpi_release(&session->key.proto.tls12.dh.client_Y);
111
0
  gnutls_pk_params_clear(&session->key.proto.tls12.dh.params);
112
113
0
  return ret;
114
0
}
115
116
int _gnutls_gen_dh_common_client_kx(gnutls_session_t session,
117
            gnutls_buffer_st *data)
118
0
{
119
0
  return _gnutls_gen_dh_common_client_kx_int(session, data, NULL);
120
0
}
121
122
int _gnutls_gen_dh_common_client_kx_int(gnutls_session_t session,
123
          gnutls_buffer_st *data,
124
          gnutls_datum_t *pskkey)
125
0
{
126
0
  int ret;
127
0
  gnutls_pk_params_st peer_pub;
128
0
  gnutls_datum_t tmp_dh_key = { NULL, 0 };
129
0
  unsigned init_pos = data->length;
130
131
0
  gnutls_pk_params_init(&peer_pub);
132
133
0
  ret = _gnutls_pk_generate_keys(GNUTLS_PK_DH, 0,
134
0
               &session->key.proto.tls12.dh.params, 1);
135
0
  if (ret < 0)
136
0
    return gnutls_assert_val(ret);
137
138
0
  _gnutls_dh_set_secret_bits(
139
0
    session,
140
0
    _gnutls_mpi_get_nbits(
141
0
      session->key.proto.tls12.dh.params.params[DH_X]));
142
143
0
  ret = _gnutls_buffer_append_mpi(
144
0
    data, 16, session->key.proto.tls12.dh.params.params[DH_Y], 0);
145
0
  if (ret < 0) {
146
0
    gnutls_assert();
147
0
    goto error;
148
0
  }
149
150
0
  peer_pub.params[DH_Y] = session->key.proto.tls12.dh.client_Y;
151
152
  /* calculate the key after calculating the message */
153
0
  ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key,
154
0
        &session->key.proto.tls12.dh.params, &peer_pub);
155
0
  if (ret < 0) {
156
0
    gnutls_assert();
157
0
    goto error;
158
0
  }
159
160
0
  if (session->security_parameters.cs->kx_algorithm !=
161
0
      GNUTLS_KX_DHE_PSK) {
162
0
    session->key.key.data = tmp_dh_key.data;
163
0
    session->key.key.size = tmp_dh_key.size;
164
0
  } else { /* In DHE_PSK the key is set differently */
165
0
    ret = _gnutls_set_psk_session_key(session, pskkey, &tmp_dh_key);
166
0
    _gnutls_free_temp_key_datum(&tmp_dh_key);
167
0
  }
168
169
0
  if (ret < 0) {
170
0
    gnutls_assert();
171
0
    goto error;
172
0
  }
173
174
0
  ret = data->length - init_pos;
175
176
0
error:
177
0
  gnutls_pk_params_clear(&session->key.proto.tls12.dh.params);
178
0
  return ret;
179
0
}
180
181
/* Returns the bytes parsed */
182
int _gnutls_proc_dh_common_server_kx(gnutls_session_t session, uint8_t *data,
183
             size_t _data_size)
184
0
{
185
0
  uint16_t n_Y, n_g, n_p;
186
0
  size_t _n_Y, _n_g, _n_p, _n_q;
187
0
  uint8_t *data_p;
188
0
  uint8_t *data_g;
189
0
  uint8_t *data_Y;
190
0
  uint8_t *data_q = NULL;
191
0
  int i, bits, ret, p_bits;
192
0
  unsigned j;
193
0
  ssize_t data_size = _data_size;
194
195
  /* just in case we are resuming a session */
196
0
  gnutls_pk_params_release(&session->key.proto.tls12.dh.params);
197
198
0
  gnutls_pk_params_init(&session->key.proto.tls12.dh.params);
199
200
0
  i = 0;
201
202
0
  DECR_LEN(data_size, 2);
203
0
  n_p = _gnutls_read_uint16(&data[i]);
204
0
  i += 2;
205
206
0
  DECR_LEN(data_size, n_p);
207
0
  data_p = &data[i];
208
0
  i += n_p;
209
210
0
  DECR_LEN(data_size, 2);
211
0
  n_g = _gnutls_read_uint16(&data[i]);
212
0
  i += 2;
213
214
0
  DECR_LEN(data_size, n_g);
215
0
  data_g = &data[i];
216
0
  i += n_g;
217
218
0
  DECR_LEN(data_size, 2);
219
0
  n_Y = _gnutls_read_uint16(&data[i]);
220
0
  i += 2;
221
222
0
  DECR_LEN(data_size, n_Y);
223
0
  data_Y = &data[i];
224
225
0
  _n_Y = n_Y;
226
0
  _n_g = n_g;
227
0
  _n_p = n_p;
228
229
0
  if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.client_Y,
230
0
             data_Y, _n_Y) != 0) {
231
0
    gnutls_assert();
232
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
233
0
  }
234
235
  /* if we are doing RFC7919 */
236
0
  if (session->internals.priorities->groups.have_ffdhe != 0) {
237
    /* verify whether the received parameters match the advertised, otherwise
238
     * log that. */
239
0
    for (j = 0; j < session->internals.priorities->groups.size;
240
0
         j++) {
241
0
      if (session->internals.priorities->groups.entry[j]
242
0
            ->generator &&
243
0
          session->internals.priorities->groups.entry[j]
244
0
              ->generator->size == n_g &&
245
0
          session->internals.priorities->groups.entry[j]
246
0
              ->prime->size == n_p &&
247
0
          memcmp(session->internals.priorities->groups
248
0
             .entry[j]
249
0
             ->generator->data,
250
0
           data_g, n_g) == 0 &&
251
0
          memcmp(session->internals.priorities->groups
252
0
             .entry[j]
253
0
             ->prime->data,
254
0
           data_p, n_p) == 0) {
255
0
        session->internals.hsk_flags |= HSK_USED_FFDHE;
256
0
        _gnutls_session_group_set(
257
0
          session, session->internals.priorities
258
0
               ->groups.entry[j]);
259
0
        session->key.proto.tls12.dh.params.qbits =
260
0
          *session->internals.priorities->groups
261
0
             .entry[j]
262
0
             ->q_bits;
263
0
        data_q = session->internals.priorities->groups
264
0
             .entry[j]
265
0
             ->q->data;
266
0
        _n_q = session->internals.priorities->groups
267
0
                 .entry[j]
268
0
                 ->q->size;
269
0
        break;
270
0
      }
271
0
    }
272
273
0
    if (!(session->internals.hsk_flags & HSK_USED_FFDHE)) {
274
0
      _gnutls_audit_log(
275
0
        session,
276
0
        "FFDHE groups advertised, but server didn't support it; falling back to server's choice\n");
277
0
    }
278
0
  }
279
#ifdef ENABLE_FIPS140
280
  if (gnutls_fips140_mode_enabled() &&
281
      !_gnutls_dh_prime_match_fips_approved(data_p, n_p, data_g, n_g,
282
              NULL, NULL)) {
283
    gnutls_assert();
284
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
285
  }
286
#endif
287
288
0
  if (_gnutls_mpi_init_scan_nz(
289
0
        &session->key.proto.tls12.dh.params.params[DH_G], data_g,
290
0
        _n_g) != 0) {
291
0
    gnutls_assert();
292
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
293
0
  }
294
295
0
  if (_gnutls_mpi_init_scan_nz(
296
0
        &session->key.proto.tls12.dh.params.params[DH_P], data_p,
297
0
        _n_p) != 0) {
298
0
    gnutls_assert();
299
    /* we release now because session->key.proto.tls12.dh.params.params_nr is not yet set */
300
0
    _gnutls_mpi_release(
301
0
      &session->key.proto.tls12.dh.params.params[DH_G]);
302
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
303
0
  }
304
0
  if (data_q && _gnutls_mpi_init_scan_nz(
305
0
            &session->key.proto.tls12.dh.params.params[DH_Q],
306
0
            data_q, _n_q) != 0) {
307
    /* we release now because params_nr is not yet set */
308
0
    _gnutls_mpi_release(
309
0
      &session->key.proto.tls12.dh.params.params[DH_P]);
310
0
    _gnutls_mpi_release(
311
0
      &session->key.proto.tls12.dh.params.params[DH_G]);
312
0
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
313
0
  }
314
315
  /* include, possibly empty, q */
316
0
  session->key.proto.tls12.dh.params.params_nr = 3;
317
0
  session->key.proto.tls12.dh.params.algo = GNUTLS_PK_DH;
318
319
0
  if (!(session->internals.hsk_flags & HSK_USED_FFDHE)) {
320
0
    bits = _gnutls_dh_get_min_prime_bits(session);
321
0
    if (bits < 0) {
322
0
      gnutls_assert();
323
0
      return bits;
324
0
    }
325
326
0
    p_bits = _gnutls_mpi_get_nbits(
327
0
      session->key.proto.tls12.dh.params.params[DH_P]);
328
0
    if (p_bits < bits) {
329
      /* the prime used by the peer is not acceptable
330
       */
331
0
      gnutls_assert();
332
0
      _gnutls_debug_log(
333
0
        "Received a prime of %u bits, limit is %u\n",
334
0
        (unsigned)_gnutls_mpi_get_nbits(
335
0
          session->key.proto.tls12.dh.params
336
0
            .params[DH_P]),
337
0
        (unsigned)bits);
338
0
      return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
339
0
    }
340
341
0
    if (p_bits >= DEFAULT_MAX_VERIFY_BITS) {
342
0
      gnutls_assert();
343
0
      _gnutls_debug_log(
344
0
        "Received a prime of %u bits, limit is %u\n",
345
0
        (unsigned)p_bits,
346
0
        (unsigned)DEFAULT_MAX_VERIFY_BITS);
347
0
      return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
348
0
    }
349
0
  }
350
351
0
  _gnutls_dh_save_group(session,
352
0
            session->key.proto.tls12.dh.params.params[DH_G],
353
0
            session->key.proto.tls12.dh.params.params[DH_P]);
354
0
  _gnutls_dh_set_peer_public(session,
355
0
           session->key.proto.tls12.dh.client_Y);
356
357
0
  ret = n_Y + n_p + n_g + 6;
358
359
0
  return ret;
360
0
}
361
362
int _gnutls_dh_common_print_server_kx(gnutls_session_t session,
363
              gnutls_buffer_st *data)
364
0
{
365
0
  int ret;
366
0
  unsigned q_bits = session->key.proto.tls12.dh.params.qbits;
367
0
  unsigned init_pos = data->length;
368
369
0
  if (q_bits < 192 && q_bits != 0) {
370
0
    gnutls_assert();
371
0
    _gnutls_debug_log("too small q_bits value for DH: %u\n",
372
0
          q_bits);
373
0
    q_bits = 0; /* auto-detect */
374
0
  }
375
376
  /* Y=g^x mod p */
377
0
  ret = _gnutls_pk_generate_keys(GNUTLS_PK_DH, q_bits,
378
0
               &session->key.proto.tls12.dh.params, 1);
379
0
  if (ret < 0)
380
0
    return gnutls_assert_val(ret);
381
382
0
  _gnutls_dh_set_secret_bits(
383
0
    session,
384
0
    _gnutls_mpi_get_nbits(
385
0
      session->key.proto.tls12.dh.params.params[DH_X]));
386
387
0
  ret = _gnutls_buffer_append_mpi(
388
0
    data, 16, session->key.proto.tls12.dh.params.params[DH_P], 0);
389
0
  if (ret < 0) {
390
0
    gnutls_assert();
391
0
    goto cleanup;
392
0
  }
393
394
0
  ret = _gnutls_buffer_append_mpi(
395
0
    data, 16, session->key.proto.tls12.dh.params.params[DH_G], 0);
396
0
  if (ret < 0) {
397
0
    gnutls_assert();
398
0
    goto cleanup;
399
0
  }
400
401
0
  ret = _gnutls_buffer_append_mpi(
402
0
    data, 16, session->key.proto.tls12.dh.params.params[DH_Y], 0);
403
0
  if (ret < 0) {
404
0
    gnutls_assert();
405
0
    goto cleanup;
406
0
  }
407
408
0
  ret = data->length - init_pos;
409
410
0
cleanup:
411
0
  return ret;
412
0
}
413
414
#endif