Coverage Report

Created: 2023-03-26 08:33

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