Coverage Report

Created: 2023-03-26 07:33

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