summaryrefslogtreecommitdiff
path: root/lib/ext/session_ticket.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-16 00:38:08 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-04-16 00:38:08 +0200
commit8b038ab976011a715c495207a750e7cc42165d06 (patch)
tree85d651247736a094ab066fbab0a7af0e3486b417 /lib/ext/session_ticket.c
parent426cc51abcf68c4e9291c283214fff9ff955cfda (diff)
downloadgnutls-8b038ab976011a715c495207a750e7cc42165d06.tar.gz
The auth_ and ext_ files were moved to respective directories.
Diffstat (limited to 'lib/ext/session_ticket.c')
-rw-r--r--lib/ext/session_ticket.c743
1 files changed, 743 insertions, 0 deletions
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c
new file mode 100644
index 0000000000..34bbad7606
--- /dev/null
+++ b/lib/ext/session_ticket.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <gnutls_algorithms.h>
+#include <gnutls_handshake.h>
+#include <gnutls_num.h>
+#include <gnutls_constate.h>
+#include <gnutls_session_pack.h>
+#include <random.h>
+#include <ext/session_ticket.h>
+#include <gnutls_mbuffers.h>
+#include <gnutls_extensions.h>
+#include <gnutls_constate.h>
+
+#ifdef ENABLE_SESSION_TICKET
+
+#define KEY_NAME_SIZE SESSION_TICKET_KEY_NAME_SIZE
+#define KEY_SIZE SESSION_TICKET_KEY_SIZE
+#define IV_SIZE SESSION_TICKET_IV_SIZE
+#define MAC_SECRET_SIZE SESSION_TICKET_MAC_SECRET_SIZE
+
+#define MAC_SIZE 32
+
+static int session_ticket_recv_params (gnutls_session_t session,
+ const opaque * data, size_t data_size);
+static int session_ticket_send_params (gnutls_session_t session,
+ gnutls_buffer_st* extdata);
+static int session_ticket_unpack (gnutls_buffer_st * ps,
+ extension_priv_data_t * _priv);
+static int session_ticket_pack (extension_priv_data_t _priv,
+ gnutls_buffer_st * ps);
+static void session_ticket_deinit_data (extension_priv_data_t priv);
+
+extension_entry_st ext_mod_session_ticket = {
+ .name = "SESSION TICKET",
+ .type = GNUTLS_EXTENSION_SESSION_TICKET,
+ .parse_type = GNUTLS_EXT_TLS,
+
+ .recv_func = session_ticket_recv_params,
+ .send_func = session_ticket_send_params,
+ .pack_func = session_ticket_pack,
+ .unpack_func = session_ticket_unpack,
+ .deinit_func = session_ticket_deinit_data,
+};
+
+#define SESSION_KEY_SIZE (SESSION_TICKET_KEY_NAME_SIZE+SESSION_TICKET_KEY_SIZE+SESSION_TICKET_MAC_SECRET_SIZE)
+#define NAME_POS (0)
+#define KEY_POS (SESSION_TICKET_KEY_NAME_SIZE)
+#define MAC_SECRET_POS (SESSION_TICKET_KEY_NAME_SIZE+SESSION_TICKET_KEY_SIZE)
+
+typedef struct
+{
+ int session_ticket_enable;
+ int session_ticket_renew;
+ opaque session_ticket_IV[SESSION_TICKET_IV_SIZE];
+
+ opaque *session_ticket;
+ int session_ticket_len;
+
+ opaque key[SESSION_KEY_SIZE];
+} session_ticket_ext_st;
+
+struct ticket
+{
+ opaque key_name[KEY_NAME_SIZE];
+ opaque IV[IV_SIZE];
+ opaque *encrypted_state;
+ uint16_t encrypted_state_len;
+ opaque mac[MAC_SIZE];
+};
+
+static int
+digest_ticket (const gnutls_datum_t * key, struct ticket *ticket,
+ opaque * digest)
+{
+ digest_hd_st digest_hd;
+ uint16_t length16;
+ int ret;
+
+ ret = _gnutls_hmac_init (&digest_hd, GNUTLS_MAC_SHA256, key->data,
+ key->size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ _gnutls_hmac (&digest_hd, ticket->key_name, KEY_NAME_SIZE);
+ _gnutls_hmac (&digest_hd, ticket->IV, IV_SIZE);
+ length16 = _gnutls_conv_uint16 (ticket->encrypted_state_len);
+ _gnutls_hmac (&digest_hd, &length16, 2);
+ _gnutls_hmac (&digest_hd, ticket->encrypted_state,
+ ticket->encrypted_state_len);
+ _gnutls_hmac_deinit (&digest_hd, digest);
+
+ return 0;
+}
+
+static int
+decrypt_ticket (gnutls_session_t session, session_ticket_ext_st * priv,
+ struct ticket *ticket)
+{
+ cipher_hd_st cipher_hd;
+ gnutls_datum_t key, IV, mac_secret, state;
+ opaque final[MAC_SECRET_SIZE];
+ time_t timestamp = time (0);
+ int ret;
+
+ /* Check the integrity of ticket using HMAC-SHA-256. */
+ mac_secret.data = (void *) &priv->key[MAC_SECRET_POS];
+ mac_secret.size = MAC_SECRET_SIZE;
+ ret = digest_ticket (&mac_secret, ticket, final);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ if (memcmp (ticket->mac, final, MAC_SIZE))
+ {
+ gnutls_assert ();
+ return GNUTLS_E_DECRYPTION_FAILED;
+ }
+
+ /* Decrypt encrypted_state using 128-bit AES in CBC mode. */
+ key.data = (void *) &priv->key[KEY_POS];
+ key.size = KEY_SIZE;
+ IV.data = ticket->IV;
+ IV.size = IV_SIZE;
+ ret =
+ _gnutls_cipher_init (&cipher_hd, GNUTLS_CIPHER_AES_128_CBC, &key, &IV);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ ret = _gnutls_cipher_decrypt (&cipher_hd, ticket->encrypted_state,
+ ticket->encrypted_state_len);
+ _gnutls_cipher_deinit (&cipher_hd);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* Unpack security parameters. */
+ state.data = ticket->encrypted_state;
+ state.size = ticket->encrypted_state_len;
+ ret = _gnutls_session_unpack (session, &state);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ if (timestamp - session->internals.resumed_security_parameters.timestamp >
+ session->internals.expire_time
+ || session->internals.resumed_security_parameters.timestamp > timestamp)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_EXPIRED;
+ }
+
+ session->internals.resumed = RESUME_TRUE;
+
+ return 0;
+}
+
+static int
+encrypt_ticket (gnutls_session_t session, session_ticket_ext_st * priv,
+ struct ticket *ticket)
+{
+ cipher_hd_st cipher_hd;
+ gnutls_datum_t key, IV, mac_secret, state, encrypted_state;
+ int blocksize;
+ int ret;
+
+ /* Pack security parameters. */
+ ret = _gnutls_session_pack (session, &state);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ blocksize = gnutls_cipher_get_block_size (GNUTLS_CIPHER_AES_128_CBC);
+
+ encrypted_state.size =
+ ((state.size + blocksize - 1) / blocksize) * blocksize;
+ encrypted_state.data = gnutls_malloc (encrypted_state.size);
+ if (!encrypted_state.data)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&state);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ memset (encrypted_state.data, 0, encrypted_state.size);
+ memcpy (encrypted_state.data, state.data, state.size);
+ _gnutls_free_datum (&state);
+
+ /* Encrypt state using 128-bit AES in CBC mode. */
+ key.data = (void *) &priv->key[KEY_POS];
+ key.size = KEY_SIZE;
+ IV.data = priv->session_ticket_IV;
+ IV.size = IV_SIZE;
+ ret =
+ _gnutls_cipher_init (&cipher_hd, GNUTLS_CIPHER_AES_128_CBC, &key, &IV);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&encrypted_state);
+ return ret;
+ }
+
+ ret = _gnutls_cipher_encrypt (&cipher_hd, encrypted_state.data,
+ encrypted_state.size);
+ _gnutls_cipher_deinit (&cipher_hd);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&encrypted_state);
+ return ret;
+ }
+
+ /* Fill the ticket structure to compute MAC. */
+ memcpy (ticket->key_name, &priv->key[NAME_POS], KEY_NAME_SIZE);
+ memcpy (ticket->IV, IV.data, IV.size);
+ ticket->encrypted_state_len = encrypted_state.size;
+ ticket->encrypted_state = encrypted_state.data;
+
+ mac_secret.data = &priv->key[MAC_SECRET_POS];
+ mac_secret.size = MAC_SECRET_SIZE;
+ ret = digest_ticket (&mac_secret, ticket, ticket->mac);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&encrypted_state);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+session_ticket_recv_params (gnutls_session_t session,
+ const opaque * data, size_t _data_size)
+{
+ ssize_t data_size = _data_size;
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+ int ret;
+
+ ret =
+ _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret < 0)
+ {
+ return 0;
+ }
+ priv = epriv.ptr;
+
+ if (!priv->session_ticket_enable)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ {
+ struct ticket ticket;
+ const opaque *encrypted_state;
+ int ret;
+
+ /* The client requested a new session ticket. */
+ if (data_size == 0)
+ {
+ priv->session_ticket_renew = 1;
+ return 0;
+ }
+
+ DECR_LEN (data_size, KEY_NAME_SIZE);
+ memcpy (ticket.key_name, data, KEY_NAME_SIZE);
+ data += KEY_NAME_SIZE;
+
+ /* If the key name of the ticket does not match the one that we
+ hold, issue a new ticket. */
+ if (memcmp (ticket.key_name, &priv->key[NAME_POS], KEY_NAME_SIZE))
+ {
+ priv->session_ticket_renew = 1;
+ return 0;
+ }
+
+ DECR_LEN (data_size, IV_SIZE);
+ memcpy (ticket.IV, data, IV_SIZE);
+ data += IV_SIZE;
+
+ DECR_LEN (data_size, 2);
+ ticket.encrypted_state_len = _gnutls_read_uint16 (data);
+ data += 2;
+
+ encrypted_state = data;
+
+ DECR_LEN (data_size, ticket.encrypted_state_len);
+ data += ticket.encrypted_state_len;
+
+ DECR_LEN (data_size, MAC_SIZE);
+ memcpy (ticket.mac, data, MAC_SIZE);
+
+ ticket.encrypted_state = gnutls_malloc (ticket.encrypted_state_len);
+ if (!ticket.encrypted_state)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ memcpy (ticket.encrypted_state, encrypted_state,
+ ticket.encrypted_state_len);
+
+ ret = decrypt_ticket (session, priv, &ticket);
+ gnutls_free (ticket.encrypted_state);
+ if (ret < 0)
+ {
+ priv->session_ticket_renew = 1;
+ return 0;
+ }
+ }
+ else /* Client */
+ {
+ if (data_size == 0)
+ {
+ priv->session_ticket_renew = 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* returns a positive number if we send the extension data, zero if we
+ do not want to send it, and a negative number on failure.
+ */
+static int
+session_ticket_send_params (gnutls_session_t session,
+ gnutls_buffer_st * extdata)
+{
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+ int ret;
+
+ ret =
+ _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret >= 0)
+ priv = epriv.ptr;
+
+ if (priv == NULL || !priv->session_ticket_enable)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ {
+ if (priv && priv->session_ticket_renew)
+ {
+ return GNUTLS_E_INT_RET_0;
+ }
+ }
+ else
+ {
+ ret =
+ _gnutls_ext_get_resumed_session_data (session,
+ GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret >= 0)
+ priv = epriv.ptr;
+
+ /* no previous data. Just advertize it */
+ if (ret < 0)
+ return GNUTLS_E_INT_RET_0;
+
+ /* previous data had session tickets disabled. Don't advertize. Ignore. */
+ if (!priv->session_ticket_enable)
+ return 0;
+
+ if (priv->session_ticket_len > 0)
+ {
+ ret = _gnutls_buffer_append_data( extdata, priv->session_ticket, priv->session_ticket_len);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return priv->session_ticket_len;
+ }
+ }
+ return 0;
+}
+
+
+static void
+session_ticket_deinit_data (extension_priv_data_t epriv)
+{
+ session_ticket_ext_st *priv = epriv.ptr;
+
+ gnutls_free (priv->session_ticket);
+ gnutls_free (priv);
+}
+
+static int
+session_ticket_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
+{
+ session_ticket_ext_st *priv = epriv.ptr;
+ int ret;
+
+ BUFFER_APPEND_PFX (ps, priv->session_ticket, priv->session_ticket_len);
+ BUFFER_APPEND_NUM (ps, priv->session_ticket_enable);
+
+ return 0;
+}
+
+static int
+session_ticket_unpack (gnutls_buffer_st * ps, extension_priv_data_t * _priv)
+{
+ session_ticket_ext_st *priv = NULL;
+ int ret;
+ extension_priv_data_t epriv;
+ gnutls_datum_t ticket;
+
+ priv = gnutls_calloc (1, sizeof (*priv));
+ if (priv == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ BUFFER_POP_DATUM (ps, &ticket);
+ priv->session_ticket = ticket.data;
+ priv->session_ticket_len = ticket.size;
+ BUFFER_POP_NUM (ps, priv->session_ticket_enable);
+
+ epriv.ptr = priv;
+ *_priv = epriv;
+
+ return 0;
+
+error:
+ gnutls_free (priv);
+ return ret;
+}
+
+
+
+/**
+ * gnutls_session_ticket_key_generate:
+ * @key: is a pointer to a #gnutls_datum_t which will contain a newly
+ * created key.
+ *
+ * Generate a random key to encrypt security parameters within
+ * SessionTicket.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int
+gnutls_session_ticket_key_generate (gnutls_datum_t * key)
+{
+ return gnutls_key_generate(key, SESSION_KEY_SIZE);
+}
+
+/**
+ * gnutls_session_ticket_enable_client:
+ * @session: is a #gnutls_session_t structure.
+ *
+ * Request that the client should attempt session resumption using
+ * SessionTicket.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int
+gnutls_session_ticket_enable_client (gnutls_session_t session)
+{
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+
+ if (!session)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ priv = gnutls_calloc (1, sizeof (*priv));
+ if (priv == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ priv->session_ticket_enable = 1;
+ epriv.ptr = priv;
+
+ _gnutls_ext_set_session_data (session,
+ GNUTLS_EXTENSION_SESSION_TICKET, epriv);
+
+ return 0;
+}
+
+/**
+ * gnutls_session_ticket_enable_server:
+ * @session: is a #gnutls_session_t structure.
+ * @key: key to encrypt session parameters.
+ *
+ * Request that the server should attempt session resumption using
+ * SessionTicket. @key must be initialized with
+ * gnutls_session_ticket_key_generate().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
+ * error code.
+ *
+ * Since: 2.10.0
+ **/
+int
+gnutls_session_ticket_enable_server (gnutls_session_t session,
+ const gnutls_datum_t * key)
+{
+ int ret;
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+
+ if (!session || !key
+ || key->size != SESSION_KEY_SIZE)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ priv = gnutls_calloc (1, sizeof (*priv));
+ if (priv == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ epriv.ptr = priv;
+
+ ret = _gnutls_rnd (GNUTLS_RND_NONCE, priv->session_ticket_IV, IV_SIZE);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ memcpy (&priv->key, key->data, key->size);
+ priv->session_ticket_enable = 1;
+
+ _gnutls_ext_set_session_data (session,
+ GNUTLS_EXTENSION_SESSION_TICKET, epriv);
+
+ return 0;
+}
+
+int
+_gnutls_send_new_session_ticket (gnutls_session_t session, int again)
+{
+ mbuffer_st *bufel = NULL;
+ uint8_t *data = NULL, *p;
+ int data_size = 0;
+ int ret;
+ struct ticket ticket;
+ uint16_t ticket_len;
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+ uint16_t epoch_saved = session->security_parameters.epoch_write;
+
+ if (again == 0)
+ {
+ ret =
+ _gnutls_ext_get_session_data (session,
+ GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret < 0)
+ return 0;
+ priv = epriv.ptr;
+
+ if (!priv->session_ticket_renew)
+ return 0;
+
+ /* XXX: Temporarily set write algorithms to be used.
+ _gnutls_write_connection_state_init() does this job, but it also
+ triggers encryption, while NewSessionTicket should not be
+ encrypted in the record layer. */
+ ret =
+ _gnutls_epoch_set_keys (session,
+ session->security_parameters.epoch_next);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ session->security_parameters.epoch_write =
+ session->security_parameters.epoch_next;
+
+ ret = encrypt_ticket (session, priv, &ticket);
+ session->security_parameters.epoch_write = epoch_saved;
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + ticket.encrypted_state_len
+ + MAC_SIZE;
+
+ bufel = _gnutls_handshake_alloc (session, 4 + 2 + ticket_len, 4+2+ticket_len);
+ if (!bufel)
+ {
+ gnutls_assert ();
+ gnutls_free (ticket.encrypted_state);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ data = _mbuffer_get_udata_ptr (bufel);
+ p = data;
+
+ _gnutls_write_uint32 (session->internals.expire_time, p);
+ p += 4;
+
+ _gnutls_write_uint16 (ticket_len, p);
+ p += 2;
+
+ memcpy (p, ticket.key_name, KEY_NAME_SIZE);
+ p += KEY_NAME_SIZE;
+
+ memcpy (p, ticket.IV, IV_SIZE);
+ p += IV_SIZE;
+
+ _gnutls_write_uint16 (ticket.encrypted_state_len, p);
+ p += 2;
+
+ memcpy (p, ticket.encrypted_state, ticket.encrypted_state_len);
+ gnutls_free (ticket.encrypted_state);
+ p += ticket.encrypted_state_len;
+
+ memcpy (p, ticket.mac, MAC_SIZE);
+ p += MAC_SIZE;
+
+ data_size = p - data;
+ }
+ return _gnutls_send_handshake (session, data_size ? bufel : NULL,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
+}
+
+int
+_gnutls_recv_new_session_ticket (gnutls_session_t session)
+{
+ uint8_t *p;
+ int data_size;
+ gnutls_buffer_st buf;
+ uint32_t lifetime_hint;
+ uint16_t ticket_len;
+ int ret;
+ session_ticket_ext_st *priv = NULL;
+ extension_priv_data_t epriv;
+
+ ret =
+ _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SESSION_TICKET,
+ &epriv);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return 0;
+ }
+ priv = epriv.ptr;
+
+ if (!priv->session_ticket_renew)
+ return 0;
+
+ ret = _gnutls_recv_handshake (session,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
+ MANDATORY_PACKET, &buf);
+ if (ret < 0)
+ return gnutls_assert_val_fatal(ret);
+
+ p = buf.data;
+ data_size = buf.length;
+
+ DECR_LENGTH_COM (data_size, 4, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
+ lifetime_hint = _gnutls_read_uint32 (p);
+ p += 4;
+
+ DECR_LENGTH_COM (data_size, 2, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
+ ticket_len = _gnutls_read_uint16 (p);
+ p += 2;
+
+ DECR_LENGTH_COM (data_size, ticket_len, ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; goto error);
+ priv->session_ticket = gnutls_realloc (priv->session_ticket, ticket_len);
+ if (!priv->session_ticket)
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+ memcpy (priv->session_ticket, p, ticket_len);
+ priv->session_ticket_len = ticket_len;
+
+ /* Discard the current session ID. (RFC5077 3.4) */
+ ret = _gnutls_generate_session_id (session->security_parameters.session_id,
+ &session->
+ security_parameters.session_id_size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ gnutls_free (priv->session_ticket);
+ priv->session_ticket = NULL;
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto error;
+ }
+ ret = 0;
+
+error:
+ _gnutls_buffer_clear (&buf);
+
+ return ret;
+}
+
+#endif