Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/ext/session_ticket.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2009-2018 Free Software Foundation, Inc.
3
 *
4
 * Author: Daiki Ueno, 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
/* This file implements the TLS session ticket extension.
24
 *
25
 * Note that the extension is only used in TLS 1.2.  For TLS 1.3, session
26
 * tickets are sent as part of pre_shared_key extension (see pre_shared_key.c).
27
 */
28
29
#include "gnutls_int.h"
30
#include "errors.h"
31
#include "fips.h"
32
#include "datum.h"
33
#include "algorithms.h"
34
#include "handshake.h"
35
#include "num.h"
36
#include "constate.h"
37
#include "session_pack.h"
38
#include "random.h"
39
#include "ext/session_ticket.h"
40
#include "mbuffers.h"
41
#include "hello_ext.h"
42
#include "constate.h"
43
#include "dtls.h"
44
#include "stek.h"
45
#include "db.h"
46
47
static int session_ticket_recv_params(gnutls_session_t session,
48
              const uint8_t *data, size_t data_size);
49
static int session_ticket_send_params(gnutls_session_t session,
50
              gnutls_buffer_st *extdata);
51
static int session_ticket_unpack(gnutls_buffer_st *ps,
52
         gnutls_ext_priv_data_t *_priv);
53
static int session_ticket_pack(gnutls_ext_priv_data_t _priv,
54
             gnutls_buffer_st *ps);
55
static void session_ticket_deinit_data(gnutls_ext_priv_data_t priv);
56
57
const hello_ext_entry_st ext_mod_session_ticket = {
58
  .name = "Session Ticket",
59
  .tls_id = 35,
60
  .gid = GNUTLS_EXTENSION_SESSION_TICKET,
61
  .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
62
        GNUTLS_EXT_FLAG_CLIENT_HELLO |
63
        GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
64
  /* This extension must be parsed on session resumption as well; see
65
   * https://gitlab.com/gnutls/gnutls/issues/841 */
66
  .client_parse_point = GNUTLS_EXT_MANDATORY,
67
  /* on server side we want this parsed after normal handshake resumption
68
   * actions are complete */
69
  .server_parse_point = GNUTLS_EXT_TLS,
70
  .recv_func = session_ticket_recv_params,
71
  .send_func = session_ticket_send_params,
72
  .pack_func = session_ticket_pack,
73
  .unpack_func = session_ticket_unpack,
74
  .deinit_func = session_ticket_deinit_data,
75
  .cannot_be_overriden = 1
76
};
77
78
typedef struct {
79
  uint8_t *session_ticket;
80
  int session_ticket_len;
81
} session_ticket_ext_st;
82
83
static void deinit_ticket(struct ticket_st *ticket)
84
0
{
85
0
  free(ticket->encrypted_state);
86
0
}
87
88
static int unpack_ticket(const gnutls_datum_t *ticket_data,
89
       struct ticket_st *ticket)
90
0
{
91
0
  const uint8_t *data = ticket_data->data;
92
0
  size_t data_size = ticket_data->size;
93
0
  const uint8_t *encrypted_state;
94
95
  /* Format:
96
   *  Key name
97
   *  IV
98
   *  data length
99
   *  encrypted data
100
   *  MAC
101
   */
102
0
  DECR_LEN(data_size, TICKET_KEY_NAME_SIZE);
103
0
  memcpy(ticket->key_name, data, TICKET_KEY_NAME_SIZE);
104
0
  data += TICKET_KEY_NAME_SIZE;
105
106
0
  DECR_LEN(data_size, TICKET_IV_SIZE);
107
0
  memcpy(ticket->IV, data, TICKET_IV_SIZE);
108
0
  data += TICKET_IV_SIZE;
109
110
0
  DECR_LEN(data_size, 2);
111
0
  ticket->encrypted_state_len = _gnutls_read_uint16(data);
112
0
  data += 2;
113
114
0
  encrypted_state = data;
115
116
0
  DECR_LEN(data_size, ticket->encrypted_state_len);
117
0
  data += ticket->encrypted_state_len;
118
119
0
  DECR_LEN(data_size, TICKET_MAC_SIZE);
120
0
  memcpy(ticket->mac, data, TICKET_MAC_SIZE);
121
122
0
  ticket->encrypted_state = gnutls_malloc(ticket->encrypted_state_len);
123
0
  if (!ticket->encrypted_state) {
124
0
    gnutls_assert();
125
0
    return GNUTLS_E_MEMORY_ERROR;
126
0
  }
127
0
  memcpy(ticket->encrypted_state, encrypted_state,
128
0
         ticket->encrypted_state_len);
129
130
0
  return 0;
131
0
}
132
133
static void pack_ticket(const struct ticket_st *ticket,
134
      gnutls_datum_t *ticket_data)
135
0
{
136
0
  uint8_t *p;
137
138
0
  p = ticket_data->data;
139
140
0
  memcpy(p, ticket->key_name, TICKET_KEY_NAME_SIZE);
141
0
  p += TICKET_KEY_NAME_SIZE;
142
143
0
  memcpy(p, ticket->IV, TICKET_IV_SIZE);
144
0
  p += TICKET_IV_SIZE;
145
146
0
  _gnutls_write_uint16(ticket->encrypted_state_len, p);
147
0
  p += 2;
148
149
  /* We use memmove instead of memcpy here because
150
   * ticket->encrypted_state is allocated from
151
   * ticket_data->data, and thus both memory areas may overlap.
152
   */
153
0
  memmove(p, ticket->encrypted_state, ticket->encrypted_state_len);
154
0
  p += ticket->encrypted_state_len;
155
156
0
  memcpy(p, ticket->mac, TICKET_MAC_SIZE);
157
0
}
158
159
static int digest_ticket(const gnutls_datum_t *key, struct ticket_st *ticket,
160
       uint8_t *digest)
161
0
{
162
0
  mac_hd_st digest_hd;
163
0
  uint16_t length16;
164
0
  int ret;
165
166
0
  ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO),
167
0
             key->data, key->size);
168
0
  if (ret < 0) {
169
0
    gnutls_assert();
170
0
    return ret;
171
0
  }
172
173
0
  _gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE);
174
0
  _gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE);
175
0
  length16 = _gnutls_conv_uint16(ticket->encrypted_state_len);
176
0
  _gnutls_mac(&digest_hd, &length16, 2);
177
0
  _gnutls_mac(&digest_hd, ticket->encrypted_state,
178
0
        ticket->encrypted_state_len);
179
0
  _gnutls_mac_deinit(&digest_hd, digest);
180
181
0
  return 0;
182
0
}
183
184
int _gnutls_decrypt_session_ticket(gnutls_session_t session,
185
           const gnutls_datum_t *ticket_data,
186
           gnutls_datum_t *state)
187
0
{
188
0
  cipher_hd_st cipher_hd;
189
0
  gnutls_datum_t IV;
190
0
  gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key;
191
0
  uint8_t cmac[TICKET_MAC_SIZE];
192
0
  struct ticket_st ticket;
193
0
  int ret;
194
195
  /* Retrieve ticket decryption keys */
196
0
  if (_gnutls_get_session_ticket_decryption_key(
197
0
        session, ticket_data, &stek_key_name, &stek_mac_key,
198
0
        &stek_cipher_key) < 0)
199
0
    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
200
201
0
  ret = unpack_ticket(ticket_data, &ticket);
202
0
  if (ret < 0)
203
0
    return ret;
204
205
  /* If the key name of the ticket does not match the one that is currently active,
206
     issue a new ticket. */
207
0
  if (memcmp(ticket.key_name, stek_key_name.data, stek_key_name.size)) {
208
0
    ret = GNUTLS_E_DECRYPTION_FAILED;
209
0
    goto cleanup;
210
0
  }
211
212
  /* Check the integrity of ticket */
213
0
  ret = digest_ticket(&stek_mac_key, &ticket, cmac);
214
0
  if (ret < 0) {
215
0
    gnutls_assert();
216
0
    goto cleanup;
217
0
  }
218
219
0
  if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) {
220
0
    ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
221
0
    goto cleanup;
222
0
  }
223
224
0
  if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) {
225
0
    ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
226
0
    goto cleanup;
227
0
  }
228
229
  /* Decrypt encrypted_state */
230
0
  IV.data = ticket.IV;
231
0
  IV.size = TICKET_IV_SIZE;
232
0
  ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER),
233
0
          &stek_cipher_key, &IV, 0);
234
0
  if (ret < 0) {
235
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
236
0
    gnutls_assert();
237
0
    goto cleanup;
238
0
  }
239
0
  _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
240
241
0
  ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state,
242
0
             ticket.encrypted_state_len);
243
0
  if (ret < 0) {
244
0
    gnutls_assert();
245
0
    goto cleanup2;
246
0
  }
247
248
0
  state->data = ticket.encrypted_state;
249
0
  state->size = ticket.encrypted_state_len;
250
251
0
  ticket.encrypted_state = NULL;
252
253
0
  ret = 0;
254
255
0
cleanup2:
256
0
  _gnutls_cipher_deinit(&cipher_hd);
257
258
0
cleanup:
259
0
  deinit_ticket(&ticket);
260
261
0
  return ret;
262
0
}
263
264
int _gnutls_encrypt_session_ticket(gnutls_session_t session,
265
           const gnutls_datum_t *state,
266
           gnutls_datum_t *ticket_data)
267
0
{
268
0
  cipher_hd_st cipher_hd;
269
0
  gnutls_datum_t IV;
270
0
  gnutls_datum_t encrypted_state;
271
0
  gnutls_datum_t result = { NULL, 0 };
272
0
  uint8_t iv[TICKET_IV_SIZE];
273
0
  gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name;
274
0
  struct ticket_st ticket;
275
0
  int ret;
276
277
0
  encrypted_state.size =
278
0
    ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) *
279
0
    TICKET_BLOCK_SIZE;
280
0
  result.size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 +
281
0
          encrypted_state.size + TICKET_MAC_SIZE;
282
0
  result.data = gnutls_calloc(1, result.size);
283
0
  if (!result.data) {
284
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
285
0
  }
286
0
  encrypted_state.data =
287
0
    result.data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2;
288
0
  memcpy(encrypted_state.data, state->data, state->size);
289
290
  /* Retrieve ticket encryption keys */
291
0
  if (_gnutls_get_session_ticket_encryption_key(session, &stek_key_name,
292
0
                  &stek_mac_key,
293
0
                  &stek_cipher_key) < 0) {
294
0
    ret = GNUTLS_E_ENCRYPTION_FAILED;
295
0
    goto cleanup;
296
0
  }
297
298
  /* Encrypt state */
299
0
  IV.data = iv;
300
0
  IV.size = TICKET_IV_SIZE;
301
302
0
  ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE);
303
0
  if (ret < 0) {
304
0
    gnutls_assert();
305
0
    goto cleanup;
306
0
  }
307
308
0
  ret = _gnutls_cipher_init(&cipher_hd, cipher_to_entry(TICKET_CIPHER),
309
0
          &stek_cipher_key, &IV, 1);
310
0
  if (ret < 0) {
311
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
312
0
    gnutls_assert();
313
0
    goto cleanup;
314
0
  }
315
0
  _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
316
317
0
  ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
318
0
             encrypted_state.size);
319
0
  if (ret < 0) {
320
0
    gnutls_assert();
321
0
    goto cleanup2;
322
0
  }
323
324
  /* Fill the ticket structure to compute MAC. */
325
0
  memcpy(ticket.key_name, stek_key_name.data, stek_key_name.size);
326
0
  memcpy(ticket.IV, IV.data, IV.size);
327
0
  ticket.encrypted_state_len = encrypted_state.size;
328
0
  ticket.encrypted_state = encrypted_state.data;
329
330
0
  ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac);
331
0
  if (ret < 0) {
332
0
    gnutls_assert();
333
0
    goto cleanup2;
334
0
  }
335
336
0
  pack_ticket(&ticket, &result);
337
0
  ticket_data->data = result.data;
338
0
  ticket_data->size = result.size;
339
0
  result.data = NULL;
340
341
0
cleanup2:
342
0
  _gnutls_cipher_deinit(&cipher_hd);
343
344
0
cleanup:
345
0
  _gnutls_free_datum(&result);
346
347
0
  return ret;
348
0
}
349
350
static int unpack_session(gnutls_session_t session, const gnutls_datum_t *state)
351
0
{
352
0
  int ret;
353
354
0
  if (unlikely(!state))
355
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
356
357
0
  ret = _gnutls_session_unpack(session, state);
358
0
  if (ret < 0)
359
0
    return gnutls_assert_val(ret);
360
361
0
  ret = _gnutls_check_resumed_params(session);
362
0
  if (ret < 0)
363
0
    return gnutls_assert_val(ret);
364
365
0
  session->internals.resumed = true;
366
0
  return 0;
367
0
}
368
369
static int session_ticket_recv_params(gnutls_session_t session,
370
              const uint8_t *data, size_t data_size)
371
0
{
372
0
  gnutls_datum_t ticket_data;
373
0
  gnutls_datum_t state;
374
0
  int ret;
375
376
0
  if (session->internals.flags &
377
0
      (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12))
378
0
    return 0;
379
380
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
381
    /* The client requested a new session ticket. */
382
0
    if (data_size == 0) {
383
0
      session->internals.session_ticket_renew = 1;
384
0
      return 0;
385
0
    }
386
387
0
    ticket_data.data = (void *)data;
388
0
    ticket_data.size = data_size;
389
0
    if ((ret = _gnutls_decrypt_session_ticket(session, &ticket_data,
390
0
                &state)) == 0) {
391
0
      ret = unpack_session(session, &state);
392
393
0
      _gnutls_free_datum(&state);
394
0
    }
395
396
0
    if (ret < 0) {
397
0
      session->internals.session_ticket_renew = 1;
398
0
      return 0;
399
0
    }
400
0
  } else { /* Client */
401
402
0
    if (data_size == 0) {
403
0
      session->internals.session_ticket_renew = 1;
404
0
      return 0;
405
0
    }
406
0
  }
407
408
0
  return 0;
409
0
}
410
411
/* returns a positive number if we send the extension data, (0) if we
412
   do not want to send it, and a negative number on failure.
413
 */
414
static int session_ticket_send_params(gnutls_session_t session,
415
              gnutls_buffer_st *extdata)
416
0
{
417
0
  session_ticket_ext_st *priv = NULL;
418
0
  gnutls_ext_priv_data_t epriv;
419
0
  int ret;
420
421
0
  if (session->internals.flags &
422
0
      (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12))
423
0
    return 0;
424
425
0
  if (session->security_parameters.entity == GNUTLS_SERVER) {
426
0
    if (session->internals.session_ticket_renew) {
427
0
      return GNUTLS_E_INT_RET_0;
428
0
    }
429
0
  } else {
430
0
    ret = _gnutls_hello_ext_get_resumed_priv(
431
0
      session, GNUTLS_EXTENSION_SESSION_TICKET, &epriv);
432
0
    if (ret >= 0)
433
0
      priv = epriv;
434
435
    /* no previous data. Just advertise it */
436
0
    if (ret < 0)
437
0
      return GNUTLS_E_INT_RET_0;
438
439
    /* previous data had session tickets disabled. Don't advertise. Ignore. */
440
0
    if (session->internals.flags & GNUTLS_NO_TICKETS)
441
0
      return 0;
442
443
0
    if (priv->session_ticket_len > 0) {
444
0
      ret = _gnutls_buffer_append_data(
445
0
        extdata, priv->session_ticket,
446
0
        priv->session_ticket_len);
447
0
      if (ret < 0)
448
0
        return gnutls_assert_val(ret);
449
450
0
      return priv->session_ticket_len;
451
0
    }
452
0
  }
453
0
  return 0;
454
0
}
455
456
static void session_ticket_deinit_data(gnutls_ext_priv_data_t epriv)
457
0
{
458
0
  session_ticket_ext_st *priv = epriv;
459
460
0
  gnutls_free(priv->session_ticket);
461
0
  gnutls_free(priv);
462
0
}
463
464
static int session_ticket_pack(gnutls_ext_priv_data_t epriv,
465
             gnutls_buffer_st *ps)
466
0
{
467
0
  session_ticket_ext_st *priv = epriv;
468
0
  int ret;
469
470
0
  BUFFER_APPEND_PFX4(ps, priv->session_ticket, priv->session_ticket_len);
471
472
0
  return 0;
473
0
}
474
475
static int session_ticket_unpack(gnutls_buffer_st *ps,
476
         gnutls_ext_priv_data_t *_priv)
477
0
{
478
0
  session_ticket_ext_st *priv = NULL;
479
0
  int ret;
480
0
  gnutls_ext_priv_data_t epriv;
481
0
  gnutls_datum_t ticket;
482
483
0
  priv = gnutls_calloc(1, sizeof(*priv));
484
0
  if (priv == NULL) {
485
0
    gnutls_assert();
486
0
    return GNUTLS_E_MEMORY_ERROR;
487
0
  }
488
489
0
  BUFFER_POP_DATUM(ps, &ticket);
490
0
  priv->session_ticket = ticket.data;
491
0
  priv->session_ticket_len = ticket.size;
492
493
0
  epriv = priv;
494
0
  *_priv = epriv;
495
496
0
  return 0;
497
498
0
error:
499
0
  gnutls_free(priv);
500
0
  return ret;
501
0
}
502
503
/**
504
 * gnutls_session_ticket_key_generate:
505
 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
506
 * created key.
507
 *
508
 * Generate a random key to encrypt security parameters within
509
 * SessionTicket.
510
 *
511
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
512
 * error code.
513
 *
514
 * Since: 2.10.0
515
 **/
516
int gnutls_session_ticket_key_generate(gnutls_datum_t *key)
517
0
{
518
0
  if (_gnutls_fips_mode_enabled()) {
519
0
    int ret;
520
    /* in FIPS140-2 mode gnutls_key_generate imposes
521
     * some limits on allowed key size, thus it is not
522
     * used. These limits do not affect this function as
523
     * it does not generate a "key" but rather key material
524
     * that includes nonces and other stuff. */
525
0
    key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
526
0
    if (key->data == NULL)
527
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
528
529
0
    key->size = TICKET_MASTER_KEY_SIZE;
530
0
    ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
531
0
    if (ret < 0) {
532
0
      gnutls_free(key->data);
533
0
      return ret;
534
0
    }
535
0
    return 0;
536
0
  } else {
537
0
    return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
538
0
  }
539
0
}
540
541
/**
542
 * gnutls_session_ticket_enable_client:
543
 * @session: is a #gnutls_session_t type.
544
 *
545
 * Request that the client should attempt session resumption using
546
 * SessionTicket. This call is typically unnecessary as session
547
 * tickets are enabled by default.
548
 *
549
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
550
 * error code.
551
 *
552
 * Since: 2.10.0
553
 **/
554
int gnutls_session_ticket_enable_client(gnutls_session_t session)
555
0
{
556
0
  if (!session) {
557
0
    gnutls_assert();
558
0
    return GNUTLS_E_INVALID_REQUEST;
559
0
  }
560
561
0
  session->internals.flags &= ~GNUTLS_NO_TICKETS;
562
563
0
  return 0;
564
0
}
565
566
/**
567
 * gnutls_session_ticket_enable_server:
568
 * @session: is a #gnutls_session_t type.
569
 * @key: key to encrypt session parameters.
570
 *
571
 * Request that the server should attempt session resumption using
572
 * session tickets, i.e., by delegating storage to the client.
573
 * @key must be initialized using gnutls_session_ticket_key_generate().
574
 * To avoid leaking that key, use gnutls_memset() prior to
575
 * releasing it.
576
 *
577
 * The default ticket expiration time can be overridden using
578
 * gnutls_db_set_cache_expiration().
579
 *
580
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
581
 * error code.
582
 *
583
 * Since: 2.10.0
584
 **/
585
int gnutls_session_ticket_enable_server(gnutls_session_t session,
586
          const gnutls_datum_t *key)
587
0
{
588
0
  int ret;
589
590
0
  if (!session || !key || key->size != TICKET_MASTER_KEY_SIZE ||
591
0
      !key->data) {
592
0
    gnutls_assert();
593
0
    return GNUTLS_E_INVALID_REQUEST;
594
0
  }
595
596
0
  ret = _gnutls_initialize_session_ticket_key_rotation(session, key);
597
0
  if (ret < 0)
598
0
    return gnutls_assert_val(ret);
599
600
0
  session->internals.flags &= ~GNUTLS_NO_TICKETS;
601
602
0
  return 0;
603
0
}
604
605
void _gnutls_session_ticket_disable_server(gnutls_session_t session)
606
0
{
607
0
  session->internals.flags |= GNUTLS_NO_TICKETS;
608
0
}
609
610
/*
611
 * Return zero if session tickets haven't been enabled.
612
 */
613
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
614
0
{
615
0
  mbuffer_st *bufel = NULL;
616
0
  uint8_t *data = NULL, *p;
617
0
  int data_size = 0;
618
0
  int ret;
619
0
  gnutls_datum_t state = { NULL, 0 };
620
0
  uint16_t epoch_saved = session->security_parameters.epoch_write;
621
0
  gnutls_datum_t ticket_data;
622
623
0
  if (again == 0) {
624
0
    if (session->internals.flags &
625
0
        (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12)) {
626
0
      return 0;
627
0
    }
628
0
    if (!session->key.stek_initialized) {
629
0
      return 0;
630
0
    }
631
0
    if (!session->internals.session_ticket_renew) {
632
0
      return 0;
633
0
    }
634
635
0
    _gnutls_handshake_log("HSK[%p]: sending session ticket\n",
636
0
              session);
637
638
    /* XXX: Temporarily set write algorithms to be used.
639
       _gnutls_write_connection_state_init() does this job, but it also
640
       triggers encryption, while NewSessionTicket should not be
641
       encrypted in the record layer. */
642
0
    ret = _gnutls_epoch_set_keys(
643
0
      session, session->security_parameters.epoch_next, 0);
644
0
    if (ret < 0) {
645
0
      gnutls_assert();
646
0
      return ret;
647
0
    }
648
649
    /* Under TLS1.2 with session tickets, the session ID is used for different
650
     * purposes than the TLS1.0 session ID. Ensure that there is an internally
651
     * set value which the server will see on the original and resumed sessions */
652
0
    if (!session->internals.resumed) {
653
0
      ret = _gnutls_generate_session_id(
654
0
        session->security_parameters.session_id,
655
0
        &session->security_parameters.session_id_size);
656
0
      if (ret < 0) {
657
0
        gnutls_assert();
658
0
        return ret;
659
0
      }
660
0
    }
661
662
0
    session->security_parameters.epoch_write =
663
0
      session->security_parameters.epoch_next;
664
665
    /* Pack security parameters. */
666
0
    ret = _gnutls_session_pack(session, &state);
667
0
    if (ret < 0) {
668
0
      gnutls_assert();
669
0
      return ret;
670
0
    }
671
672
    /* Generate an encrypted ticket */
673
0
    ret = _gnutls_encrypt_session_ticket(session, &state,
674
0
                 &ticket_data);
675
0
    session->security_parameters.epoch_write = epoch_saved;
676
0
    _gnutls_free_datum(&state);
677
0
    if (ret < 0) {
678
0
      gnutls_assert();
679
0
      return ret;
680
0
    }
681
682
0
    bufel = _gnutls_handshake_alloc(session,
683
0
            4 + 2 + ticket_data.size);
684
0
    if (!bufel) {
685
0
      gnutls_assert();
686
0
      _gnutls_free_datum(&ticket_data);
687
0
      return GNUTLS_E_MEMORY_ERROR;
688
0
    }
689
690
0
    data = _mbuffer_get_udata_ptr(bufel);
691
0
    p = data;
692
693
0
    _gnutls_write_uint32(session->internals.expire_time, p);
694
0
    p += 4;
695
696
0
    _gnutls_write_uint16(ticket_data.size, p);
697
0
    p += 2;
698
699
0
    memcpy(p, ticket_data.data, ticket_data.size);
700
0
    p += ticket_data.size;
701
702
0
    _gnutls_free_datum(&ticket_data);
703
704
0
    data_size = p - data;
705
706
0
    session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
707
0
  }
708
0
  return _gnutls_send_handshake(session, data_size ? bufel : NULL,
709
0
              GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
710
0
}
711
712
/*
713
 * Return zero if session tickets haven't been enabled.
714
 */
715
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
716
0
{
717
0
  uint8_t *p;
718
0
  int data_size;
719
0
  gnutls_buffer_st buf;
720
0
  uint16_t ticket_len;
721
0
  int ret;
722
0
  session_ticket_ext_st *priv = NULL;
723
0
  gnutls_ext_priv_data_t epriv;
724
725
0
  if (session->internals.flags &
726
0
      (GNUTLS_NO_TICKETS | GNUTLS_NO_TICKETS_TLS12))
727
0
    return 0;
728
0
  if (!session->internals.session_ticket_renew)
729
0
    return 0;
730
731
  /* This is the last flight and peer cannot be sure
732
   * we have received it unless we notify him. So we
733
   * wait for a message and retransmit if needed. */
734
0
  if (IS_DTLS(session) && !_dtls_is_async(session)) {
735
0
    unsigned have;
736
0
    mbuffer_st *bufel = NULL;
737
738
0
    have = gnutls_record_check_pending(session) +
739
0
           record_check_unprocessed(session);
740
741
0
    if (have != 0) {
742
0
      bufel = _mbuffer_head_get_first(
743
0
        &session->internals.record_buffer, NULL);
744
0
    }
745
746
0
    if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
747
0
      ret = _dtls_wait_and_retransmit(session);
748
0
      if (ret < 0)
749
0
        return gnutls_assert_val(ret);
750
0
    }
751
0
  }
752
753
0
  ret = _gnutls_recv_handshake(
754
0
    session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 0, &buf);
755
0
  if (ret < 0)
756
0
    return gnutls_assert_val_fatal(ret);
757
758
0
  p = buf.data;
759
0
  data_size = buf.length;
760
761
0
  DECR_LENGTH_COM(data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
762
0
      goto error);
763
  /* skip over lifetime hint */
764
0
  p += 4;
765
766
0
  DECR_LENGTH_COM(data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
767
0
      goto error);
768
0
  ticket_len = _gnutls_read_uint16(p);
769
0
  p += 2;
770
771
0
  DECR_LENGTH_COM(data_size, ticket_len,
772
0
      ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
773
0
      goto error);
774
775
0
  priv = gnutls_calloc(1, sizeof(*priv));
776
0
  if (!priv) {
777
0
    gnutls_assert();
778
0
    ret = GNUTLS_E_MEMORY_ERROR;
779
0
    goto error;
780
0
  }
781
0
  if (ticket_len > 0) {
782
0
    priv->session_ticket =
783
0
      gnutls_realloc_fast(priv->session_ticket, ticket_len);
784
0
    if (!priv->session_ticket) {
785
0
      gnutls_free(priv);
786
0
      gnutls_assert();
787
0
      ret = GNUTLS_E_MEMORY_ERROR;
788
0
      goto error;
789
0
    }
790
0
    memcpy(priv->session_ticket, p, ticket_len);
791
0
  }
792
0
  priv->session_ticket_len = ticket_len;
793
0
  epriv = priv;
794
795
  /* Discard the current session ID.  (RFC5077 3.4) */
796
0
  ret = _gnutls_generate_session_id(
797
0
    session->security_parameters.session_id,
798
0
    &session->security_parameters.session_id_size);
799
0
  if (ret < 0) {
800
0
    gnutls_assert();
801
0
    session_ticket_deinit_data(epriv);
802
0
    ret = GNUTLS_E_INTERNAL_ERROR;
803
0
    goto error;
804
0
  }
805
0
  ret = 0;
806
807
0
  _gnutls_handshake_log("HSK[%p]: received session ticket\n", session);
808
0
  session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
809
810
0
  _gnutls_hello_ext_set_priv(session, GNUTLS_EXTENSION_SESSION_TICKET,
811
0
           epriv);
812
813
0
error:
814
0
  _gnutls_buffer_clear(&buf);
815
816
0
  return ret;
817
0
}