Coverage Report

Created: 2026-08-14 06:46

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