Coverage Report

Created: 2024-10-29 07:00

/src/gnutls/lib/session.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2000-2016 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
#include "gnutls_int.h"
24
#include "errors.h"
25
#include "debug.h"
26
#include "session_pack.h"
27
#include "datum.h"
28
#include "buffers.h"
29
#include "state.h"
30
#include "ext/cert_types.h"
31
#include <minmax.h>
32
33
/**
34
 * gnutls_session_get_data:
35
 * @session: is a #gnutls_session_t type.
36
 * @session_data: is a pointer to space to hold the session.
37
 * @session_data_size: is the session_data's size, or it will be set by the function.
38
 *
39
 * Returns all session parameters needed to be stored to support resumption,
40
 * in a pre-allocated buffer.
41
 *
42
 * See gnutls_session_get_data2() for more information.
43
 *
44
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
45
 *   an error code is returned.
46
 **/
47
int gnutls_session_get_data(gnutls_session_t session, void *session_data,
48
          size_t *session_data_size)
49
0
{
50
0
  gnutls_datum_t psession;
51
0
  int ret;
52
53
0
  ret = gnutls_session_get_data2(session, &psession);
54
0
  if (ret < 0) {
55
0
    gnutls_assert();
56
0
    return ret;
57
0
  }
58
59
0
  if (psession.size > *session_data_size) {
60
0
    *session_data_size = psession.size;
61
0
    ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
62
0
    goto error;
63
0
  }
64
0
  *session_data_size = psession.size;
65
66
0
  if (session_data != NULL)
67
0
    memcpy(session_data, psession.data, psession.size);
68
69
0
  ret = 0;
70
71
0
error:
72
0
  _gnutls_free_datum(&psession);
73
0
  return ret;
74
0
}
75
76
0
#define EMPTY_DATA "\x00\x00\x00\x00"
77
0
#define EMPTY_DATA_SIZE 4
78
79
/**
80
 * gnutls_session_get_data2:
81
 * @session: is a #gnutls_session_t type.
82
 * @data: is a pointer to a datum that will hold the session.
83
 *
84
 * Returns necessary parameters to support resumption. The client
85
 * should call this function and store the returned session data. A session
86
 * can be resumed later by calling gnutls_session_set_data() with the returned
87
 * data. Note that under TLS 1.3, it is recommended for clients to use
88
 * session parameters only once, to prevent passive-observers from correlating
89
 * the different connections.
90
 *
91
 * The returned @data are allocated and must be released using gnutls_free().
92
 *
93
 * This function will fail if called prior to handshake completion. In
94
 * case of false start TLS, the handshake completes only after data have
95
 * been successfully received from the peer.
96
 *
97
 * Under TLS1.3 session resumption is possible only after a session ticket
98
 * is received by the client. To ensure that such a ticket has been received use
99
 * gnutls_session_get_flags() and check for flag %GNUTLS_SFLAGS_SESSION_TICKET;
100
 * if this flag is not set, this function will wait for a new ticket within
101
 * an estimated roundtrip, and if not received will return dummy data which
102
 * cannot lead to resumption.
103
 *
104
 * To get notified when new tickets are received by the server
105
 * use gnutls_handshake_set_hook_function() to wait for %GNUTLS_HANDSHAKE_NEW_SESSION_TICKET
106
 * messages. Each call of gnutls_session_get_data2() after a ticket is
107
 * received, will return session resumption data corresponding to the last
108
 * received ticket.
109
 *
110
 * Note that this function under TLS1.3 requires a callback to be set with
111
 * gnutls_transport_set_pull_timeout_function() for successful operation. There
112
 * was a bug before 3.6.10 which could make this function fail if that callback
113
 * was not set. On later versions if not set, the function will return a successful
114
 * error code, but will return dummy data that cannot lead to a resumption.
115
 *
116
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
117
 *   an error code is returned.
118
 **/
119
int gnutls_session_get_data2(gnutls_session_t session, gnutls_datum_t *data)
120
0
{
121
0
  const version_entry_st *vers = get_version(session);
122
0
  int ret;
123
124
0
  if (data == NULL || vers == NULL) {
125
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
126
0
  }
127
128
0
  if (vers->tls13_sem &&
129
0
      !(session->internals.hsk_flags & HSK_TICKET_RECEIVED)) {
130
0
    unsigned ertt = session->internals.ertt;
131
    /* use our estimation of round-trip + some time for the server to calculate
132
     * the value(s). */
133
0
    ertt += 60;
134
135
    /* we cannot use a read with timeout if the caller has not set
136
     * a callback with gnutls_transport_set_pull_timeout_function() */
137
0
    if (NO_TIMEOUT_FUNC_SET(session) ||
138
0
        (session->internals.flags & GNUTLS_NONBLOCK)) {
139
0
      if (!(session->internals.flags & GNUTLS_NONBLOCK))
140
0
        _gnutls_debug_log(
141
0
          "TLS1.3 works efficiently if a callback with gnutls_transport_set_pull_timeout_function() is set\n");
142
0
    } else {
143
      /* wait for a message with timeout */
144
0
      ret = _gnutls_recv_in_buffers(
145
0
        session, GNUTLS_APPLICATION_DATA, -1, ertt);
146
0
      if (ret < 0 && (gnutls_error_is_fatal(ret) &&
147
0
          ret != GNUTLS_E_TIMEDOUT)) {
148
0
        return gnutls_assert_val(ret);
149
0
      }
150
0
    }
151
152
0
    if (!(session->internals.hsk_flags & HSK_TICKET_RECEIVED)) {
153
0
      ret = _gnutls_set_datum(data, EMPTY_DATA,
154
0
            EMPTY_DATA_SIZE);
155
0
      if (ret < 0)
156
0
        return gnutls_assert_val(ret);
157
158
0
      return 0;
159
0
    }
160
0
  } else if (!vers->tls13_sem) {
161
    /* under TLS1.3 we want to pack the latest ticket, while that's
162
     * not the case in TLS1.2 or earlier. */
163
0
    if (gnutls_session_is_resumed(session) &&
164
0
        session->internals.resumption_data.data) {
165
0
      ret = _gnutls_set_datum(
166
0
        data, session->internals.resumption_data.data,
167
0
        session->internals.resumption_data.size);
168
0
      if (ret < 0)
169
0
        return gnutls_assert_val(ret);
170
171
0
      return 0;
172
0
    }
173
0
  }
174
175
0
  if (!session->internals.resumable)
176
0
    return GNUTLS_E_INVALID_SESSION;
177
178
0
  ret = _gnutls_session_pack(session, data);
179
0
  if (ret < 0) {
180
0
    gnutls_assert();
181
0
    return ret;
182
0
  }
183
184
0
  return 0;
185
0
}
186
187
/**
188
 * gnutls_session_get_id:
189
 * @session: is a #gnutls_session_t type.
190
 * @session_id: is a pointer to space to hold the session id.
191
 * @session_id_size: initially should contain the maximum @session_id size and will be updated.
192
 *
193
 * Returns the TLS session identifier. The session ID is selected by the
194
 * server, and in older versions of TLS was a unique identifier shared
195
 * between client and server which was persistent across resumption.
196
 * In the latest version of TLS (1.3) or TLS with session tickets, the
197
 * notion of session identifiers is undefined and cannot be relied for uniquely
198
 * identifying sessions across client and server.
199
 *
200
 * In client side this function returns the identifier returned by the
201
 * server, and cannot be assumed to have any relation to session resumption.
202
 * In server side this function is guaranteed to return a persistent
203
 * identifier of the session since GnuTLS 3.6.4, which may not necessarily
204
 * map into the TLS session ID value. Prior to that version the value
205
 * could only be considered a persistent identifier, under TLS1.2 or earlier
206
 * and when no session tickets were in use.
207
 *
208
 * The session identifier value returned is always less than
209
 * %GNUTLS_MAX_SESSION_ID_SIZE.
210
 *
211
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
212
 *   an error code is returned.
213
 **/
214
int gnutls_session_get_id(gnutls_session_t session, void *session_id,
215
        size_t *session_id_size)
216
0
{
217
0
  size_t given_session_id_size = *session_id_size;
218
219
0
  *session_id_size = session->security_parameters.session_id_size;
220
221
  /* just return the session size */
222
0
  if (session_id == NULL) {
223
0
    return 0;
224
0
  }
225
226
0
  if (given_session_id_size <
227
0
      session->security_parameters.session_id_size) {
228
0
    return GNUTLS_E_SHORT_MEMORY_BUFFER;
229
0
  }
230
231
0
  memcpy(session_id, &session->security_parameters.session_id,
232
0
         *session_id_size);
233
234
0
  return 0;
235
0
}
236
237
/**
238
 * gnutls_session_get_id2:
239
 * @session: is a #gnutls_session_t type.
240
 * @session_id: will point to the session ID.
241
 *
242
 * Returns the TLS session identifier. The session ID is selected by the
243
 * server, and in older versions of TLS was a unique identifier shared
244
 * between client and server which was persistent across resumption.
245
 * In the latest version of TLS (1.3) or TLS 1.2 with session tickets, the
246
 * notion of session identifiers is undefined and cannot be relied for uniquely
247
 * identifying sessions across client and server.
248
 *
249
 * In client side this function returns the identifier returned by the
250
 * server, and cannot be assumed to have any relation to session resumption.
251
 * In server side this function is guaranteed to return a persistent
252
 * identifier of the session since GnuTLS 3.6.4, which may not necessarily
253
 * map into the TLS session ID value. Prior to that version the value
254
 * could only be considered a persistent identifier, under TLS1.2 or earlier
255
 * and when no session tickets were in use.
256
 *
257
 * The session identifier value returned is always less than
258
 * %GNUTLS_MAX_SESSION_ID_SIZE and should be treated as constant.
259
 *
260
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
261
 *   an error code is returned.
262
 *
263
 * Since: 3.1.4
264
 **/
265
int gnutls_session_get_id2(gnutls_session_t session, gnutls_datum_t *session_id)
266
0
{
267
0
  session_id->size = session->security_parameters.session_id_size;
268
0
  session_id->data = session->security_parameters.session_id;
269
270
0
  return 0;
271
0
}
272
273
/**
274
 * gnutls_session_set_data:
275
 * @session: is a #gnutls_session_t type.
276
 * @session_data: is a pointer to space to hold the session.
277
 * @session_data_size: is the session's size
278
 *
279
 * Sets all session parameters, in order to resume a previously
280
 * established session.  The session data given must be the one
281
 * returned by gnutls_session_get_data().  This function should be
282
 * called before gnutls_handshake().
283
 *
284
 * Keep in mind that session resuming is advisory. The server may
285
 * choose not to resume the session, thus a full handshake will be
286
 * performed.
287
 *
288
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
289
 *   an error code is returned.
290
 **/
291
int gnutls_session_set_data(gnutls_session_t session, const void *session_data,
292
          size_t session_data_size)
293
0
{
294
0
  int ret;
295
0
  gnutls_datum_t psession;
296
297
0
  psession.data = (uint8_t *)session_data;
298
0
  psession.size = session_data_size;
299
300
0
  if (session_data == NULL || session_data_size == 0) {
301
0
    gnutls_assert();
302
0
    return GNUTLS_E_INVALID_REQUEST;
303
0
  }
304
305
  /* under TLS1.3 we always return some data on resumption when there
306
   * is no ticket in order to keep compatibility with existing apps */
307
0
  if (session_data_size == EMPTY_DATA_SIZE &&
308
0
      memcmp(session_data, EMPTY_DATA, EMPTY_DATA_SIZE) == 0) {
309
0
    return 0;
310
0
  }
311
312
0
  ret = _gnutls_session_unpack(session, &psession);
313
0
  if (ret < 0) {
314
0
    gnutls_assert();
315
0
    return ret;
316
0
  }
317
318
0
  session->internals.resumption_requested = 1;
319
320
0
  if (session->internals.resumption_data.data != NULL)
321
0
    gnutls_free(session->internals.resumption_data.data);
322
0
  ret = _gnutls_set_datum(&session->internals.resumption_data,
323
0
        session_data, session_data_size);
324
0
  if (ret < 0) {
325
0
    gnutls_assert();
326
0
    return ret;
327
0
  }
328
329
0
  return 0;
330
0
}
331
332
/**
333
 * gnutls_session_force_valid:
334
 * @session: is a #gnutls_session_t type.
335
 *
336
 * Clears the invalid flag in a session. That means
337
 * that sessions were corrupt or invalid data were received 
338
 * can be re-used. Use only when debugging or experimenting
339
 * with the TLS protocol. Should not be used in typical
340
 * applications.
341
 *
342
 **/
343
void gnutls_session_force_valid(gnutls_session_t session)
344
0
{
345
0
  session->internals.invalid_connection = 0;
346
0
}
347
348
0
#define DESC_SIZE 96
349
350
/**
351
 * gnutls_session_get_desc:
352
 * @session: is a gnutls session
353
 *
354
 * This function returns a string describing the current session.
355
 * The string is null terminated and allocated using gnutls_malloc().
356
 *
357
 * If initial negotiation is not complete when this function is called,
358
 * %NULL will be returned.
359
 *
360
 * Returns: a description of the protocols and algorithms in the current session.
361
 *
362
 * Since: 3.1.10
363
 **/
364
char *gnutls_session_get_desc(gnutls_session_t session)
365
0
{
366
0
  gnutls_kx_algorithm_t kx;
367
0
  const char *kx_str, *sign_str;
368
0
  gnutls_certificate_type_t ctype_client, ctype_server;
369
0
  char kx_name[64] = "";
370
0
  char proto_name[32];
371
0
  char _group_name[24];
372
0
  const char *group_name = NULL;
373
0
  int dh_bits = 0;
374
0
  unsigned mac_id;
375
0
  unsigned sign_algo;
376
0
  char *desc;
377
0
  const struct gnutls_group_entry_st *group = get_group(session);
378
0
  const version_entry_st *ver = get_version(session);
379
380
0
  if (session->internals.initial_negotiation_completed == 0)
381
0
    return NULL;
382
383
0
  kx = session->security_parameters.cs->kx_algorithm;
384
0
  if (group)
385
0
    group_name = group->name;
386
0
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
387
0
  if (group_name == NULL && _gnutls_kx_is_dhe(kx)) {
388
0
    dh_bits = gnutls_dh_get_prime_bits(session);
389
0
    if (dh_bits > 0)
390
0
      snprintf(_group_name, sizeof(_group_name), "CUSTOM%d",
391
0
         dh_bits);
392
0
    else
393
0
      snprintf(_group_name, sizeof(_group_name), "CUSTOM");
394
0
    group_name = _group_name;
395
0
  }
396
0
#endif
397
398
  /* Key exchange    - Signature algorithm */
399
  /* DHE-3072        - RSA-PSS-2048        */
400
  /* ECDHE-SECP256R1 - ECDSA-SECP256R1     */
401
402
0
  sign_algo = gnutls_sign_algorithm_get(session);
403
0
  sign_str = gnutls_sign_get_name(sign_algo);
404
405
0
  if (kx == 0 && ver->tls13_sem) { /* TLS 1.3 */
406
0
    if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
407
0
      if (group) {
408
0
        if (group->pk == GNUTLS_PK_DH)
409
0
          snprintf(kx_name, sizeof(kx_name),
410
0
             "(DHE-PSK-%s)", group_name);
411
0
        else
412
0
          snprintf(kx_name, sizeof(kx_name),
413
0
             "(ECDHE-PSK-%s)", group_name);
414
0
      } else {
415
0
        snprintf(kx_name, sizeof(kx_name), "(PSK)");
416
0
      }
417
0
    } else if (group && sign_str) {
418
0
      if (group->curve)
419
0
        snprintf(kx_name, sizeof(kx_name),
420
0
           "(ECDHE-%s)-(%s)", group_name,
421
0
           sign_str);
422
0
      else
423
0
        snprintf(kx_name, sizeof(kx_name),
424
0
           "(DHE-%s)-(%s)", group_name, sign_str);
425
0
    }
426
0
  } else {
427
0
    kx_str = gnutls_kx_get_name(kx);
428
0
    if (kx_str == NULL) {
429
0
      gnutls_assert();
430
0
      return NULL;
431
0
    }
432
433
0
    if ((kx == GNUTLS_KX_ECDHE_ECDSA || kx == GNUTLS_KX_ECDHE_RSA ||
434
0
         kx == GNUTLS_KX_ECDHE_PSK) &&
435
0
        group_name) {
436
0
      if (sign_str)
437
0
        snprintf(kx_name, sizeof(kx_name),
438
0
           "(ECDHE-%s)-(%s)", group_name,
439
0
           sign_str);
440
0
      else
441
0
        snprintf(kx_name, sizeof(kx_name), "(ECDHE-%s)",
442
0
           group_name);
443
0
    } else if ((kx == GNUTLS_KX_DHE_DSS ||
444
0
          kx == GNUTLS_KX_DHE_RSA ||
445
0
          kx == GNUTLS_KX_DHE_PSK) &&
446
0
         group_name) {
447
0
      if (sign_str)
448
0
        snprintf(kx_name, sizeof(kx_name),
449
0
           "(DHE-%s)-(%s)", group_name, sign_str);
450
0
      else
451
0
        snprintf(kx_name, sizeof(kx_name), "(DHE-%s)",
452
0
           group_name);
453
0
    } else if (kx == GNUTLS_KX_RSA) {
454
      /* Possible enhancement: include the certificate bits */
455
0
      snprintf(kx_name, sizeof(kx_name), "(RSA)");
456
0
    } else {
457
0
      snprintf(kx_name, sizeof(kx_name), "(%s)", kx_str);
458
0
    }
459
0
  }
460
461
0
  if (are_alternative_cert_types_allowed(session)) {
462
    // Get certificate types
463
0
    ctype_client =
464
0
      get_certificate_type(session, GNUTLS_CTYPE_CLIENT);
465
0
    ctype_server =
466
0
      get_certificate_type(session, GNUTLS_CTYPE_SERVER);
467
468
0
    if (ctype_client == ctype_server) {
469
      // print proto version, client/server cert type
470
0
      snprintf(
471
0
        proto_name, sizeof(proto_name), "%s-%s",
472
0
        gnutls_protocol_get_name(
473
0
          get_num_version(session)),
474
0
        gnutls_certificate_type_get_name(ctype_client));
475
0
    } else {
476
      // print proto version, client cert type, server cert type
477
0
      snprintf(
478
0
        proto_name, sizeof(proto_name), "%s-%s-%s",
479
0
        gnutls_protocol_get_name(
480
0
          get_num_version(session)),
481
0
        gnutls_certificate_type_get_name(ctype_client),
482
0
        gnutls_certificate_type_get_name(ctype_server));
483
0
    }
484
0
  } else { // Assumed default certificate type (X.509)
485
0
    snprintf(proto_name, sizeof(proto_name), "%s",
486
0
       gnutls_protocol_get_name(get_num_version(session)));
487
0
  }
488
489
0
  desc = gnutls_malloc(DESC_SIZE);
490
0
  if (desc == NULL)
491
0
    return NULL;
492
493
0
  mac_id = gnutls_mac_get(session);
494
0
  if (mac_id == GNUTLS_MAC_AEAD) { /* no need to print */
495
0
    snprintf(desc, DESC_SIZE, "(%s)-%s-(%s)", proto_name, kx_name,
496
0
       gnutls_cipher_get_name(gnutls_cipher_get(session)));
497
0
  } else {
498
0
    snprintf(desc, DESC_SIZE, "(%s)-%s-(%s)-(%s)", proto_name,
499
0
       kx_name,
500
0
       gnutls_cipher_get_name(gnutls_cipher_get(session)),
501
0
       gnutls_mac_get_name(mac_id));
502
0
  }
503
504
0
  return desc;
505
0
}
506
507
/**
508
 * gnutls_session_set_id:
509
 * @session: is a #gnutls_session_t type.
510
 * @sid: the session identifier
511
 *
512
 * This function sets the session ID to be used in a client hello.
513
 * This is a function intended for exceptional uses. Do not use this
514
 * function unless you are implementing a custom protocol.
515
 *
516
 * To set session resumption parameters use gnutls_session_set_data() instead.
517
 *
518
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
519
 *   an error code is returned.
520
 *
521
 * Since: 3.2.1
522
 **/
523
int gnutls_session_set_id(gnutls_session_t session, const gnutls_datum_t *sid)
524
0
{
525
0
  if (session->security_parameters.entity == GNUTLS_SERVER ||
526
0
      sid->size > GNUTLS_MAX_SESSION_ID_SIZE)
527
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
528
529
0
  memset(&session->internals.resumed_security_parameters, 0,
530
0
         sizeof(session->internals.resumed_security_parameters));
531
532
0
  session->internals.resumed_security_parameters.session_id_size =
533
0
    sid->size;
534
0
  memcpy(session->internals.resumed_security_parameters.session_id,
535
0
         sid->data, sid->size);
536
537
0
  return 0;
538
0
}