Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/dh-session.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2015 Free Software Foundation, Inc.
3
 * Copyright (C) 2015 Nikos Mavrogiannopoulos
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 certificate authentication functions to be exported in the
25
 * API which did not fit elsewhere.
26
 */
27
28
#include "gnutls_int.h"
29
#include "auth/srp_kx.h"
30
#include "auth/anon.h"
31
#include "auth/cert.h"
32
#include "auth/psk.h"
33
#include "errors.h"
34
#include "auth.h"
35
#include "state.h"
36
#include "datum.h"
37
#include "algorithms.h"
38
39
/* ANON & DHE */
40
41
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
42
/**
43
 * gnutls_dh_set_prime_bits:
44
 * @session: is a #gnutls_session_t type.
45
 * @bits: is the number of bits
46
 *
47
 * This function sets the number of bits, for use in a Diffie-Hellman
48
 * key exchange.  This is used both in DH ephemeral and DH anonymous
49
 * cipher suites.  This will set the minimum size of the prime that
50
 * will be used for the handshake.
51
 *
52
 * In the client side it sets the minimum accepted number of bits.  If
53
 * a server sends a prime with less bits than that
54
 * %GNUTLS_E_DH_PRIME_UNACCEPTABLE will be returned by the handshake.
55
 *
56
 * Note that this function will warn via the audit log for value that
57
 * are believed to be weak.
58
 *
59
 * The function has no effect in server side.
60
 * 
61
 * Note that since 3.1.7 this function is deprecated. The minimum
62
 * number of bits is set by the priority string level.
63
 * Also this function must be called after gnutls_priority_set_direct()
64
 * or the set value may be overridden by the selected priority options.
65
 *
66
 *
67
 **/
68
void gnutls_dh_set_prime_bits(gnutls_session_t session, unsigned int bits)
69
0
{
70
0
  if (bits < gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
71
0
                 GNUTLS_SEC_PARAM_WEAK) &&
72
0
      bits != 0)
73
0
    _gnutls_audit_log(
74
0
      session,
75
0
      "Note that the security level of the Diffie-Hellman key exchange has been lowered to %u bits and this may allow decryption of the session data\n",
76
0
      bits);
77
0
  session->internals.dh_prime_bits = bits;
78
0
}
79
80
/**
81
 * gnutls_dh_get_group:
82
 * @session: is a gnutls session
83
 * @raw_gen: will hold the generator.
84
 * @raw_prime: will hold the prime.
85
 *
86
 * This function will return the group parameters used in the last
87
 * Diffie-Hellman key exchange with the peer.  These are the prime and
88
 * the generator used.  This function should be used for both
89
 * anonymous and ephemeral Diffie-Hellman.  The output parameters must
90
 * be freed with gnutls_free().
91
 *
92
 * Note, that the prime and generator are exported as non-negative
93
 * integers and may include a leading zero byte.
94
 *
95
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
96
 *   an error code is returned.
97
 **/
98
int gnutls_dh_get_group(gnutls_session_t session, gnutls_datum_t *raw_gen,
99
      gnutls_datum_t *raw_prime)
100
0
{
101
0
  dh_info_st *dh;
102
0
  int ret;
103
0
  anon_auth_info_t anon_info;
104
0
  cert_auth_info_t cert_info;
105
0
  psk_auth_info_t psk_info;
106
107
0
  switch (gnutls_auth_get_type(session)) {
108
0
  case GNUTLS_CRD_ANON:
109
0
    anon_info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
110
0
    if (anon_info == NULL)
111
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
112
0
    dh = &anon_info->dh;
113
0
    break;
114
0
  case GNUTLS_CRD_PSK:
115
0
    psk_info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
116
0
    if (psk_info == NULL)
117
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
118
0
    dh = &psk_info->dh;
119
0
    break;
120
0
  case GNUTLS_CRD_CERTIFICATE:
121
0
    cert_info =
122
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
123
0
    if (cert_info == NULL)
124
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
125
0
    dh = &cert_info->dh;
126
0
    break;
127
0
  default:
128
0
    gnutls_assert();
129
0
    return GNUTLS_E_INVALID_REQUEST;
130
0
  }
131
132
0
  ret = _gnutls_set_datum(raw_prime, dh->prime.data, dh->prime.size);
133
0
  if (ret < 0) {
134
0
    gnutls_assert();
135
0
    return ret;
136
0
  }
137
138
0
  ret = _gnutls_set_datum(raw_gen, dh->generator.data,
139
0
        dh->generator.size);
140
0
  if (ret < 0) {
141
0
    gnutls_assert();
142
0
    _gnutls_free_datum(raw_prime);
143
0
    return ret;
144
0
  }
145
146
0
  return 0;
147
0
}
148
149
/**
150
 * gnutls_dh_get_pubkey:
151
 * @session: is a gnutls session
152
 * @raw_key: will hold the public key.
153
 *
154
 * This function will return the peer's public key used in the last
155
 * Diffie-Hellman key exchange.  This function should be used for both
156
 * anonymous and ephemeral Diffie-Hellman.  The output parameters must
157
 * be freed with gnutls_free().
158
 *
159
 * Note, that public key is exported as non-negative
160
 * integer and may include a leading zero byte.
161
 *
162
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
163
 *   an error code is returned.
164
 **/
165
int gnutls_dh_get_pubkey(gnutls_session_t session, gnutls_datum_t *raw_key)
166
0
{
167
0
  dh_info_st *dh;
168
0
  anon_auth_info_t anon_info;
169
0
  cert_auth_info_t cert_info;
170
0
  psk_auth_info_t psk_info;
171
172
0
  switch (gnutls_auth_get_type(session)) {
173
0
  case GNUTLS_CRD_ANON: {
174
0
    anon_info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
175
0
    if (anon_info == NULL)
176
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
177
0
    dh = &anon_info->dh;
178
0
    break;
179
0
  }
180
0
  case GNUTLS_CRD_PSK: {
181
0
    psk_info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
182
0
    if (psk_info == NULL)
183
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
184
0
    dh = &psk_info->dh;
185
0
    break;
186
0
  }
187
0
  case GNUTLS_CRD_CERTIFICATE: {
188
0
    cert_info =
189
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
190
0
    if (cert_info == NULL)
191
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
192
0
    dh = &cert_info->dh;
193
0
    break;
194
0
  }
195
0
  default:
196
0
    gnutls_assert();
197
0
    return GNUTLS_E_INVALID_REQUEST;
198
0
  }
199
200
0
  return _gnutls_set_datum(raw_key, dh->public_key.data,
201
0
         dh->public_key.size);
202
0
}
203
204
/**
205
 * gnutls_dh_get_secret_bits:
206
 * @session: is a gnutls session
207
 *
208
 * This function will return the bits used in the last Diffie-Hellman
209
 * key exchange with the peer.  Should be used for both anonymous and
210
 * ephemeral Diffie-Hellman.
211
 *
212
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
213
 *   an error code is returned.
214
 **/
215
int gnutls_dh_get_secret_bits(gnutls_session_t session)
216
0
{
217
0
  switch (gnutls_auth_get_type(session)) {
218
0
  case GNUTLS_CRD_ANON: {
219
0
    anon_auth_info_t info;
220
221
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
222
0
    if (info == NULL)
223
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
224
0
    return info->dh.secret_bits;
225
0
  }
226
0
  case GNUTLS_CRD_PSK: {
227
0
    psk_auth_info_t info;
228
229
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
230
0
    if (info == NULL)
231
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
232
0
    return info->dh.secret_bits;
233
0
  }
234
0
  case GNUTLS_CRD_CERTIFICATE: {
235
0
    cert_auth_info_t info;
236
237
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
238
0
    if (info == NULL)
239
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
240
241
0
    return info->dh.secret_bits;
242
0
  }
243
0
  default:
244
0
    gnutls_assert();
245
0
    return GNUTLS_E_INVALID_REQUEST;
246
0
  }
247
0
}
248
249
static int mpi_buf2bits(gnutls_datum_t *mpi_buf)
250
0
{
251
0
  bigint_t mpi;
252
0
  int rc;
253
254
0
  rc = _gnutls_mpi_init_scan_nz(&mpi, mpi_buf->data, mpi_buf->size);
255
0
  if (rc) {
256
0
    gnutls_assert();
257
0
    return rc;
258
0
  }
259
260
0
  rc = _gnutls_mpi_get_nbits(mpi);
261
0
  _gnutls_mpi_release(&mpi);
262
263
0
  return rc;
264
0
}
265
266
/**
267
 * gnutls_dh_get_prime_bits:
268
 * @session: is a gnutls session
269
 *
270
 * This function will return the bits of the prime used in the last
271
 * Diffie-Hellman key exchange with the peer.  Should be used for both
272
 * anonymous and ephemeral Diffie-Hellman.  Note that some ciphers,
273
 * like RSA and DSA without DHE, do not use a Diffie-Hellman key
274
 * exchange, and then this function will return 0.
275
 *
276
 * Returns: The Diffie-Hellman bit strength is returned, or 0 if no
277
 *   Diffie-Hellman key exchange was done, or a negative error code on
278
 *   failure.
279
 **/
280
int gnutls_dh_get_prime_bits(gnutls_session_t session)
281
0
{
282
0
  dh_info_st *dh;
283
284
0
  switch (gnutls_auth_get_type(session)) {
285
0
  case GNUTLS_CRD_ANON: {
286
0
    anon_auth_info_t info;
287
288
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
289
0
    if (info == NULL)
290
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
291
0
    dh = &info->dh;
292
0
    break;
293
0
  }
294
0
  case GNUTLS_CRD_PSK: {
295
0
    psk_auth_info_t info;
296
297
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
298
0
    if (info == NULL)
299
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
300
0
    dh = &info->dh;
301
0
    break;
302
0
  }
303
0
  case GNUTLS_CRD_CERTIFICATE: {
304
0
    cert_auth_info_t info;
305
306
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
307
0
    if (info == NULL)
308
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
309
310
0
    dh = &info->dh;
311
0
    break;
312
0
  }
313
0
  default:
314
0
    gnutls_assert();
315
0
    return GNUTLS_E_INVALID_REQUEST;
316
0
  }
317
318
0
  if (dh->prime.size == 0)
319
0
    return 0;
320
321
0
  return mpi_buf2bits(&dh->prime);
322
0
}
323
324
/**
325
 * gnutls_dh_get_peers_public_bits:
326
 * @session: is a gnutls session
327
 *
328
 * Get the Diffie-Hellman public key bit size.  Can be used for both
329
 * anonymous and ephemeral Diffie-Hellman.
330
 *
331
 * Returns: The public key bit size used in the last Diffie-Hellman
332
 *   key exchange with the peer, or a negative error code in case of error.
333
 **/
334
int gnutls_dh_get_peers_public_bits(gnutls_session_t session)
335
0
{
336
0
  dh_info_st *dh;
337
338
0
  switch (gnutls_auth_get_type(session)) {
339
0
  case GNUTLS_CRD_ANON: {
340
0
    anon_auth_info_t info;
341
342
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
343
0
    if (info == NULL)
344
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
345
346
0
    dh = &info->dh;
347
0
    break;
348
0
  }
349
0
  case GNUTLS_CRD_PSK: {
350
0
    psk_auth_info_t info;
351
352
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
353
0
    if (info == NULL)
354
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
355
356
0
    dh = &info->dh;
357
0
    break;
358
0
  }
359
0
  case GNUTLS_CRD_CERTIFICATE: {
360
0
    cert_auth_info_t info;
361
362
0
    info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
363
0
    if (info == NULL)
364
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
365
366
0
    dh = &info->dh;
367
0
    break;
368
0
  }
369
0
  default:
370
0
    gnutls_assert();
371
0
    return GNUTLS_E_INVALID_REQUEST;
372
0
  }
373
374
0
  return mpi_buf2bits(&dh->public_key);
375
0
}
376
377
#endif /* DH */