Coverage Report

Created: 2025-03-06 06:58

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