Coverage Report

Created: 2024-10-29 07:00

/src/gnutls/lib/tls13/session_ticket.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017-2018 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos, Ander Juaristi
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "gnutls_int.h"
24
#include "errors.h"
25
#include "extv.h"
26
#include "handshake.h"
27
#include "mbuffers.h"
28
#include "ext/pre_shared_key.h"
29
#include "ext/session_ticket.h"
30
#include "ext/early_data.h"
31
#include "auth/cert.h"
32
#include "tls13/session_ticket.h"
33
#include "session_pack.h"
34
#include "db.h"
35
36
static int pack_ticket(gnutls_session_t session, tls13_ticket_st *ticket,
37
           gnutls_datum_t *packed)
38
0
{
39
0
  uint8_t *p;
40
0
  gnutls_datum_t state;
41
0
  int ret;
42
43
0
  ret = _gnutls_session_pack(session, &state);
44
0
  if (ret < 0)
45
0
    return gnutls_assert_val(ret);
46
47
0
  packed->size = 2 + 4 + 4 + 1 + ticket->prf->output_size + 1 +
48
0
           ticket->nonce_size + 2 + state.size + 12;
49
50
0
  packed->data = gnutls_malloc(packed->size);
51
0
  if (!packed->data) {
52
0
    gnutls_assert();
53
0
    ret = GNUTLS_E_MEMORY_ERROR;
54
0
    goto cleanup;
55
0
  }
56
57
0
  p = packed->data;
58
59
0
  _gnutls_write_uint16(ticket->prf->id, p);
60
0
  p += 2;
61
0
  _gnutls_write_uint32(ticket->age_add, p);
62
0
  p += 4;
63
0
  _gnutls_write_uint32(ticket->lifetime, p);
64
0
  p += 4;
65
0
  *p = ticket->prf->output_size;
66
0
  p += 1;
67
0
  memcpy(p, ticket->resumption_master_secret, ticket->prf->output_size);
68
0
  p += ticket->prf->output_size;
69
0
  *p = ticket->nonce_size;
70
71
0
  p += 1;
72
0
  memcpy(p, ticket->nonce, ticket->nonce_size);
73
0
  p += ticket->nonce_size;
74
75
0
  _gnutls_write_uint16(state.size, p);
76
0
  p += 2;
77
78
0
  memcpy(p, state.data, state.size);
79
0
  p += state.size;
80
81
0
  _gnutls_write_uint32((uint64_t)ticket->creation_time.tv_sec >> 32, p);
82
0
  p += 4;
83
0
  _gnutls_write_uint32(ticket->creation_time.tv_sec & 0xFFFFFFFF, p);
84
0
  p += 4;
85
0
  _gnutls_write_uint32(ticket->creation_time.tv_nsec, p);
86
87
0
  ret = 0;
88
89
0
cleanup:
90
0
  gnutls_free(state.data);
91
0
  return ret;
92
0
}
93
94
static int unpack_ticket(gnutls_session_t session, gnutls_datum_t *packed,
95
       tls13_ticket_st *data)
96
0
{
97
0
  uint32_t age_add, lifetime;
98
0
  struct timespec creation_time;
99
0
  uint8_t resumption_master_secret[MAX_HASH_SIZE];
100
0
  size_t resumption_master_secret_size;
101
0
  uint8_t nonce[UINT8_MAX];
102
0
  size_t nonce_size;
103
0
  gnutls_datum_t state;
104
0
  gnutls_mac_algorithm_t kdf;
105
0
  const mac_entry_st *prf;
106
0
  uint8_t *p;
107
0
  size_t len;
108
0
  uint64_t v;
109
0
  int ret;
110
111
0
  if (unlikely(packed == NULL || data == NULL))
112
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
113
114
0
  memset(data, 0, sizeof(*data));
115
116
0
  p = packed->data;
117
0
  len = packed->size;
118
119
0
  DECR_LEN(len, 2);
120
0
  kdf = _gnutls_read_uint16(p);
121
0
  p += 2;
122
123
  /* Check if the MAC ID we got is valid */
124
0
  prf = _gnutls_mac_to_entry(kdf);
125
0
  if (prf == NULL)
126
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
127
128
  /* Read the ticket age add and the ticket lifetime */
129
0
  DECR_LEN(len, 4);
130
0
  age_add = _gnutls_read_uint32(p);
131
0
  p += 4;
132
133
0
  DECR_LEN(len, 4);
134
0
  lifetime = _gnutls_read_uint32(p);
135
0
  p += 4;
136
137
  /*
138
   * Check if the whole ticket is large enough,
139
   * and read the resumption master secret
140
   */
141
0
  DECR_LEN(len, 1);
142
0
  resumption_master_secret_size = *p;
143
0
  p += 1;
144
145
  /* Check if the size of resumption_master_secret matches the PRF */
146
0
  if (resumption_master_secret_size != prf->output_size)
147
0
    return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
148
149
0
  DECR_LEN(len, resumption_master_secret_size);
150
0
  memcpy(resumption_master_secret, p, resumption_master_secret_size);
151
0
  p += resumption_master_secret_size;
152
153
  /* Read the ticket nonce */
154
0
  DECR_LEN(len, 1);
155
0
  nonce_size = *p;
156
0
  p += 1;
157
158
0
  DECR_LEN(len, nonce_size);
159
0
  memcpy(nonce, p, nonce_size);
160
0
  p += nonce_size;
161
162
0
  DECR_LEN(len, 2);
163
0
  state.size = _gnutls_read_uint16(p);
164
0
  p += 2;
165
166
0
  DECR_LEN(len, state.size);
167
0
  state.data = p;
168
0
  p += state.size;
169
170
0
  DECR_LEN(len, 12);
171
0
  v = _gnutls_read_uint32(p);
172
0
  p += 4;
173
0
  creation_time.tv_sec = (v << 32) | _gnutls_read_uint32(p);
174
0
  p += 4;
175
0
  creation_time.tv_nsec = _gnutls_read_uint32(p);
176
177
0
  ret = _gnutls_session_unpack(session, &state);
178
0
  if (ret < 0)
179
0
    return gnutls_assert_val(ret);
180
181
  /* No errors - Now return all the data to the caller */
182
0
  data->prf = prf;
183
0
  memcpy(data->resumption_master_secret, resumption_master_secret,
184
0
         resumption_master_secret_size);
185
0
  memcpy(data->nonce, nonce, nonce_size);
186
0
  data->nonce_size = nonce_size;
187
0
  data->age_add = age_add;
188
0
  data->lifetime = lifetime;
189
0
  memcpy(&data->creation_time, &creation_time, sizeof(struct timespec));
190
191
0
  return 0;
192
0
}
193
194
static int generate_session_ticket(gnutls_session_t session,
195
           tls13_ticket_st *ticket)
196
0
{
197
0
  int ret;
198
0
  gnutls_datum_t packed = { NULL, 0 };
199
0
  struct timespec now;
200
0
  tls13_ticket_st ticket_data;
201
202
0
  gnutls_gettime(&now);
203
0
  if (session->internals.resumed) {
204
    /* If we are resuming ensure that we don't extend the lifetime
205
     * of the ticket past the original session expiration time */
206
0
    if (now.tv_sec >= session->security_parameters.timestamp +
207
0
            session->internals.expire_time)
208
0
      return GNUTLS_E_INT_RET_0; /* don't send ticket */
209
0
    else
210
0
      ticket->lifetime =
211
0
        session->security_parameters.timestamp +
212
0
        session->internals.expire_time - now.tv_sec;
213
0
  } else {
214
    /* Set ticket lifetime to the default expiration time */
215
0
    ticket->lifetime = session->internals.expire_time;
216
0
  }
217
218
  /* Generate a random 32-bit ticket nonce */
219
0
  ticket->nonce_size = 4;
220
221
0
  if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, ticket->nonce,
222
0
            ticket->nonce_size)) < 0)
223
0
    return gnutls_assert_val(ret);
224
225
0
  if ((ret = gnutls_rnd(GNUTLS_RND_NONCE, &ticket->age_add,
226
0
            sizeof(uint32_t))) < 0)
227
0
    return gnutls_assert_val(ret);
228
    /* This is merely to produce the same binder value on
229
   * different endian architectures. */
230
#ifdef WORDS_BIGENDIAN
231
  ticket->age_add = bswap_32(ticket->age_add);
232
#endif
233
234
0
  ticket->prf = session->security_parameters.prf;
235
236
  /* Encrypt the ticket and place the result in ticket->ticket */
237
0
  ticket_data.lifetime = ticket->lifetime;
238
0
  ticket_data.age_add = ticket->age_add;
239
0
  memcpy(&ticket_data.creation_time, &now, sizeof(struct timespec));
240
0
  memcpy(ticket_data.nonce, ticket->nonce, ticket->nonce_size);
241
0
  ticket_data.nonce_size = ticket->nonce_size;
242
0
  ticket_data.prf = ticket->prf;
243
0
  memcpy(&ticket_data.resumption_master_secret,
244
0
         session->key.proto.tls13.ap_rms, ticket->prf->output_size);
245
246
0
  ret = pack_ticket(session, &ticket_data, &packed);
247
0
  if (ret < 0)
248
0
    return gnutls_assert_val(ret);
249
250
0
  ret = _gnutls_encrypt_session_ticket(session, &packed, &ticket->ticket);
251
0
  _gnutls_free_datum(&packed);
252
0
  if (ret < 0)
253
0
    return gnutls_assert_val(ret);
254
255
0
  return 0;
256
0
}
257
258
static int append_nst_extension(void *ctx, gnutls_buffer_st *buf)
259
0
{
260
0
  gnutls_session_t session = ctx;
261
0
  int ret;
262
263
0
  if (!(session->internals.flags & GNUTLS_ENABLE_EARLY_DATA))
264
0
    return 0;
265
266
0
  ret = _gnutls_buffer_append_prefix(
267
0
    buf, 32, session->security_parameters.max_early_data_size);
268
0
  if (ret < 0)
269
0
    gnutls_assert();
270
271
0
  return ret;
272
0
}
273
274
int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr,
275
          unsigned again)
276
0
{
277
0
  int ret = 0;
278
0
  mbuffer_st *bufel = NULL;
279
0
  gnutls_buffer_st buf;
280
0
  tls13_ticket_st ticket;
281
0
  unsigned i;
282
283
  /* Client does not send a NewSessionTicket */
284
0
  if (unlikely(session->security_parameters.entity == GNUTLS_CLIENT))
285
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
286
287
  /* Session resumption has not been enabled */
288
0
  if (session->internals.flags & GNUTLS_NO_TICKETS)
289
0
    return gnutls_assert_val(0);
290
291
  /* If we received the psk_key_exchange_modes extension which
292
   * does not have overlap with the server configuration, don't
293
   * send a session ticket */
294
0
  if (session->internals.hsk_flags & HSK_PSK_KE_MODE_INVALID)
295
0
    return gnutls_assert_val(0);
296
297
0
  if (again == 0) {
298
0
    for (i = 0; i < nr; i++) {
299
0
      unsigned init_pos;
300
301
0
      memset(&ticket, 0, sizeof(tls13_ticket_st));
302
0
      bufel = NULL;
303
304
0
      ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
305
0
      if (ret < 0)
306
0
        return gnutls_assert_val(ret);
307
308
0
      ret = generate_session_ticket(session, &ticket);
309
0
      if (ret < 0) {
310
0
        if (ret == GNUTLS_E_INT_RET_0) {
311
0
          ret = gnutls_assert_val(0);
312
0
          goto cleanup;
313
0
        }
314
0
        gnutls_assert();
315
0
        goto cleanup;
316
0
      }
317
318
0
      ret = _gnutls_buffer_append_prefix(&buf, 32,
319
0
                 ticket.lifetime);
320
0
      if (ret < 0) {
321
0
        gnutls_assert();
322
0
        goto cleanup;
323
0
      }
324
325
0
      ret = _gnutls_buffer_append_prefix(&buf, 32,
326
0
                 ticket.age_add);
327
0
      if (ret < 0) {
328
0
        gnutls_assert();
329
0
        goto cleanup;
330
0
      }
331
332
      /* append ticket_nonce */
333
0
      ret = _gnutls_buffer_append_data_prefix(
334
0
        &buf, 8, ticket.nonce, ticket.nonce_size);
335
0
      if (ret < 0) {
336
0
        gnutls_assert();
337
0
        goto cleanup;
338
0
      }
339
340
      /* append ticket */
341
0
      ret = _gnutls_buffer_append_data_prefix(
342
0
        &buf, 16, ticket.ticket.data,
343
0
        ticket.ticket.size);
344
0
      if (ret < 0) {
345
0
        gnutls_assert();
346
0
        goto cleanup;
347
0
      }
348
349
0
      _gnutls_free_datum(&ticket.ticket);
350
351
      /* append extensions */
352
0
      ret = _gnutls_extv_append_init(&buf);
353
0
      if (ret < 0) {
354
0
        gnutls_assert();
355
0
        goto cleanup;
356
0
      }
357
0
      init_pos = ret;
358
359
0
      ret = _gnutls_extv_append(
360
0
        &buf, ext_mod_early_data.tls_id, session,
361
0
        (extv_append_func)append_nst_extension);
362
0
      if (ret < 0) {
363
0
        gnutls_assert();
364
0
        goto cleanup;
365
0
      }
366
367
0
      ret = _gnutls_extv_append_final(&buf, init_pos, 0);
368
0
      if (ret < 0) {
369
0
        gnutls_assert();
370
0
        goto cleanup;
371
0
      }
372
373
0
      bufel = _gnutls_buffer_to_mbuffer(&buf);
374
375
0
      ret = _gnutls_send_handshake2(
376
0
        session, bufel,
377
0
        GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 1);
378
0
      if (ret < 0) {
379
0
        gnutls_assert();
380
0
        goto cleanup;
381
0
      }
382
383
0
      session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
384
0
    }
385
0
  }
386
387
0
  ret = _gnutls_handshake_io_write_flush(session);
388
389
0
  return ret;
390
391
0
cleanup:
392
0
  _gnutls_free_datum(&ticket.ticket);
393
0
  _mbuffer_xfree(&bufel);
394
0
  _gnutls_buffer_clear(&buf);
395
396
0
  return ret;
397
0
}
398
399
static int parse_nst_extension(void *ctx, unsigned tls_id,
400
             const unsigned char *data, unsigned data_size)
401
0
{
402
0
  gnutls_session_t session = ctx;
403
0
  if (tls_id == ext_mod_early_data.tls_id) {
404
0
    if (data_size < 4)
405
0
      return gnutls_assert_val(
406
0
        GNUTLS_E_TLS_PACKET_DECODING_ERROR);
407
0
    session->security_parameters.max_early_data_size =
408
0
      _gnutls_read_uint32(data);
409
0
  }
410
0
  return 0;
411
0
}
412
413
int _gnutls13_recv_session_ticket(gnutls_session_t session,
414
          gnutls_buffer_st *buf)
415
0
{
416
0
  int ret;
417
0
  uint8_t value;
418
0
  tls13_ticket_st *ticket = &session->internals.tls13_ticket;
419
0
  gnutls_datum_t t;
420
0
  size_t val;
421
422
0
  if (unlikely(buf == NULL))
423
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
424
425
0
  _gnutls_free_datum(&ticket->ticket);
426
0
  memset(ticket, 0, sizeof(tls13_ticket_st));
427
428
0
  _gnutls_handshake_log("HSK[%p]: parsing session ticket message\n",
429
0
            session);
430
431
  /* ticket_lifetime */
432
0
  ret = _gnutls_buffer_pop_prefix32(buf, &val, 0);
433
0
  if (ret < 0)
434
0
    return gnutls_assert_val(ret);
435
0
  ticket->lifetime = val;
436
437
  /* ticket_age_add */
438
0
  ret = _gnutls_buffer_pop_prefix32(buf, &val, 0);
439
0
  if (ret < 0)
440
0
    return gnutls_assert_val(ret);
441
0
  ticket->age_add = val;
442
443
  /* ticket_nonce */
444
0
  ret = _gnutls_buffer_pop_prefix8(buf, &value, 0);
445
0
  if (ret < 0)
446
0
    return gnutls_assert_val(ret);
447
448
0
  ticket->nonce_size = value;
449
0
  ret = _gnutls_buffer_pop_data(buf, ticket->nonce, ticket->nonce_size);
450
0
  if (ret < 0)
451
0
    return gnutls_assert_val(ret);
452
453
  /* ticket */
454
0
  ret = _gnutls_buffer_pop_datum_prefix16(buf, &t);
455
0
  if (ret < 0)
456
0
    return gnutls_assert_val(ret);
457
458
0
  gnutls_free(ticket->ticket.data);
459
0
  ret = _gnutls_set_datum(&ticket->ticket, t.data, t.size);
460
0
  if (ret < 0)
461
0
    return gnutls_assert_val(ret);
462
463
  /* Extensions */
464
0
  ret = _gnutls_extv_parse(session, parse_nst_extension, buf->data,
465
0
         buf->length);
466
0
  if (ret < 0)
467
0
    return gnutls_assert_val(ret);
468
469
  /* Record the ticket arrival time */
470
0
  gnutls_gettime(&ticket->arrival_time);
471
472
0
  return 0;
473
0
}
474
475
/*
476
 * Parse the ticket in 'data' and return the resumption master secret
477
 * and the KDF ID associated to it.
478
 */
479
int _gnutls13_unpack_session_ticket(gnutls_session_t session,
480
            gnutls_datum_t *data,
481
            tls13_ticket_st *ticket_data)
482
0
{
483
0
  int ret;
484
0
  gnutls_datum_t decrypted = { NULL, 0 };
485
486
0
  if (unlikely(data == NULL || ticket_data == NULL))
487
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
488
489
0
  if (!session->key.stek_initialized) {
490
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
491
0
  }
492
493
  /* Check MAC and decrypt ticket */
494
0
  ret = _gnutls_decrypt_session_ticket(session, data, &decrypted);
495
0
  if (ret < 0)
496
0
    return gnutls_assert_val(ret);
497
498
  /* Return ticket parameters */
499
0
  ret = unpack_ticket(session, &decrypted, ticket_data);
500
0
  _gnutls_free_datum(&decrypted);
501
0
  if (ret < 0)
502
0
    return ret;
503
504
0
  ret = _gnutls_check_resumed_params(session);
505
0
  if (ret < 0)
506
0
    return gnutls_assert_val(ret);
507
508
0
  return 0;
509
0
}