Coverage Report

Created: 2023-03-26 08:33

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