Coverage Report

Created: 2025-12-31 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/auth.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2001-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
#include "gnutls_int.h"
25
#include "errors.h"
26
#include "auth.h"
27
#include "auth.h"
28
#include "algorithms.h"
29
#include "auth/cert.h"
30
#include "auth/psk.h"
31
#include "auth/srp_kx.h"
32
#include "auth/anon.h"
33
#include "datum.h"
34
35
/* The functions here are used in order for authentication algorithms
36
 * to be able to retrieve the needed credentials eg public and private
37
 * key etc.
38
 */
39
40
/**
41
 * gnutls_credentials_clear:
42
 * @session: is a #gnutls_session_t type.
43
 *
44
 * Clears all the credentials previously set in this session.
45
 **/
46
void gnutls_credentials_clear(gnutls_session_t session)
47
0
{
48
0
  if (session->key.cred) { /* beginning of the list */
49
0
    auth_cred_st *ccred, *ncred;
50
0
    ccred = session->key.cred;
51
0
    while (ccred != NULL) {
52
0
      ncred = ccred->next;
53
0
      gnutls_free(ccred);
54
0
      ccred = ncred;
55
0
    }
56
0
    session->key.cred = NULL;
57
0
  }
58
0
}
59
60
/* 
61
 * This creates a linked list of the form:
62
 * { algorithm, credentials, pointer to next }
63
 */
64
/**
65
 * gnutls_credentials_set:
66
 * @session: is a #gnutls_session_t type.
67
 * @type: is the type of the credentials
68
 * @cred: the credentials to set
69
 *
70
 * Sets the needed credentials for the specified type.  E.g. username,
71
 * password - or public and private keys etc.  The @cred parameter is
72
 * a structure that depends on the specified @type and on the current
73
 * session (client or server). Only a single @cred may be set for
74
 * each different @type, subsequent calls with the same @type will
75
 * replace the previously set credentials.
76
 *
77
 * In order to minimize memory usage, and share credentials between
78
 * several threads gnutls keeps a pointer to @cred, and not the whole
79
 * cred structure.  Thus you will have to keep the structure allocated
80
 * until you call gnutls_deinit(), or a future call of
81
 * gnutls_credentials_set() with the same @type replaces the @cred
82
 * structure.
83
 *
84
 * For %GNUTLS_CRD_ANON, @cred should be
85
 * #gnutls_anon_client_credentials_t in case of a client.  In case of
86
 * a server it should be #gnutls_anon_server_credentials_t.
87
 *
88
 * For %GNUTLS_CRD_SRP, @cred should be #gnutls_srp_client_credentials_t
89
 * in case of a client, and #gnutls_srp_server_credentials_t, in case
90
 * of a server.
91
 *
92
 * For %GNUTLS_CRD_CERTIFICATE, @cred should be
93
 * #gnutls_certificate_credentials_t.
94
 *
95
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
96
 *   otherwise a negative error code is returned.
97
 **/
98
int gnutls_credentials_set(gnutls_session_t session,
99
         gnutls_credentials_type_t type, void *cred)
100
0
{
101
0
  auth_cred_st *ccred = NULL, *pcred = NULL;
102
0
  int exists = 0;
103
104
0
  if (session->key.cred == NULL) { /* beginning of the list */
105
106
0
    session->key.cred = gnutls_malloc(sizeof(auth_cred_st));
107
0
    if (session->key.cred == NULL)
108
0
      return GNUTLS_E_MEMORY_ERROR;
109
110
    /* copy credentials locally */
111
0
    session->key.cred->credentials = cred;
112
113
0
    session->key.cred->next = NULL;
114
0
    session->key.cred->algorithm = type;
115
0
  } else {
116
0
    ccred = session->key.cred;
117
0
    while (ccred != NULL) {
118
0
      if (ccred->algorithm == type) {
119
0
        exists = 1;
120
0
        break;
121
0
      }
122
0
      pcred = ccred;
123
0
      ccred = ccred->next;
124
0
    }
125
    /* After this, pcred is not null.
126
     */
127
128
0
    if (exists == 0) { /* new entry */
129
0
      pcred->next = gnutls_malloc(sizeof(auth_cred_st));
130
0
      if (pcred->next == NULL)
131
0
        return GNUTLS_E_MEMORY_ERROR;
132
133
0
      ccred = pcred->next;
134
135
      /* copy credentials locally */
136
0
      ccred->credentials = cred;
137
138
0
      ccred->next = NULL;
139
0
      ccred->algorithm = type;
140
0
    } else { /* modify existing entry */
141
0
      ccred->credentials = cred;
142
0
    }
143
0
  }
144
145
  /* sanity tests */
146
0
  if (type == GNUTLS_CRD_CERTIFICATE) {
147
0
    gnutls_certificate_credentials_t c = cred;
148
0
    unsigned i;
149
0
    bool allow_tls13 = 0;
150
0
    unsigned key_usage;
151
152
0
    if (c != NULL && c->ncerts != 0) {
153
0
      for (i = 0; i < c->ncerts; i++) {
154
0
        key_usage = get_key_usage(
155
0
          session,
156
0
          c->certs[i].cert_list[0].pubkey);
157
0
        if (key_usage == 0 ||
158
0
            (key_usage &
159
0
             GNUTLS_KEY_DIGITAL_SIGNATURE)) {
160
0
          allow_tls13 = 1;
161
0
          break;
162
0
        }
163
0
      }
164
165
0
      if (session->security_parameters.entity ==
166
0
            GNUTLS_SERVER &&
167
0
          !c->tls13_ok)
168
0
        allow_tls13 = 0;
169
170
0
      if (!allow_tls13) {
171
        /* to prevent the server random indicate TLS1.3 support */
172
0
        session->internals.flags |= INT_FLAG_NO_TLS13;
173
0
      }
174
0
    }
175
0
  }
176
177
0
  return 0;
178
0
}
179
180
/**
181
 * gnutls_credentials_get:
182
 * @session: is a #gnutls_session_t type.
183
 * @type: is the type of the credentials to return
184
 * @cred: will contain the credentials.
185
 *
186
 * Returns the previously provided credentials structures.
187
 *
188
 * For %GNUTLS_CRD_ANON, @cred will be
189
 * #gnutls_anon_client_credentials_t in case of a client.  In case of
190
 * a server it should be #gnutls_anon_server_credentials_t.
191
 *
192
 * For %GNUTLS_CRD_SRP, @cred will be #gnutls_srp_client_credentials_t
193
 * in case of a client, and #gnutls_srp_server_credentials_t, in case
194
 * of a server.
195
 *
196
 * For %GNUTLS_CRD_PSK, @cred will be #gnutls_psk_client_credentials_t
197
 * in case of a client, and #gnutls_psk_server_credentials_t, in case
198
 * of a server.
199
 *
200
 * For %GNUTLS_CRD_CERTIFICATE, @cred will be
201
 * #gnutls_certificate_credentials_t.
202
 *
203
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
204
 *   otherwise a negative error code is returned.
205
 *
206
 * Since: 3.3.3
207
 **/
208
int gnutls_credentials_get(gnutls_session_t session,
209
         gnutls_credentials_type_t type, void **cred)
210
0
{
211
0
  const void *_cred;
212
213
0
  _cred = _gnutls_get_cred(session, type);
214
0
  if (_cred == NULL)
215
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
216
217
0
  if (cred)
218
0
    *cred = (void *)_cred;
219
220
0
  return 0;
221
0
}
222
223
/**
224
 * gnutls_auth_get_type:
225
 * @session: is a #gnutls_session_t type.
226
 *
227
 * Returns type of credentials for the current authentication schema.
228
 * The returned information is to be used to distinguish the function used
229
 * to access authentication data.
230
 *
231
 * Eg. for CERTIFICATE ciphersuites (key exchange algorithms:
232
 * %GNUTLS_KX_RSA, %GNUTLS_KX_DHE_RSA), the same function are to be
233
 * used to access the authentication data.
234
 *
235
 * Note that on resumed sessions, this function returns the schema
236
 * used in the original session authentication.
237
 *
238
 * Returns: The type of credentials for the current authentication
239
 *   schema, a #gnutls_credentials_type_t type.
240
 **/
241
gnutls_credentials_type_t gnutls_auth_get_type(gnutls_session_t session)
242
0
{
243
0
  if (session->security_parameters.entity == GNUTLS_SERVER)
244
0
    return gnutls_auth_client_get_type(session);
245
0
  else
246
0
    return gnutls_auth_server_get_type(session);
247
0
}
248
249
/**
250
 * gnutls_auth_server_get_type:
251
 * @session: is a #gnutls_session_t type.
252
 *
253
 * Returns the type of credentials that were used for server authentication.
254
 * The returned information is to be used to distinguish the function used
255
 * to access authentication data.
256
 *
257
 * Note that on resumed sessions, this function returns the schema
258
 * used in the original session authentication.
259
 *
260
 * Returns: The type of credentials for the server authentication
261
 *   schema, a #gnutls_credentials_type_t type.
262
 **/
263
gnutls_credentials_type_t gnutls_auth_server_get_type(gnutls_session_t session)
264
0
{
265
0
  return session->security_parameters.server_auth_type;
266
0
}
267
268
/**
269
 * gnutls_auth_client_get_type:
270
 * @session: is a #gnutls_session_t type.
271
 *
272
 * Returns the type of credentials that were used for client authentication.
273
 * The returned information is to be used to distinguish the function used
274
 * to access authentication data.
275
 *
276
 * Note that on resumed sessions, this function returns the schema
277
 * used in the original session authentication.
278
 *
279
 * Returns: The type of credentials for the client authentication
280
 *   schema, a #gnutls_credentials_type_t type.
281
 **/
282
gnutls_credentials_type_t gnutls_auth_client_get_type(gnutls_session_t session)
283
0
{
284
0
  return session->security_parameters.client_auth_type;
285
0
}
286
287
/* 
288
 * This returns a pointer to the linked list. Don't
289
 * free that!!!
290
 */
291
const void *_gnutls_get_kx_cred(gnutls_session_t session,
292
        gnutls_kx_algorithm_t algo)
293
0
{
294
0
  int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 :
295
0
                      0;
296
297
0
  return _gnutls_get_cred(session, _gnutls_map_kx_get_cred(algo, server));
298
0
}
299
300
const void *_gnutls_get_cred(gnutls_session_t session,
301
           gnutls_credentials_type_t type)
302
0
{
303
0
  auth_cred_st *ccred;
304
0
  gnutls_key_st *key = &session->key;
305
306
0
  ccred = key->cred;
307
0
  while (ccred != NULL) {
308
0
    if (ccred->algorithm == type) {
309
0
      break;
310
0
    }
311
0
    ccred = ccred->next;
312
0
  }
313
0
  if (ccred == NULL)
314
0
    return NULL;
315
316
0
  return ccred->credentials;
317
0
}
318
319
/*-
320
 * _gnutls_free_auth_info - Frees the auth info structure
321
 * @session: is a #gnutls_session_t type.
322
 *
323
 * This function frees the auth info structure and sets it to
324
 * null. It must be called since some structures contain malloced
325
 * elements.
326
 -*/
327
void _gnutls_free_auth_info(gnutls_session_t session)
328
0
{
329
0
  dh_info_st *dh_info;
330
331
0
  if (session == NULL) {
332
0
    gnutls_assert();
333
0
    return;
334
0
  }
335
336
0
  switch (session->key.auth_info_type) {
337
0
  case GNUTLS_CRD_SRP: {
338
0
    srp_server_auth_info_t info =
339
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_SRP);
340
341
0
    if (info == NULL)
342
0
      break;
343
344
0
    gnutls_free(info->username);
345
0
    info->username = NULL;
346
0
  } break;
347
0
#ifdef ENABLE_ANON
348
0
  case GNUTLS_CRD_ANON: {
349
0
    anon_auth_info_t info =
350
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
351
352
0
    if (info == NULL)
353
0
      break;
354
355
0
    dh_info = &info->dh;
356
0
    _gnutls_free_dh_info(dh_info);
357
0
  } break;
358
0
#endif
359
0
  case GNUTLS_CRD_PSK: {
360
0
    psk_auth_info_t info =
361
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
362
363
0
    if (info == NULL)
364
0
      break;
365
366
0
    gnutls_free(info->username);
367
0
    info->username = NULL;
368
0
    info->username_len = 0;
369
370
0
    gnutls_free(info->hint);
371
0
    info->hint = NULL;
372
0
    info->hint_len = 0;
373
374
0
#ifdef ENABLE_DHE
375
0
    dh_info = &info->dh;
376
0
    _gnutls_free_dh_info(dh_info);
377
0
#endif
378
0
  } break;
379
0
  case GNUTLS_CRD_CERTIFICATE: {
380
0
    unsigned int i;
381
0
    cert_auth_info_t info =
382
0
      _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
383
384
0
    if (info == NULL)
385
0
      break;
386
387
0
    dh_info = &info->dh;
388
0
    for (i = 0; i < info->ncerts; i++) {
389
0
      _gnutls_free_datum(&info->raw_certificate_list[i]);
390
0
    }
391
392
0
    for (i = 0; i < info->nocsp; i++) {
393
0
      _gnutls_free_datum(&info->raw_ocsp_list[i]);
394
0
    }
395
396
0
    gnutls_free(info->raw_certificate_list);
397
0
    gnutls_free(info->raw_ocsp_list);
398
0
    info->ncerts = 0;
399
0
    info->nocsp = 0;
400
401
0
#ifdef ENABLE_DHE
402
0
    _gnutls_free_dh_info(dh_info);
403
0
#endif
404
0
  }
405
406
0
  break;
407
0
  default:
408
0
    return;
409
0
  }
410
411
0
  gnutls_free(session->key.auth_info);
412
0
  session->key.auth_info_size = 0;
413
0
  session->key.auth_info_type = 0;
414
0
}
415
416
/* This function will create the auth info structure in the key
417
 * structure if needed.
418
 *
419
 * If allow change is !=0 then this will allow changing the auth
420
 * info structure to a different type.
421
 */
422
int _gnutls_auth_info_init(gnutls_session_t session,
423
         gnutls_credentials_type_t type, int size,
424
         int allow_change)
425
0
{
426
0
  if (session->key.auth_info == NULL) {
427
0
    session->key.auth_info = gnutls_calloc(1, size);
428
0
    if (session->key.auth_info == NULL) {
429
0
      gnutls_assert();
430
0
      return GNUTLS_E_MEMORY_ERROR;
431
0
    }
432
0
    session->key.auth_info_type = type;
433
0
    session->key.auth_info_size = size;
434
0
  } else {
435
0
    if (allow_change == 0) {
436
      /* If the credentials for the current authentication scheme,
437
       * are not the one we want to set, then it's an error.
438
       * This may happen if a rehandshake is performed an the
439
       * ciphersuite which is negotiated has different authentication
440
       * schema.
441
       */
442
0
      if (type != session->key.auth_info_type) {
443
0
        gnutls_assert();
444
0
        return GNUTLS_E_INVALID_REQUEST;
445
0
      }
446
0
    } else {
447
      /* The new behaviour: Here we reallocate the auth info structure
448
       * in order to be able to negotiate different authentication
449
       * types. Ie. perform an auth_anon and then authenticate again using a
450
       * certificate (in order to prevent revealing the certificate's contents,
451
       * to passive eavesdropers.
452
       */
453
0
      if (type != session->key.auth_info_type) {
454
0
        _gnutls_free_auth_info(session);
455
456
0
        session->key.auth_info = gnutls_calloc(1, size);
457
0
        if (session->key.auth_info == NULL) {
458
0
          gnutls_assert();
459
0
          return GNUTLS_E_MEMORY_ERROR;
460
0
        }
461
462
0
        session->key.auth_info_type = type;
463
0
        session->key.auth_info_size = size;
464
0
      }
465
0
    }
466
0
  }
467
0
  return 0;
468
0
}