Coverage Report

Created: 2023-03-26 07:33

/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 <
71
0
      gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_WEAK)
72
0
      && bits != 0)
73
0
    _gnutls_audit_log(session,
74
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",
75
0
          bits);
76
0
  session->internals.dh_prime_bits = bits;
77
0
}
78
79
/**
80
 * gnutls_dh_get_group:
81
 * @session: is a gnutls session
82
 * @raw_gen: will hold the generator.
83
 * @raw_prime: will hold the prime.
84
 *
85
 * This function will return the group parameters used in the last
86
 * Diffie-Hellman key exchange with the peer.  These are the prime and
87
 * the generator used.  This function should be used for both
88
 * anonymous and ephemeral Diffie-Hellman.  The output parameters must
89
 * be freed with gnutls_free().
90
 *
91
 * Note, that the prime and generator are exported as non-negative
92
 * integers and may include a leading zero byte.
93
 *
94
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
95
 *   an error code is returned.
96
 **/
97
int
98
gnutls_dh_get_group(gnutls_session_t session,
99
        gnutls_datum_t * raw_gen, 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 =
139
0
      _gnutls_set_datum(raw_gen, dh->generator.data, 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
    {
175
0
      anon_info =
176
0
          _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
177
0
      if (anon_info == NULL)
178
0
        return
179
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
180
0
      dh = &anon_info->dh;
181
0
      break;
182
0
    }
183
0
  case GNUTLS_CRD_PSK:
184
0
    {
185
0
      psk_info =
186
0
          _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
187
0
      if (psk_info == NULL)
188
0
        return
189
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
190
0
      dh = &psk_info->dh;
191
0
      break;
192
0
    }
193
0
  case GNUTLS_CRD_CERTIFICATE:
194
0
    {
195
196
0
      cert_info =
197
0
          _gnutls_get_auth_info(session,
198
0
              GNUTLS_CRD_CERTIFICATE);
199
0
      if (cert_info == NULL)
200
0
        return
201
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
202
0
      dh = &cert_info->dh;
203
0
      break;
204
0
    }
205
0
  default:
206
0
    gnutls_assert();
207
0
    return GNUTLS_E_INVALID_REQUEST;
208
0
  }
209
210
0
  return _gnutls_set_datum(raw_key, dh->public_key.data,
211
0
         dh->public_key.size);
212
0
}
213
214
/**
215
 * gnutls_dh_get_secret_bits:
216
 * @session: is a gnutls session
217
 *
218
 * This function will return the bits used in the last Diffie-Hellman
219
 * key exchange with the peer.  Should be used for both anonymous and
220
 * ephemeral Diffie-Hellman.
221
 *
222
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
223
 *   an error code is returned.
224
 **/
225
int gnutls_dh_get_secret_bits(gnutls_session_t session)
226
0
{
227
0
  switch (gnutls_auth_get_type(session)) {
228
0
  case GNUTLS_CRD_ANON:
229
0
    {
230
0
      anon_auth_info_t info;
231
232
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
233
0
      if (info == NULL)
234
0
        return
235
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
236
0
      return info->dh.secret_bits;
237
0
    }
238
0
  case GNUTLS_CRD_PSK:
239
0
    {
240
0
      psk_auth_info_t info;
241
242
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
243
0
      if (info == NULL)
244
0
        return
245
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
246
0
      return info->dh.secret_bits;
247
0
    }
248
0
  case GNUTLS_CRD_CERTIFICATE:
249
0
    {
250
0
      cert_auth_info_t info;
251
252
0
      info =
253
0
          _gnutls_get_auth_info(session,
254
0
              GNUTLS_CRD_CERTIFICATE);
255
0
      if (info == NULL)
256
0
        return
257
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
258
259
0
      return info->dh.secret_bits;
260
0
    }
261
0
  default:
262
0
    gnutls_assert();
263
0
    return GNUTLS_E_INVALID_REQUEST;
264
0
  }
265
0
}
266
267
static int mpi_buf2bits(gnutls_datum_t * mpi_buf)
268
0
{
269
0
  bigint_t mpi;
270
0
  int rc;
271
272
0
  rc = _gnutls_mpi_init_scan_nz(&mpi, mpi_buf->data, mpi_buf->size);
273
0
  if (rc) {
274
0
    gnutls_assert();
275
0
    return rc;
276
0
  }
277
278
0
  rc = _gnutls_mpi_get_nbits(mpi);
279
0
  _gnutls_mpi_release(&mpi);
280
281
0
  return rc;
282
0
}
283
284
/**
285
 * gnutls_dh_get_prime_bits:
286
 * @session: is a gnutls session
287
 *
288
 * This function will return the bits of the prime used in the last
289
 * Diffie-Hellman key exchange with the peer.  Should be used for both
290
 * anonymous and ephemeral Diffie-Hellman.  Note that some ciphers,
291
 * like RSA and DSA without DHE, do not use a Diffie-Hellman key
292
 * exchange, and then this function will return 0.
293
 *
294
 * Returns: The Diffie-Hellman bit strength is returned, or 0 if no
295
 *   Diffie-Hellman key exchange was done, or a negative error code on
296
 *   failure.
297
 **/
298
int gnutls_dh_get_prime_bits(gnutls_session_t session)
299
0
{
300
0
  dh_info_st *dh;
301
302
0
  switch (gnutls_auth_get_type(session)) {
303
0
  case GNUTLS_CRD_ANON:
304
0
    {
305
0
      anon_auth_info_t info;
306
307
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
308
0
      if (info == NULL)
309
0
        return
310
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
311
0
      dh = &info->dh;
312
0
      break;
313
0
    }
314
0
  case GNUTLS_CRD_PSK:
315
0
    {
316
0
      psk_auth_info_t info;
317
318
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
319
0
      if (info == NULL)
320
0
        return
321
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
322
0
      dh = &info->dh;
323
0
      break;
324
0
    }
325
0
  case GNUTLS_CRD_CERTIFICATE:
326
0
    {
327
0
      cert_auth_info_t info;
328
329
0
      info =
330
0
          _gnutls_get_auth_info(session,
331
0
              GNUTLS_CRD_CERTIFICATE);
332
0
      if (info == NULL)
333
0
        return
334
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
335
336
0
      dh = &info->dh;
337
0
      break;
338
0
    }
339
0
  default:
340
0
    gnutls_assert();
341
0
    return GNUTLS_E_INVALID_REQUEST;
342
0
  }
343
344
0
  if (dh->prime.size == 0)
345
0
    return 0;
346
347
0
  return mpi_buf2bits(&dh->prime);
348
0
}
349
350
/**
351
 * gnutls_dh_get_peers_public_bits:
352
 * @session: is a gnutls session
353
 *
354
 * Get the Diffie-Hellman public key bit size.  Can be used for both
355
 * anonymous and ephemeral Diffie-Hellman.
356
 *
357
 * Returns: The public key bit size used in the last Diffie-Hellman
358
 *   key exchange with the peer, or a negative error code in case of error.
359
 **/
360
int gnutls_dh_get_peers_public_bits(gnutls_session_t session)
361
0
{
362
0
  dh_info_st *dh;
363
364
0
  switch (gnutls_auth_get_type(session)) {
365
0
  case GNUTLS_CRD_ANON:
366
0
    {
367
0
      anon_auth_info_t info;
368
369
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
370
0
      if (info == NULL)
371
0
        return
372
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
373
374
0
      dh = &info->dh;
375
0
      break;
376
0
    }
377
0
  case GNUTLS_CRD_PSK:
378
0
    {
379
0
      psk_auth_info_t info;
380
381
0
      info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
382
0
      if (info == NULL)
383
0
        return
384
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
385
386
0
      dh = &info->dh;
387
0
      break;
388
0
    }
389
0
  case GNUTLS_CRD_CERTIFICATE:
390
0
    {
391
0
      cert_auth_info_t info;
392
393
0
      info =
394
0
          _gnutls_get_auth_info(session,
395
0
              GNUTLS_CRD_CERTIFICATE);
396
0
      if (info == NULL)
397
0
        return
398
0
            gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
399
400
0
      dh = &info->dh;
401
0
      break;
402
0
    }
403
0
  default:
404
0
    gnutls_assert();
405
0
    return GNUTLS_E_INVALID_REQUEST;
406
0
  }
407
408
0
  return mpi_buf2bits(&dh->public_key);
409
0
}
410
411
#endif        /* DH */