|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Copyright (C) 2009-2018 Free Software Foundation, Inc.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Author: Daiki Ueno, Ander Juaristi
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This file is part of GnuTLS.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
aea12f |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
aea12f |
* the License, or (at your option) any later version.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
aea12f |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
aea12f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
aea12f |
* Lesser General Public License for more details.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
aea12f |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
#include "gnutls_int.h"
|
|
Packit |
aea12f |
#include "errors.h"
|
|
Packit |
aea12f |
#include <datum.h>
|
|
Packit |
aea12f |
#include <algorithms.h>
|
|
Packit |
aea12f |
#include <handshake.h>
|
|
Packit |
aea12f |
#include <num.h>
|
|
Packit |
aea12f |
#include <constate.h>
|
|
Packit |
aea12f |
#include <session_pack.h>
|
|
Packit |
aea12f |
#include <random.h>
|
|
Packit |
aea12f |
#include <ext/session_ticket.h>
|
|
Packit |
aea12f |
#include <mbuffers.h>
|
|
Packit |
aea12f |
#include <hello_ext.h>
|
|
Packit |
aea12f |
#include <constate.h>
|
|
Packit |
aea12f |
#include <dtls.h>
|
|
Packit |
aea12f |
#include "stek.h"
|
|
Packit |
aea12f |
#include "db.h"
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int session_ticket_recv_params(gnutls_session_t session,
|
|
Packit |
aea12f |
const uint8_t * data,
|
|
Packit |
aea12f |
size_t data_size);
|
|
Packit |
aea12f |
static int session_ticket_send_params(gnutls_session_t session,
|
|
Packit |
aea12f |
gnutls_buffer_st * extdata);
|
|
Packit |
aea12f |
static int session_ticket_unpack(gnutls_buffer_st * ps,
|
|
Packit |
aea12f |
gnutls_ext_priv_data_t * _priv);
|
|
Packit |
aea12f |
static int session_ticket_pack(gnutls_ext_priv_data_t _priv,
|
|
Packit |
aea12f |
gnutls_buffer_st * ps);
|
|
Packit |
aea12f |
static void session_ticket_deinit_data(gnutls_ext_priv_data_t priv);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
const hello_ext_entry_st ext_mod_session_ticket = {
|
|
Packit |
aea12f |
.name = "Session Ticket",
|
|
Packit |
aea12f |
.tls_id = 35,
|
|
Packit |
aea12f |
.gid = GNUTLS_EXTENSION_SESSION_TICKET,
|
|
Packit |
aea12f |
.validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
|
|
Packit |
aea12f |
GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
|
|
Packit |
aea12f |
.parse_type = GNUTLS_EXT_TLS,
|
|
Packit |
aea12f |
.recv_func = session_ticket_recv_params,
|
|
Packit |
aea12f |
.send_func = session_ticket_send_params,
|
|
Packit |
aea12f |
.pack_func = session_ticket_pack,
|
|
Packit |
aea12f |
.unpack_func = session_ticket_unpack,
|
|
Packit |
aea12f |
.deinit_func = session_ticket_deinit_data,
|
|
Packit |
aea12f |
.cannot_be_overriden = 1
|
|
Packit |
aea12f |
};
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
typedef struct {
|
|
Packit |
aea12f |
uint8_t *session_ticket;
|
|
Packit |
aea12f |
int session_ticket_len;
|
|
Packit |
aea12f |
} session_ticket_ext_st;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static void
|
|
Packit |
aea12f |
deinit_ticket(struct ticket_st *ticket)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
free(ticket->encrypted_state);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
unpack_ticket(const gnutls_datum_t *ticket_data, struct ticket_st *ticket)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
const uint8_t * data = ticket_data->data;
|
|
Packit |
5407aa |
size_t data_size = ticket_data->size;
|
|
Packit |
aea12f |
const uint8_t *encrypted_state;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Format:
|
|
Packit |
aea12f |
* Key name
|
|
Packit |
aea12f |
* IV
|
|
Packit |
aea12f |
* data length
|
|
Packit |
aea12f |
* encrypted data
|
|
Packit |
aea12f |
* MAC
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
DECR_LEN(data_size, TICKET_KEY_NAME_SIZE);
|
|
Packit |
aea12f |
memcpy(ticket->key_name, data, TICKET_KEY_NAME_SIZE);
|
|
Packit |
aea12f |
data += TICKET_KEY_NAME_SIZE;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LEN(data_size, TICKET_IV_SIZE);
|
|
Packit |
aea12f |
memcpy(ticket->IV, data, TICKET_IV_SIZE);
|
|
Packit |
aea12f |
data += TICKET_IV_SIZE;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LEN(data_size, 2);
|
|
Packit |
aea12f |
ticket->encrypted_state_len = _gnutls_read_uint16(data);
|
|
Packit |
aea12f |
data += 2;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
encrypted_state = data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LEN(data_size, ticket->encrypted_state_len);
|
|
Packit |
aea12f |
data += ticket->encrypted_state_len;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LEN(data_size, TICKET_MAC_SIZE);
|
|
Packit |
aea12f |
memcpy(ticket->mac, data, TICKET_MAC_SIZE);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ticket->encrypted_state =
|
|
Packit |
aea12f |
gnutls_malloc(ticket->encrypted_state_len);
|
|
Packit |
aea12f |
if (!ticket->encrypted_state) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
memcpy(ticket->encrypted_state, encrypted_state,
|
|
Packit |
aea12f |
ticket->encrypted_state_len);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static void
|
|
Packit |
aea12f |
pack_ticket(const struct ticket_st *ticket, gnutls_datum_t *ticket_data)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
uint8_t *p;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
p = ticket_data->data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(p, ticket->key_name, TICKET_KEY_NAME_SIZE);
|
|
Packit |
aea12f |
p += TICKET_KEY_NAME_SIZE;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(p, ticket->IV, TICKET_IV_SIZE);
|
|
Packit |
aea12f |
p += TICKET_IV_SIZE;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_write_uint16(ticket->encrypted_state_len, p);
|
|
Packit |
aea12f |
p += 2;
|
|
Packit |
aea12f |
|
|
Packit |
f3da79 |
/* We use memmove instead of memcpy here because
|
|
Packit |
f3da79 |
* ticket->encrypted_state is allocated from
|
|
Packit |
f3da79 |
* ticket_data->data, and thus both memory areas may overlap.
|
|
Packit |
f3da79 |
*/
|
|
Packit |
f3da79 |
memmove(p, ticket->encrypted_state, ticket->encrypted_state_len);
|
|
Packit |
aea12f |
p += ticket->encrypted_state_len;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(p, ticket->mac, TICKET_MAC_SIZE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static
|
|
Packit |
aea12f |
int digest_ticket(const gnutls_datum_t * key, struct ticket_st *ticket,
|
|
Packit |
aea12f |
uint8_t * digest)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
mac_hd_st digest_hd;
|
|
Packit |
aea12f |
uint16_t length16;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_mac_init(&digest_hd, mac_to_entry(TICKET_MAC_ALGO),
|
|
Packit |
aea12f |
key->data, key->size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_mac(&digest_hd, ticket->key_name, TICKET_KEY_NAME_SIZE);
|
|
Packit |
aea12f |
_gnutls_mac(&digest_hd, ticket->IV, TICKET_IV_SIZE);
|
|
Packit |
aea12f |
length16 = _gnutls_conv_uint16(ticket->encrypted_state_len);
|
|
Packit |
aea12f |
_gnutls_mac(&digest_hd, &length16, 2);
|
|
Packit |
aea12f |
_gnutls_mac(&digest_hd, ticket->encrypted_state,
|
|
Packit |
aea12f |
ticket->encrypted_state_len);
|
|
Packit |
aea12f |
_gnutls_mac_deinit(&digest_hd, digest);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
_gnutls_decrypt_session_ticket(gnutls_session_t session,
|
|
Packit |
aea12f |
const gnutls_datum_t *ticket_data,
|
|
Packit |
aea12f |
gnutls_datum_t *state)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
cipher_hd_st cipher_hd;
|
|
Packit |
aea12f |
gnutls_datum_t IV;
|
|
Packit |
aea12f |
gnutls_datum_t stek_key_name, stek_cipher_key, stek_mac_key;
|
|
Packit |
aea12f |
uint8_t cmac[TICKET_MAC_SIZE];
|
|
Packit |
aea12f |
struct ticket_st ticket;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* callers must have that checked */
|
|
Packit |
aea12f |
assert(!(session->internals.flags & GNUTLS_NO_TICKETS));
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Retrieve ticket decryption keys */
|
|
Packit |
aea12f |
if (_gnutls_get_session_ticket_decryption_key(session,
|
|
Packit |
aea12f |
ticket_data,
|
|
Packit |
aea12f |
&stek_key_name,
|
|
Packit |
aea12f |
&stek_mac_key,
|
|
Packit |
aea12f |
&stek_cipher_key) < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = unpack_ticket(ticket_data, &ticket);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* If the key name of the ticket does not match the one that is currently active,
|
|
Packit |
aea12f |
issue a new ticket. */
|
|
Packit |
aea12f |
if (memcmp
|
|
Packit |
aea12f |
(ticket.key_name, stek_key_name.data,
|
|
Packit |
aea12f |
stek_key_name.size)) {
|
|
Packit |
aea12f |
ret = GNUTLS_E_DECRYPTION_FAILED;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Check the integrity of ticket */
|
|
Packit |
aea12f |
ret = digest_ticket(&stek_mac_key, &ticket, cmac);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (memcmp(ticket.mac, cmac, TICKET_MAC_SIZE)) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ticket.encrypted_state_len % TICKET_BLOCK_SIZE != 0) {
|
|
Packit |
aea12f |
ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Decrypt encrypted_state */
|
|
Packit |
aea12f |
IV.data = ticket.IV;
|
|
Packit |
aea12f |
IV.size = TICKET_IV_SIZE;
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_cipher_init(&cipher_hd,
|
|
Packit |
aea12f |
cipher_to_entry(TICKET_CIPHER),
|
|
Packit |
aea12f |
&stek_cipher_key, &IV, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state,
|
|
Packit |
aea12f |
ticket.encrypted_state_len);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup2;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
state->data = ticket.encrypted_state;
|
|
Packit |
aea12f |
state->size = ticket.encrypted_state_len;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ticket.encrypted_state = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup2:
|
|
Packit |
aea12f |
_gnutls_cipher_deinit(&cipher_hd);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
deinit_ticket(&ticket);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
_gnutls_encrypt_session_ticket(gnutls_session_t session,
|
|
Packit |
aea12f |
const gnutls_datum_t *state,
|
|
Packit |
aea12f |
gnutls_datum_t *ticket_data)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
cipher_hd_st cipher_hd;
|
|
Packit |
aea12f |
gnutls_datum_t IV;
|
|
Packit |
aea12f |
gnutls_datum_t encrypted_state = {NULL,0};
|
|
Packit |
aea12f |
uint8_t iv[TICKET_IV_SIZE];
|
|
Packit |
aea12f |
gnutls_datum_t stek_cipher_key, stek_mac_key, stek_key_name;
|
|
Packit |
aea12f |
struct ticket_st ticket;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
encrypted_state.size = ((state->size + TICKET_BLOCK_SIZE - 1) / TICKET_BLOCK_SIZE) * TICKET_BLOCK_SIZE;
|
|
Packit |
aea12f |
ticket_data->size = TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2 +
|
|
Packit |
aea12f |
encrypted_state.size + TICKET_MAC_SIZE;
|
|
Packit |
aea12f |
ticket_data->data = gnutls_calloc(1, ticket_data->size);
|
|
Packit |
aea12f |
if (!ticket_data->data) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
encrypted_state.data = ticket_data->data + TICKET_KEY_NAME_SIZE + TICKET_IV_SIZE + 2;
|
|
Packit |
aea12f |
memcpy(encrypted_state.data, state->data, state->size);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Retrieve ticket encryption keys */
|
|
Packit |
aea12f |
if (_gnutls_get_session_ticket_encryption_key(session,
|
|
Packit |
aea12f |
&stek_key_name,
|
|
Packit |
aea12f |
&stek_mac_key,
|
|
Packit |
aea12f |
&stek_cipher_key) < 0) {
|
|
Packit |
aea12f |
ret = GNUTLS_E_ENCRYPTION_FAILED;
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Encrypt state */
|
|
Packit |
aea12f |
IV.data = iv;
|
|
Packit |
aea12f |
IV.size = TICKET_IV_SIZE;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = gnutls_rnd(GNUTLS_RND_NONCE, iv, TICKET_IV_SIZE);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_cipher_init(&cipher_hd,
|
|
Packit |
aea12f |
cipher_to_entry(TICKET_CIPHER),
|
|
Packit |
aea12f |
&stek_cipher_key, &IV, 1);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
|
|
Packit |
aea12f |
encrypted_state.size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup2;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Fill the ticket structure to compute MAC. */
|
|
Packit |
aea12f |
memcpy(ticket.key_name, stek_key_name.data, stek_key_name.size);
|
|
Packit |
aea12f |
memcpy(ticket.IV, IV.data, IV.size);
|
|
Packit |
aea12f |
ticket.encrypted_state_len = encrypted_state.size;
|
|
Packit |
aea12f |
ticket.encrypted_state = encrypted_state.data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = digest_ticket(&stek_mac_key, &ticket, ticket.mac);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
goto cleanup2;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
encrypted_state.data = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
pack_ticket(&ticket, ticket_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup2:
|
|
Packit |
aea12f |
_gnutls_cipher_deinit(&cipher_hd);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
cleanup:
|
|
Packit |
aea12f |
_gnutls_free_datum(&encrypted_state);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
unpack_session(gnutls_session_t session, const gnutls_datum_t *state)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (unlikely(!state))
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_session_unpack(session, state);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_check_resumed_params(session);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.resumed = RESUME_TRUE;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
session_ticket_recv_params(gnutls_session_t session,
|
|
Packit |
5407aa |
const uint8_t * data, size_t data_size)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
gnutls_datum_t ticket_data;
|
|
Packit |
aea12f |
gnutls_datum_t state;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.flags & GNUTLS_NO_TICKETS)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_SERVER) {
|
|
Packit |
aea12f |
/* The client requested a new session ticket. */
|
|
Packit |
aea12f |
if (data_size == 0) {
|
|
Packit |
aea12f |
session->internals.session_ticket_renew = 1;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ticket_data.data = (void *)data;
|
|
Packit |
aea12f |
ticket_data.size = data_size;
|
|
Packit |
aea12f |
if ((ret = _gnutls_decrypt_session_ticket(session, &ticket_data, &state)) == 0) {
|
|
Packit |
aea12f |
ret = unpack_session(session, &state);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_free_datum(&state);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
session->internals.session_ticket_renew = 1;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else { /* Client */
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (data_size == 0) {
|
|
Packit |
aea12f |
session->internals.session_ticket_renew = 1;
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* returns a positive number if we send the extension data, (0) if we
|
|
Packit |
aea12f |
do not want to send it, and a negative number on failure.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
session_ticket_send_params(gnutls_session_t session,
|
|
Packit |
aea12f |
gnutls_buffer_st * extdata)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
session_ticket_ext_st *priv = NULL;
|
|
Packit |
aea12f |
gnutls_ext_priv_data_t epriv;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.flags & GNUTLS_NO_TICKETS)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->security_parameters.entity == GNUTLS_SERVER) {
|
|
Packit |
aea12f |
if (session->internals.session_ticket_renew) {
|
|
Packit |
aea12f |
return GNUTLS_E_INT_RET_0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_hello_ext_get_resumed_priv(session,
|
|
Packit |
aea12f |
GNUTLS_EXTENSION_SESSION_TICKET,
|
|
Packit |
aea12f |
&epriv);
|
|
Packit |
aea12f |
if (ret >= 0)
|
|
Packit |
aea12f |
priv = epriv;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* no previous data. Just advertize it */
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return GNUTLS_E_INT_RET_0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* previous data had session tickets disabled. Don't advertize. Ignore. */
|
|
Packit |
aea12f |
if (session->internals.flags & GNUTLS_NO_TICKETS)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (priv->session_ticket_len > 0) {
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_buffer_append_data(extdata,
|
|
Packit |
aea12f |
priv->
|
|
Packit |
aea12f |
session_ticket,
|
|
Packit |
aea12f |
priv->
|
|
Packit |
aea12f |
session_ticket_len);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return priv->session_ticket_len;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static void session_ticket_deinit_data(gnutls_ext_priv_data_t epriv)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
session_ticket_ext_st *priv = epriv;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_free(priv->session_ticket);
|
|
Packit |
aea12f |
gnutls_free(priv);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
session_ticket_pack(gnutls_ext_priv_data_t epriv, gnutls_buffer_st * ps)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
session_ticket_ext_st *priv = epriv;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
BUFFER_APPEND_PFX4(ps, priv->session_ticket,
|
|
Packit |
aea12f |
priv->session_ticket_len);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
static int
|
|
Packit |
aea12f |
session_ticket_unpack(gnutls_buffer_st * ps, gnutls_ext_priv_data_t * _priv)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
session_ticket_ext_st *priv = NULL;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_ext_priv_data_t epriv;
|
|
Packit |
aea12f |
gnutls_datum_t ticket;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
priv = gnutls_calloc(1, sizeof(*priv));
|
|
Packit |
aea12f |
if (priv == NULL) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
BUFFER_POP_DATUM(ps, &ticket);
|
|
Packit |
aea12f |
priv->session_ticket = ticket.data;
|
|
Packit |
aea12f |
priv->session_ticket_len = ticket.size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
epriv = priv;
|
|
Packit |
aea12f |
*_priv = epriv;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
gnutls_free(priv);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_session_ticket_key_generate:
|
|
Packit |
aea12f |
* @key: is a pointer to a #gnutls_datum_t which will contain a newly
|
|
Packit |
aea12f |
* created key.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Generate a random key to encrypt security parameters within
|
|
Packit |
aea12f |
* SessionTicket.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
|
|
Packit |
aea12f |
* error code.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Since: 2.10.0
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int gnutls_session_ticket_key_generate(gnutls_datum_t * key)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
if (_gnutls_fips_mode_enabled()) {
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
/* in FIPS140-2 mode gnutls_key_generate imposes
|
|
Packit |
aea12f |
* some limits on allowed key size, thus it is not
|
|
Packit |
aea12f |
* used. These limits do not affect this function as
|
|
Packit |
aea12f |
* it does not generate a "key" but rather key material
|
|
Packit |
aea12f |
* that includes nonces and other stuff. */
|
|
Packit |
aea12f |
key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
|
|
Packit |
aea12f |
if (key->data == NULL)
|
|
Packit |
aea12f |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
key->size = TICKET_MASTER_KEY_SIZE;
|
|
Packit |
aea12f |
ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_free(key->data);
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
} else {
|
|
Packit |
aea12f |
return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_session_ticket_enable_client:
|
|
Packit |
aea12f |
* @session: is a #gnutls_session_t type.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Request that the client should attempt session resumption using
|
|
Packit |
aea12f |
* SessionTicket. This call is typically unnecessary as session
|
|
Packit |
aea12f |
* tickets are enabled by default.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
|
|
Packit |
aea12f |
* error code.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Since: 2.10.0
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int gnutls_session_ticket_enable_client(gnutls_session_t session)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
if (!session) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.flags &= ~GNUTLS_NO_TICKETS;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/**
|
|
Packit |
aea12f |
* gnutls_session_ticket_enable_server:
|
|
Packit |
aea12f |
* @session: is a #gnutls_session_t type.
|
|
Packit |
aea12f |
* @key: key to encrypt session parameters.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Request that the server should attempt session resumption using
|
|
Packit |
aea12f |
* session tickets, i.e., by delegating storage to the client.
|
|
Packit |
aea12f |
* @key must be initialized using gnutls_session_ticket_key_generate().
|
|
Packit |
aea12f |
* To avoid leaking that key, use gnutls_memset() prior to
|
|
Packit |
aea12f |
* releasing it.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* The default ticket expiration time can be overridden using
|
|
Packit |
aea12f |
* gnutls_db_set_cache_expiration().
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
|
|
Packit |
aea12f |
* error code.
|
|
Packit |
aea12f |
*
|
|
Packit |
aea12f |
* Since: 2.10.0
|
|
Packit |
aea12f |
**/
|
|
Packit |
aea12f |
int
|
|
Packit |
aea12f |
gnutls_session_ticket_enable_server(gnutls_session_t session,
|
|
Packit |
aea12f |
const gnutls_datum_t * key)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (!session || !key || key->size != TICKET_MASTER_KEY_SIZE || !key->data) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_initialize_session_ticket_key_rotation(session, key);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.flags &= ~GNUTLS_NO_TICKETS;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Return zero if session tickets haven't been enabled.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
int _gnutls_send_new_session_ticket(gnutls_session_t session, int again)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
mbuffer_st *bufel = NULL;
|
|
Packit |
aea12f |
uint8_t *data = NULL, *p;
|
|
Packit |
aea12f |
int data_size = 0;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
gnutls_datum_t state = { NULL, 0 };
|
|
Packit |
aea12f |
uint16_t epoch_saved = session->security_parameters.epoch_write;
|
|
Packit |
aea12f |
gnutls_datum_t ticket_data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (again == 0) {
|
|
Packit |
aea12f |
if (session->internals.flags & GNUTLS_NO_TICKETS)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
if (!session->internals.session_ticket_renew)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log
|
|
Packit |
aea12f |
("HSK[%p]: sending session ticket\n", session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* XXX: Temporarily set write algorithms to be used.
|
|
Packit |
aea12f |
_gnutls_write_connection_state_init() does this job, but it also
|
|
Packit |
aea12f |
triggers encryption, while NewSessionTicket should not be
|
|
Packit |
aea12f |
encrypted in the record layer. */
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_epoch_set_keys(session,
|
|
Packit |
aea12f |
session->security_parameters.
|
|
Packit |
aea12f |
epoch_next, 0);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Under TLS1.2 with session tickets, the session ID is used for different
|
|
Packit |
aea12f |
* purposes than the TLS1.0 session ID. Ensure that there is an internally
|
|
Packit |
aea12f |
* set value which the server will see on the original and resumed sessions */
|
|
Packit |
aea12f |
if (session->internals.resumed != RESUME_TRUE) {
|
|
Packit |
aea12f |
ret = _gnutls_generate_session_id(session->security_parameters.
|
|
Packit |
aea12f |
session_id,
|
|
Packit |
aea12f |
&session->security_parameters.
|
|
Packit |
aea12f |
session_id_size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->security_parameters.epoch_write =
|
|
Packit |
aea12f |
session->security_parameters.epoch_next;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Pack security parameters. */
|
|
Packit |
aea12f |
ret = _gnutls_session_pack(session, &state);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Generate an encrypted ticket */
|
|
Packit |
aea12f |
ret = _gnutls_encrypt_session_ticket(session, &state, &ticket_data);
|
|
Packit |
aea12f |
session->security_parameters.epoch_write = epoch_saved;
|
|
Packit |
aea12f |
_gnutls_free_datum(&state);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
bufel =
|
|
Packit |
aea12f |
_gnutls_handshake_alloc(session,
|
|
Packit |
aea12f |
4 + 2 + ticket_data.size);
|
|
Packit |
aea12f |
if (!bufel) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
_gnutls_free_datum(&ticket_data);
|
|
Packit |
aea12f |
return GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
data = _mbuffer_get_udata_ptr(bufel);
|
|
Packit |
aea12f |
p = data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_write_uint32(session->internals.expire_time, p);
|
|
Packit |
aea12f |
p += 4;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_write_uint16(ticket_data.size, p);
|
|
Packit |
aea12f |
p += 2;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
memcpy(p, ticket_data.data, ticket_data.size);
|
|
Packit |
aea12f |
p += ticket_data.size;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_free_datum(&ticket_data);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
data_size = p - data;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_TLS12_TICKET_SENT;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
return _gnutls_send_handshake(session, data_size ? bufel : NULL,
|
|
Packit |
aea12f |
GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/*
|
|
Packit |
aea12f |
* Return zero if session tickets haven't been enabled.
|
|
Packit |
aea12f |
*/
|
|
Packit |
aea12f |
int _gnutls_recv_new_session_ticket(gnutls_session_t session)
|
|
Packit |
aea12f |
{
|
|
Packit |
aea12f |
uint8_t *p;
|
|
Packit |
aea12f |
int data_size;
|
|
Packit |
aea12f |
gnutls_buffer_st buf;
|
|
Packit |
aea12f |
uint16_t ticket_len;
|
|
Packit |
aea12f |
int ret;
|
|
Packit |
aea12f |
session_ticket_ext_st *priv = NULL;
|
|
Packit |
aea12f |
gnutls_ext_priv_data_t epriv;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (session->internals.flags & GNUTLS_NO_TICKETS)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
if (!session->internals.session_ticket_renew)
|
|
Packit |
aea12f |
return 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This is the last flight and peer cannot be sure
|
|
Packit |
aea12f |
* we have received it unless we notify him. So we
|
|
Packit |
aea12f |
* wait for a message and retransmit if needed. */
|
|
Packit |
aea12f |
if (IS_DTLS(session) && !_dtls_is_async(session)) {
|
|
Packit |
aea12f |
unsigned have;
|
|
Packit |
aea12f |
mbuffer_st *bufel = NULL;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
have = gnutls_record_check_pending(session) +
|
|
Packit |
aea12f |
record_check_unprocessed(session);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (have != 0) {
|
|
Packit |
aea12f |
bufel = _mbuffer_head_get_first(&session->internals.record_buffer, NULL);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (have == 0 || (bufel && bufel->type != GNUTLS_HANDSHAKE)) {
|
|
Packit |
aea12f |
ret = _dtls_wait_and_retransmit(session);
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val(ret);
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
ret = _gnutls_recv_handshake(session,
|
|
Packit |
aea12f |
GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
|
|
Packit |
aea12f |
0, &buf;;
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
return gnutls_assert_val_fatal(ret);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
p = buf.data;
|
|
Packit |
aea12f |
data_size = buf.length;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LENGTH_COM(data_size, 4, ret =
|
|
Packit |
aea12f |
GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
|
Packit |
aea12f |
goto error);
|
|
Packit |
aea12f |
/* skip over lifetime hint */
|
|
Packit |
aea12f |
p += 4;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LENGTH_COM(data_size, 2, ret =
|
|
Packit |
aea12f |
GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
|
Packit |
aea12f |
goto error);
|
|
Packit |
aea12f |
ticket_len = _gnutls_read_uint16(p);
|
|
Packit |
aea12f |
p += 2;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
DECR_LENGTH_COM(data_size, ticket_len, ret =
|
|
Packit |
aea12f |
GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
|
Packit |
aea12f |
goto error);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
priv = gnutls_calloc(1, sizeof(*priv));
|
|
Packit |
aea12f |
if (!priv) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
priv->session_ticket =
|
|
Packit |
aea12f |
gnutls_realloc_fast(priv->session_ticket, ticket_len);
|
|
Packit |
aea12f |
if (!priv->session_ticket) {
|
|
Packit |
aea12f |
gnutls_free(priv);
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
ret = GNUTLS_E_MEMORY_ERROR;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
memcpy(priv->session_ticket, p, ticket_len);
|
|
Packit |
aea12f |
priv->session_ticket_len = ticket_len;
|
|
Packit |
aea12f |
epriv = priv;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* Discard the current session ID. (RFC5077 3.4) */
|
|
Packit |
aea12f |
ret =
|
|
Packit |
aea12f |
_gnutls_generate_session_id(session->security_parameters.
|
|
Packit |
aea12f |
session_id,
|
|
Packit |
aea12f |
&session->security_parameters.
|
|
Packit |
aea12f |
session_id_size);
|
|
Packit |
aea12f |
if (ret < 0) {
|
|
Packit |
aea12f |
gnutls_assert();
|
|
Packit |
aea12f |
session_ticket_deinit_data(epriv);
|
|
Packit |
aea12f |
ret = GNUTLS_E_INTERNAL_ERROR;
|
|
Packit |
aea12f |
goto error;
|
|
Packit |
aea12f |
}
|
|
Packit |
aea12f |
ret = 0;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_handshake_log
|
|
Packit |
aea12f |
("HSK[%p]: received session ticket\n", session);
|
|
Packit |
aea12f |
session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
_gnutls_hello_ext_set_priv(session,
|
|
Packit |
aea12f |
GNUTLS_EXTENSION_SESSION_TICKET,
|
|
Packit |
aea12f |
epriv);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
error:
|
|
Packit |
aea12f |
_gnutls_buffer_clear(&buf;;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
return ret;
|
|
Packit |
aea12f |
}
|