summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <ueno@unixuser.org>2009-08-19 16:53:07 +0900
committerSimon Josefsson <simon@josefsson.org>2009-08-19 14:54:50 +0200
commit979cc233a4a6795e4af1c2f67e3276834e717ccf (patch)
treeae6433553519d26776e62cd0e6dd402c04034034
parentbdee4a4266b71eedd05938d139e0be50ce1dec8a (diff)
downloadgnutls-979cc233a4a6795e4af1c2f67e3276834e717ccf.tar.gz
session ticket support
Signed-off-by: Simon Josefsson <simon@josefsson.org>
-rw-r--r--doc/TODO1
-rw-r--r--lib/Makefile.am8
-rw-r--r--lib/ext_session_ticket.c622
-rw-r--r--lib/ext_session_ticket.h35
-rw-r--r--lib/gnutls_constate.c6
-rw-r--r--lib/gnutls_extensions.c29
-rw-r--r--lib/gnutls_handshake.c59
-rw-r--r--lib/gnutls_int.h24
-rw-r--r--lib/gnutls_session_pack.c40
-rw-r--r--lib/gnutls_state.c4
-rw-r--r--lib/includes/gnutls/gnutls.h.in7
-rw-r--r--lib/libgnutls.map3
-rw-r--r--lib/m4/hooks.m414
-rw-r--r--src/cli.c5
-rw-r--r--src/cli.gaa5
-rw-r--r--src/serv.c18
-rw-r--r--src/serv.gaa5
-rw-r--r--tests/resume.c109
18 files changed, 948 insertions, 46 deletions
diff --git a/doc/TODO b/doc/TODO
index 86f144ba68..d561d57e97 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -50,7 +50,6 @@ Current list:
be able to execve a new process that take over the current
living socket (using the fcntl close-on-exec flag) and
continue the TLS session as well.
-- Implement draft-salowey-tls-ticket-05, useful for (e.g.) EAP-FAST.
- Reduce memory footprint
- Inside gnutls_global_init, the library allocates about 64 kb of
memory in almost 4000 calls to malloc. On my desktop, there are 22
diff --git a/lib/Makefile.am b/lib/Makefile.am
index efc89dac0a..ad189b90ad 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -63,6 +63,8 @@ PSK_COBJECTS = auth_psk.c auth_psk_passwd.c gnutls_psk.c \
OPRFI_COBJECTS = ext_oprfi.c
+SESSION_TICKET_COBJECTS = ext_session_ticket.c
+
COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \
gnutls_buffers.c gnutls_handshake.c gnutls_num.c \
gnutls_errors.c gnutls_algorithms.c gnutls_dh.c gnutls_kx.c \
@@ -97,12 +99,14 @@ HFILES = debug.h gnutls_compress.h gnutls_cipher.h gnutls_buffers.h \
gnutls_rsa_export.h ext_server_name.h auth_dh_common.h \
ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h \
gnutls_helper.h auth_psk.h auth_psk_passwd.h \
- gnutls_supplemental.h ext_oprfi.h crypto.h random.h
+ gnutls_supplemental.h ext_oprfi.h crypto.h random.h \
+ ext_session_ticket.h
# Separate so we can create the documentation
libgnutls_la_SOURCES = $(HFILES) $(COBJECTS) $(SRP_COBJECTS) \
- $(PSK_COBJECTS) gnutls.asn pkix.asn libgnutls.map
+ $(PSK_COBJECTS) $(SESSION_TICKET_COBJECTS) \
+ gnutls.asn pkix.asn libgnutls.map
libgnutls_la_LDFLAGS = -no-undefined \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/lib/ext_session_ticket.c b/lib/ext_session_ticket.c
new file mode 100644
index 0000000000..b8cd8a2fc8
--- /dev/null
+++ b/lib/ext_session_ticket.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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>
+
+#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
+
+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, struct ticket *ticket)
+{
+ cipher_hd_st cipher_hd;
+ gnutls_datum_t key, IV, mac_secret, state;
+ opaque final[32];
+ time_t timestamp = time (0);
+ int ret;
+
+ /* Check the integrity of ticket using HMAC-SHA-256. */
+ mac_secret.data = session->security_parameters.extensions.
+ session_ticket_key->mac_secret;
+ 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 = session->security_parameters.extensions.
+ session_ticket_key->key;
+ 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, 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 = session->security_parameters.extensions.session_ticket_key->key;
+ key.size = KEY_SIZE;
+ IV.data = session->security_parameters.extensions.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,
+ session->security_parameters.extensions.
+ session_ticket_key->key_name,
+ 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 = session->security_parameters.extensions.
+ session_ticket_key->mac_secret;
+ 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;
+}
+
+int
+_gnutls_session_ticket_recv_params (gnutls_session_t session,
+ const opaque * data, size_t _data_size)
+{
+ ssize_t data_size = _data_size;
+
+ if (!session->internals.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)
+ {
+ session->internals.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,
+ session->security_parameters.extensions.
+ session_ticket_key->key_name,
+ KEY_NAME_SIZE))
+ {
+ session->internals.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, &ticket);
+ gnutls_free (ticket.encrypted_state);
+ if (ret < 0)
+ {
+ session->internals.session_ticket_renew = 1;
+ return 0;
+ }
+ }
+ else
+ {
+ if (data_size == 0)
+ {
+ session->internals.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.
+ */
+int
+_gnutls_session_ticket_send_params (gnutls_session_t session,
+ opaque * data, size_t _data_size)
+{
+ ssize_t data_size = _data_size;
+
+ if (!session->internals.session_ticket_enable)
+ return 0;
+
+ if (session->security_parameters.entity == GNUTLS_SERVER)
+ {
+ if (session->internals.session_ticket_renew)
+ {
+ return GNUTLS_E_INT_RET_0;
+ }
+ }
+ else
+ {
+ if (session->internals.resumed_security_parameters.extensions.
+ session_ticket_len > 0)
+ {
+ DECR_LENGTH_RET (data_size,
+ session->internals.resumed_security_parameters.
+ extensions.session_ticket_len,
+ GNUTLS_E_SHORT_MEMORY_BUFFER);
+ memcpy (data,
+ session->internals.resumed_security_parameters.extensions.
+ session_ticket,
+ session->internals.resumed_security_parameters.extensions.
+ session_ticket_len);
+
+ return session->internals.resumed_security_parameters.
+ extensions.session_ticket_len;
+ }
+ else
+ {
+ return GNUTLS_E_INT_RET_0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * 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.
+ **/
+int
+gnutls_session_ticket_key_generate (gnutls_datum_t *key)
+{
+ int ret;
+
+ key->size = sizeof(struct gnutls_session_ticket_key_st);
+ key->data = gnutls_malloc (key->size);
+ if (!key->data)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ret = _gnutls_rnd (GNUTLS_RND_RANDOM, key->data, key->size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (key);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * 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.
+ **/
+int
+gnutls_session_ticket_enable_client (gnutls_session_t session)
+{
+ if (!session)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ session->internals.session_ticket_enable = 1;
+ 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.
+ **/
+int
+gnutls_session_ticket_enable_server (gnutls_session_t session,
+ const gnutls_datum_t *key)
+{
+ int ret;
+
+ if (!session || !key
+ || key->size != sizeof(struct gnutls_session_ticket_key_st))
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = _gnutls_rnd (GNUTLS_RND_RANDOM,
+ session->security_parameters.extensions.
+ session_ticket_IV, IV_SIZE);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ session->security_parameters.extensions.session_ticket_key =
+ (struct gnutls_session_ticket_key_st *)key->data;
+ session->internals.session_ticket_enable = 1;
+ return 0;
+}
+
+int
+_gnutls_send_new_session_ticket (gnutls_session_t session, int again)
+{
+ uint8_t *data = NULL, *p;
+ int data_size = 0;
+ int ret;
+ struct ticket ticket;
+ uint16_t ticket_len;
+ gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
+ gnutls_mac_algorithm_t write_mac_algorithm;
+ gnutls_compression_method_t write_compression_algorithm;
+
+#define SAVE_WRITE_SECURITY_PARAMETERS \
+ do \
+ { \
+ write_bulk_cipher_algorithm = \
+ session->security_parameters.write_bulk_cipher_algorithm; \
+ write_mac_algorithm = \
+ session->security_parameters.write_mac_algorithm; \
+ write_compression_algorithm = \
+ session->security_parameters.write_compression_algorithm; \
+ } \
+ while (0)
+
+#define RESTORE_WRITE_SECURITY_PARAMETERS \
+ do \
+ { \
+ session->security_parameters.write_bulk_cipher_algorithm = \
+ write_bulk_cipher_algorithm; \
+ session->security_parameters.write_mac_algorithm = \
+ write_mac_algorithm; \
+ session->security_parameters.write_compression_algorithm = \
+ write_compression_algorithm; \
+ } \
+ while (0)
+
+ if (again == 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. */
+ SAVE_WRITE_SECURITY_PARAMETERS;
+ ret = _gnutls_set_write_cipher (session,
+ _gnutls_cipher_suite_get_cipher_algo
+ (&session->security_parameters.
+ current_cipher_suite));
+ if (ret < 0)
+ return ret;
+ ret = _gnutls_set_write_mac (session,
+ _gnutls_cipher_suite_get_mac_algo
+ (&session->security_parameters.
+ current_cipher_suite));
+ if (ret < 0)
+ return ret;
+ ret = _gnutls_set_write_compression (session,
+ session->internals.
+ compression_method);
+ if (ret < 0)
+ return ret;
+
+ ret = encrypt_ticket (session, &ticket);
+ RESTORE_WRITE_SECURITY_PARAMETERS;
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + ticket.encrypted_state_len
+ + MAC_SIZE;
+
+ data = gnutls_malloc (4 + 2 + ticket_len);
+ if (!data)
+ {
+ gnutls_assert ();
+ gnutls_free (ticket.encrypted_state);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ p = data;
+ /* FIXME: ticket lifetime is fixed to 10 days, which should be
+ customizable. */
+ _gnutls_write_uint32 (864000, 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;
+ }
+
+ ret = _gnutls_send_handshake (session, data_size ? data : NULL, data_size,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
+ gnutls_free (data);
+
+ return ret;
+}
+
+int
+_gnutls_recv_new_session_ticket (gnutls_session_t session)
+{
+ uint8_t *data = NULL, *p;
+ int data_size;
+ uint32_t lifetime_hint;
+ uint16_t ticket_len;
+ int ret;
+
+ ret = _gnutls_recv_handshake (session, &data, &data_size,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
+ MANDATORY_PACKET);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ p = data;
+ DECR_LENGTH_COM (data_size, 4, goto error);
+ lifetime_hint = _gnutls_read_uint32 (p);
+ p += 4;
+
+ DECR_LENGTH_COM (data_size, 2, goto error);
+ ticket_len = _gnutls_read_uint16 (p);
+ p += 2;
+
+ DECR_LENGTH_COM (data_size, ticket_len, goto error);
+ session->security_parameters.extensions.session_ticket =
+ gnutls_realloc (session->security_parameters.extensions.session_ticket,
+ ticket_len);
+ if (!session->security_parameters.extensions.session_ticket)
+ {
+ gnutls_assert ();
+ gnutls_free (data);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ memcpy (session->security_parameters.extensions.session_ticket,
+ p, ticket_len);
+ gnutls_free (data);
+ session->security_parameters.extensions.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 (data);
+ gnutls_free (session->security_parameters.extensions.session_ticket);
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+ return 0;
+
+ error:
+ gnutls_free (data);
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+}
+
+#endif
diff --git a/lib/ext_session_ticket.h b/lib/ext_session_ticket.h
new file mode 100644
index 0000000000..5f6e29c4fa
--- /dev/null
+++ b/lib/ext_session_ticket.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Daiki Ueno
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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
+ *
+ */
+
+#ifdef ENABLE_SESSION_TICKET
+
+int _gnutls_session_ticket_recv_params (gnutls_session_t session,
+ const opaque * data, size_t data_size);
+int _gnutls_session_ticket_send_params (gnutls_session_t session,
+ opaque * data, size_t data_size);
+
+int _gnutls_send_new_session_ticket (gnutls_session_t session, int again);
+int _gnutls_recv_new_session_ticket (gnutls_session_t session);
+
+#endif
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index 521e55f542..9afd897092 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -486,9 +486,12 @@ _gnutls_read_connection_state_init (gnutls_session_t session)
}
else
{ /* RESUME_TRUE */
+ opaque *session_ticket =
+ session->security_parameters.extensions.session_ticket;
_gnutls_cpy_read_security_parameters (&session->security_parameters,
&session->internals.
resumed_security_parameters);
+ session->security_parameters.extensions.session_ticket = session_ticket;
}
@@ -668,9 +671,12 @@ _gnutls_write_connection_state_init (gnutls_session_t session)
}
else
{ /* RESUME_TRUE */
+ opaque *session_ticket =
+ session->security_parameters.extensions.session_ticket;
_gnutls_cpy_write_security_parameters (&session->security_parameters,
&session->internals.
resumed_security_parameters);
+ session->security_parameters.extensions.session_ticket = session_ticket;
}
rc = _gnutls_set_write_keys (session);
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index 31769d248a..8cf5ed03cc 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -35,6 +35,7 @@
#include <ext_server_name.h>
#include <ext_oprfi.h>
#include <ext_srp.h>
+#include <ext_session_ticket.h>
#include <gnutls_num.h>
typedef struct
@@ -42,7 +43,18 @@ typedef struct
const char *name;
uint16_t type;
gnutls_ext_parse_type_t parse_type;
+
+ /* this function must return 0 when Not Applicable
+ * size of extension data if ok
+ * < 0 on other error.
+ */
gnutls_ext_recv_func recv_func;
+
+ /* this function must return 0 when Not Applicable
+ * size of extension data if ok
+ * GNUTLS_E_INT_RET_0 if extension data size is zero
+ * < 0 on other error.
+ */
gnutls_ext_send_func send_func;
} gnutls_extension_entry;
@@ -197,7 +209,7 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
int size;
uint16_t pos = 0;
opaque *sdata;
- int sdata_size;
+ size_t sdata_size;
size_t i;
if (data_size < 2)
@@ -225,8 +237,11 @@ _gnutls_gen_extensions (gnutls_session_t session, opaque * data,
continue;
size = p->send_func (session, sdata, sdata_size);
- if (size > 0)
+ if (size > 0 || size == GNUTLS_E_INT_RET_0)
{
+ if (size == GNUTLS_E_INT_RET_0)
+ size = 0;
+
if (data_size < pos + (size_t) size + 4)
{
gnutls_assert ();
@@ -324,6 +339,16 @@ _gnutls_ext_init (void)
return ret;
#endif
+#ifdef ENABLE_SESSION_TICKET
+ ret = gnutls_ext_register (GNUTLS_EXTENSION_SESSION_TICKET,
+ "SESSION_TICKET",
+ GNUTLS_EXT_TLS,
+ _gnutls_session_ticket_recv_params,
+ _gnutls_session_ticket_send_params);
+ if (ret != GNUTLS_E_SUCCESS)
+ return ret;
+#endif
+
return GNUTLS_E_SUCCESS;
}
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 5ccd31746a..1b8512830c 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -48,6 +48,7 @@
#include <gnutls_record.h>
#include <gnutls_state.h>
#include <ext_srp.h>
+#include <ext_session_ticket.h>
#include <gnutls_rsa_export.h> /* for gnutls_get_rsa_params() */
#include <auth_anon.h> /* for gnutls_anon_server_credentials_t */
#include <auth_psk.h> /* for gnutls_psk_server_credentials_t */
@@ -354,7 +355,7 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
gnutls_protocol_t adv_version;
int neg_version;
int len = datalen;
- opaque rnd[GNUTLS_RANDOM_SIZE], *suite_ptr, *comp_ptr;
+ opaque rnd[GNUTLS_RANDOM_SIZE], *suite_ptr, *comp_ptr, *session_id;
if (session->internals.v2_hello != 0)
{ /* version 2.0 */
@@ -399,7 +400,8 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
}
DECR_LEN (len, session_id_len);
- ret = _gnutls_server_restore_session (session, &data[pos], session_id_len);
+ session_id = &data[pos];
+ ret = _gnutls_server_restore_session (session, session_id, session_id_len);
pos += session_id_len;
if (ret == 0)
@@ -467,6 +469,24 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
gnutls_assert ();
return ret;
}
+
+ /* resumed by session_ticket extension */
+ if (session->internals.resumed == RESUME_TRUE)
+ {
+ /* to indicate the client that the current session is resumed */
+ memcpy (session->internals.resumed_security_parameters.session_id,
+ session_id, session_id_len);
+ session->internals.resumed_security_parameters.session_id_size =
+ session_id_len;
+
+ session->internals.resumed_security_parameters.max_record_recv_size =
+ session->security_parameters.max_record_recv_size;
+ session->internals.resumed_security_parameters.max_record_send_size =
+ session->security_parameters.max_record_send_size;
+
+ resume_copy_required_values (session);
+ return 0;
+ }
}
/* select an appropriate cipher suite
@@ -1291,6 +1311,7 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
ret = length32;
break;
default:
@@ -2686,6 +2707,23 @@ _gnutls_handshake_common (gnutls_session_t session)
ret = _gnutls_recv_handshake_final (session, TRUE);
IMED_RET ("recv handshake final", ret);
+#ifdef ENABLE_SESSION_TICKET
+ switch (STATE)
+ {
+ case STATE0:
+ case STATE40:
+ if (session->internals.session_ticket_renew)
+ {
+ ret = _gnutls_send_new_session_ticket (session, AGAIN(STATE40));
+ STATE = STATE40;
+ IMED_RET ("send handshake new session ticket", ret);
+ }
+ STATE = STATE0;
+ default:
+ break;
+ }
+#endif
+
ret = _gnutls_send_handshake_final (session, FALSE);
IMED_RET ("send handshake final", ret);
}
@@ -2695,6 +2733,23 @@ _gnutls_handshake_common (gnutls_session_t session)
ret = _gnutls_send_handshake_final (session, TRUE);
IMED_RET ("send handshake final 2", ret);
+#ifdef ENABLE_SESSION_TICKET
+ switch (STATE)
+ {
+ case STATE0:
+ case STATE41:
+ if (session->internals.session_ticket_renew)
+ {
+ ret = _gnutls_recv_new_session_ticket (session);
+ STATE = STATE41;
+ IMED_RET ("recv handshake new session ticket", ret);
+ }
+ STATE = STATE0;
+ default:
+ break;
+ }
+#endif
+
ret = _gnutls_recv_handshake_final (session, FALSE);
IMED_RET ("recv handshake final 2", ret);
}
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index f8c8cebfab..d5f958ec89 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -86,6 +86,12 @@ typedef struct
#define MAX_LOG_SIZE 1024 /* maximum size of log message */
#define MAX_SRP_USERNAME 128
#define MAX_SERVER_NAME_SIZE 128
+#define MAX_SESSION_TICKET_SIZE 65535
+
+#define SESSION_TICKET_KEY_NAME_SIZE 16
+#define SESSION_TICKET_KEY_SIZE 16
+#define SESSION_TICKET_IV_SIZE 16
+#define SESSION_TICKET_MAC_SECRET_SIZE 32
/* we can receive up to MAX_EXT_TYPES extensions.
*/
@@ -149,8 +155,8 @@ typedef enum handshake_state_t
{ STATE0 = 0, STATE1, STATE2,
STATE3, STATE4, STATE5,
STATE6, STATE7, STATE8, STATE9, STATE20 = 20, STATE21,
- STATE30 = 30, STATE31, STATE50 = 50, STATE60 = 60, STATE61, STATE62,
- STATE70, STATE71
+ STATE30 = 30, STATE31, STATE40 = 40, STATE41, STATE50 = 50,
+ STATE60 = 60, STATE61, STATE62, STATE70, STATE71
} handshake_state_t;
#include <gnutls_str.h>
@@ -170,6 +176,7 @@ typedef enum extensions_t
GNUTLS_EXTENSION_OPAQUE_PRF_INPUT = ENABLE_OPRFI,
#endif
GNUTLS_EXTENSION_SRP = 12,
+ GNUTLS_EXTENSION_SESSION_TICKET = 35,
GNUTLS_EXTENSION_INNER_APPLICATION = 37703
} extensions_t;
@@ -281,6 +288,12 @@ typedef struct
#define MAX_SERVER_NAME_EXTENSIONS 3
+struct gnutls_session_ticket_key_st {
+ opaque key_name[SESSION_TICKET_KEY_NAME_SIZE];
+ opaque key[SESSION_TICKET_KEY_SIZE];
+ opaque mac_secret[SESSION_TICKET_MAC_SECRET_SIZE];
+};
+
typedef struct
{
server_name_st server_names[MAX_SERVER_NAME_EXTENSIONS];
@@ -303,6 +316,11 @@ typedef struct
uint16_t oprfi_client_len;
opaque *oprfi_server;
uint16_t oprfi_server_len;
+
+ opaque *session_ticket;
+ uint16_t session_ticket_len;
+ struct gnutls_session_ticket_key_st *session_ticket_key;
+ opaque session_ticket_IV[SESSION_TICKET_IV_SIZE];
} tls_ext_st;
/* auth_info_t structures now MAY contain malloced
@@ -672,6 +690,8 @@ typedef struct
*/
uint16_t srp_prime_bits;
+ int session_ticket_enable, session_ticket_renew;
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} internals_st;
diff --git a/lib/gnutls_session_pack.c b/lib/gnutls_session_pack.c
index 115f17ed1d..dc56b0a431 100644
--- a/lib/gnutls_session_pack.c
+++ b/lib/gnutls_session_pack.c
@@ -280,7 +280,8 @@ pack_certificate_auth_info (gnutls_session_t session,
/* calculate the size and allocate the data.
*/
packed_session->data =
- gnutls_malloc (packed_session->size + MAX_SEC_PARAMS);
+ gnutls_malloc (packed_session->size + MAX_SEC_PARAMS + 2 +
+ session->security_parameters.extensions.session_ticket_len);
if (packed_session->data == NULL)
{
@@ -513,7 +514,8 @@ pack_srp_auth_info (gnutls_session_t session, gnutls_datum_t * packed_session)
/* calculate the size and allocate the data.
*/
packed_session->data =
- gnutls_malloc (packed_session->size + MAX_SEC_PARAMS);
+ gnutls_malloc (packed_session->size + MAX_SEC_PARAMS + 2 +
+ session->security_parameters.extensions.session_ticket_len);
if (packed_session->data == NULL)
{
@@ -618,7 +620,8 @@ pack_anon_auth_info (gnutls_session_t session,
/* calculate the size and allocate the data.
*/
packed_session->data =
- gnutls_malloc (packed_session->size + MAX_SEC_PARAMS);
+ gnutls_malloc (packed_session->size + MAX_SEC_PARAMS + 2 +
+ session->security_parameters.extensions.session_ticket_len);
if (packed_session->data == NULL)
{
@@ -781,7 +784,8 @@ pack_psk_auth_info (gnutls_session_t session, gnutls_datum_t * packed_session)
/* calculate the size and allocate the data.
*/
packed_session->data =
- gnutls_malloc (packed_session->size + MAX_SEC_PARAMS);
+ gnutls_malloc (packed_session->size + MAX_SEC_PARAMS + 2 +
+ session->security_parameters.extensions.session_ticket_len);
if (packed_session->data == NULL)
{
@@ -977,9 +981,11 @@ error:
* 2 bytes the size of the first name
* x bytes the first name (MAX_SERVER_NAME_SIZE)
* and so on...
+ * 2 bytes the session ticket size
+ * x bytes the session ticket (MAX_SESSION_TICKET_SIZE)
*
* --------------------
- * MAX: 7+MAX_SRP_USERNAME+MAX_SERVER_NAME_EXTENSIONS*(3+MAX_SERVER_NAME_SIZE)
+ * MAX: 7+MAX_SRP_USERNAME+MAX_SERVER_NAME_EXTENSIONS*(3+MAX_SERVER_NAME_SIZE)+MAX_SESSION_TICKET_SIZE
*/
static int
pack_security_parameters (gnutls_session_t session,
@@ -1077,6 +1083,15 @@ pack_security_parameters (gnutls_session_t session,
session->security_parameters.extensions.server_names[i].name_length;
}
+ _gnutls_write_uint16 (session->security_parameters.extensions.
+ session_ticket_len,
+ &packed_session->data[pos]);
+ pos += 2;
+ memcpy (&packed_session->data[pos],
+ session->security_parameters.extensions.session_ticket,
+ session->security_parameters.extensions.session_ticket_len);
+ pos += session->security_parameters.extensions.session_ticket_len;
+
/* write the total size */
_gnutls_write_uint32 (pos - init - 4, &packed_session->data[init]);
packed_session->size += pos - init;
@@ -1109,7 +1124,7 @@ unpack_security_parameters (gnutls_session_t session,
return GNUTLS_E_INVALID_REQUEST;
/* a simple check for integrity */
- if (pack_size > MAX_SEC_PARAMS)
+ if (pack_size > MAX_SEC_PARAMS + 2 + MAX_SESSION_TICKET_SIZE)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
@@ -1212,5 +1227,18 @@ unpack_security_parameters (gnutls_session_t session,
session->internals.resumed_security_parameters.extensions.
server_names[i].name_length;
}
+
+ session->internals.resumed_security_parameters.extensions.
+ session_ticket_len = _gnutls_read_uint16 (&packed_session->data[pos]);
+ pos += 2;
+ session->internals.resumed_security_parameters.extensions.session_ticket =
+ gnutls_malloc (session->internals.resumed_security_parameters.extensions.
+ session_ticket_len);
+ memcpy (session->internals.resumed_security_parameters.extensions.
+ session_ticket,
+ &packed_session->data[pos],
+ session->internals.resumed_security_parameters.extensions.
+ session_ticket_len);
+
return 0;
}
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index d9abd556c7..5b5f7a775b 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -433,6 +433,10 @@ gnutls_deinit (gnutls_session_t session)
gnutls_free (session->internals.srp_password);
}
+ gnutls_free (session->security_parameters.extensions.session_ticket);
+ gnutls_free (session->internals.resumed_security_parameters.extensions.
+ session_ticket);
+
memset (session, 0, sizeof (struct gnutls_session_int));
gnutls_free (session);
}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index af27b8dee2..a78fc39d41 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -221,6 +221,7 @@ extern "C" {
{ GNUTLS_HANDSHAKE_HELLO_REQUEST = 0,
GNUTLS_HANDSHAKE_CLIENT_HELLO = 1,
GNUTLS_HANDSHAKE_SERVER_HELLO = 2,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET = 4,
GNUTLS_HANDSHAKE_CERTIFICATE_PKT = 11,
GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE = 12,
GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST = 13,
@@ -554,6 +555,12 @@ extern "C" {
const char *gnutls_supplemental_get_name
(gnutls_supplemental_data_format_type_t type);
+ /* SessionTicket, RFC 5077. */
+ int gnutls_session_ticket_key_generate (gnutls_datum_t *key);
+ int gnutls_session_ticket_enable_client (gnutls_session_t session);
+ int gnutls_session_ticket_enable_server (gnutls_session_t session,
+ const gnutls_datum_t *key);
+
/* functions to set priority of cipher suites
*/
int gnutls_cipher_set_priority (gnutls_session_t session, const int *list);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 73dc6aa33b..63f349768f 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -565,6 +565,9 @@ GNUTLS_2_8
gnutls_x509_crt_get_verify_algorithm;
gnutls_x509_crt_set_crq_extensions;
gnutls_x509_crt_verify_hash;
+ gnutls_session_ticket_key_generate;
+ gnutls_session_ticket_enable_client;
+ gnutls_session_ticket_enable_server;
} GNUTLS_1_4;
GNUTLS_PRIVATE {
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index 95e43e22fa..5e5e0637fd 100644
--- a/lib/m4/hooks.m4
+++ b/lib/m4/hooks.m4
@@ -214,6 +214,20 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
fi
AM_CONDITIONAL(ENABLE_OPENPGP, test "$ac_enable_openpgp" = "yes")
+ AC_MSG_CHECKING([whether to disable SessionTicket extension support])
+ AC_ARG_ENABLE(session-ticket,
+ AS_HELP_STRING([--disable-session-ticket],
+ [disable the SessionTicket extension support]),
+ ac_session_ticket=no)
+ if test x$ac_session_ticket != xno; then
+ AC_MSG_RESULT(no)
+ AC_DEFINE([ENABLE_SESSION_TICKET], 1, [enable SessionTicket extension])
+ else
+ ac_full=0
+ AC_MSG_RESULT(yes)
+ fi
+ AM_CONDITIONAL(ENABLE_SESSION_TICKET, test "$ac_enable_session_ticket" != "no")
+
# For storing integers in pointers without warnings
# http://developer.gnome.org/doc/API/2.0/glib/glib-Type-Conversion-Macros.html#desc
AC_CHECK_SIZEOF(void *)
diff --git a/src/cli.c b/src/cli.c
index ddbb46fb00..36020c6307 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -476,6 +476,11 @@ init_tls_session (const char *hostname)
info.opaque_prf_input);
#endif
+#ifdef ENABLE_SESSION_TICKET
+ if (!info.noticket)
+ gnutls_session_ticket_enable_client (session);
+#endif
+
return session;
}
diff --git a/src/cli.gaa b/src/cli.gaa
index d1672177ad..14d7b3da26 100644
--- a/src/cli.gaa
+++ b/src/cli.gaa
@@ -17,6 +17,9 @@ option (d, debug) INT "integer" { $debug = $1 } "Enable debugging"
#int resume;
option (r, resume) { $resume = 1 } "Connect, establish a session. Connect again and resume this session."
+#int noticket;
+option (noticket) { $noticket = 1 } "Doen't accept session tickets."
+
#int starttls;
option (s, starttls) { $starttls = 1 } "Connect, establish a plain session and start TLS when EOF or a SIGALRM is received."
@@ -121,7 +124,7 @@ option (v, version) { cli_version(); exit(0); } "prints the program's version nu
#char *rest_args;
rest STR "hostname" { $rest_args = $1; }
-init { $resume=0; $port="443"; $rest_args=NULL; $ciphers=NULL;
+init { $resume=0; $noticket=0; $port="443"; $rest_args=NULL; $ciphers=NULL;
$kx=NULL; $comp=NULL; $macs=NULL; $ctype=NULL; $nciphers=0;
$nkx=0; $ncomp=0; $nmacs=0; $nctype = 0; $record_size=0;
$fingerprint=0; $pgp_keyring=NULL; $x509_crlfile = NULL;
diff --git a/src/serv.c b/src/serv.c
index f05a3ac8ab..ede5117b88 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -62,6 +62,7 @@ static int debug;
int verbose;
static int nodb;
+static int noticket;
int require_cert;
int disable_client_cert;
@@ -79,6 +80,8 @@ char *x509_cafile;
char *dh_params_file;
char *x509_crlfile = NULL;
+gnutls_datum_t session_ticket_key;
+
/* end of globals */
/* This is a sample TCP echo server.
@@ -370,6 +373,10 @@ initialize_session (void)
gnutls_db_set_store_function (session, wrap_db_store);
gnutls_db_set_ptr (session, NULL);
}
+#ifdef ENABLE_SESSION_TICKET
+ if (noticket == 0)
+ gnutls_session_ticket_enable_server (session, &session_ticket_key);
+#endif
if (gnutls_priority_set_direct (session, info.priorities, &err) < 0)
{
@@ -1060,6 +1067,11 @@ main (int argc, char **argv)
/* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
#endif
+#ifdef ENABLE_SESSION_TICKET
+ if (noticket == 0)
+ gnutls_session_ticket_key_generate (&session_ticket_key);
+#endif
+
if (listen_socket (name, port) < 0)
exit (1);
@@ -1393,6 +1405,11 @@ main (int argc, char **argv)
gnutls_anon_free_server_credentials (dh_cred);
#endif
+#ifdef ENABLE_SESSION_TICKET
+ if (noticket == 0)
+ gnutls_free (session_ticket_key.data);
+#endif
+
if (nodb == 0)
wrap_db_deinit ();
gnutls_global_deinit ();
@@ -1416,6 +1433,7 @@ gaa_parser (int argc, char **argv)
debug = info.debug;
verbose = info.quiet;
nodb = info.nodb;
+ noticket = info.noticket;
if (info.http == 0)
http = 0;
diff --git a/src/serv.gaa b/src/serv.gaa
index 4fe9870c68..c216e0000e 100644
--- a/src/serv.gaa
+++ b/src/serv.gaa
@@ -24,6 +24,9 @@ option (q, quiet) { $quiet = 1 } "Suppress some messages."
#int nodb;
option (nodb) { $nodb = 1 } "Does not use the resume database."
+#int noticket;
+option (noticket) { $noticket = 1 } "Does not issue session tickets."
+
#int http;
option (http) { $http = 1 } "Act as an HTTP Server."
option (echo) { $http = 0 } "Act as an Echo Server."
@@ -121,7 +124,7 @@ INCOMP ra
init { $generate=0; $port=5556; $http=0; $ciphers=NULL;
$kx=NULL; $comp=NULL; $macs=NULL; $ctype=NULL; $nciphers=0;
- $nkx=0; $ncomp=0; $nmacs=0; $nctype = 0; $nodb = 0;
+ $nkx=0; $ncomp=0; $nmacs=0; $nctype = 0; $nodb = 0; $noticket = 0;
$x509_cafile = NULL; $pgp_keyfile=NULL; $pgp_certfile=NULL;
$x509_keyfile=NULL; $x509_certfile=NULL; $x509_crlfile = NULL;
$x509_dsakeyfile=NULL; $x509_dsacertfile=NULL;
diff --git a/tests/resume.c b/tests/resume.c
index e68a9bbecd..e4d7a2ab80 100644
--- a/tests/resume.c
+++ b/tests/resume.c
@@ -49,6 +49,26 @@ static int wrap_db_delete (void *dbf, gnutls_datum_t key);
#define TLS_SESSION_CACHE 50
+struct params_res
+{
+ const char *desc;
+ int enable_db;
+ int enable_session_ticket_server;
+ int enable_session_ticket_client;
+ int expect_resume;
+};
+
+struct params_res resume_tests[] =
+ {
+ {"try to resume from db", 50, 0, 0, 1},
+#ifdef ENABLE_SESSION_TICKET
+ {"try to resume from session ticket", 0, 1, 1, 1},
+ {"try to resume from session ticket (server only)", 0, 1, 0, 0},
+ {"try to resume from session ticket (client only)", 0, 0, 1, 0},
+#endif
+ {NULL, -1}
+ };
+
/* A very basic TLS client, with anonymous authentication.
*/
@@ -56,7 +76,7 @@ static int wrap_db_delete (void *dbf, gnutls_datum_t key);
#define MSG "Hello TLS"
static void
-client (void)
+client (struct params_res *params)
{
int ret, sd, ii;
gnutls_session_t session;
@@ -93,6 +113,11 @@ client (void)
*/
gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred);
+#ifdef ENABLE_SESSION_TICKET
+ if (params->enable_session_ticket_client)
+ gnutls_session_ticket_enable_client (session);
+#endif
+
if (t > 0)
{
/* if this is not the first time we connect */
@@ -131,11 +156,17 @@ client (void)
/* check if we actually resumed the previous session */
if (gnutls_session_is_resumed (session) != 0)
{
- success ("- Previous session was resumed\n");
+ if (params->expect_resume)
+ success ("- Previous session was resumed\n");
+ else
+ fail ("- Previous session was resumed\n");
}
else
{
- success ("*** Previous session was NOT resumed\n");
+ if (params->expect_resume)
+ fail ("*** Previous session was NOT resumed\n");
+ else
+ success ("*** Previous session was NOT resumed\n");
}
}
@@ -185,9 +216,10 @@ client (void)
/* These are global */
gnutls_anon_server_credentials_t anoncred;
+gnutls_datum_t session_ticket_key;
static gnutls_session_t
-initialize_tls_session (void)
+initialize_tls_session (struct params_res *params)
{
gnutls_session_t session;
const int kx_prio[] = { GNUTLS_KX_ANON_DH, 0 };
@@ -204,13 +236,17 @@ initialize_tls_session (void)
gnutls_dh_set_prime_bits (session, DH_BITS);
- if (TLS_SESSION_CACHE != 0)
+ if (params->enable_db)
{
gnutls_db_set_retrieve_function (session, wrap_db_fetch);
gnutls_db_set_remove_function (session, wrap_db_delete);
gnutls_db_set_store_function (session, wrap_db_store);
gnutls_db_set_ptr (session, NULL);
}
+#ifdef ENABLE_SESSION_TICKET
+ if (params->enable_session_ticket_server)
+ gnutls_session_ticket_enable_server (session, &session_ticket_key);
+#endif
return session;
}
@@ -289,10 +325,12 @@ global_stop (void)
gnutls_dh_params_deinit (dh_params);
gnutls_global_deinit ();
+
+ shutdown (listen_sd, SHUT_RDWR);
}
static void
-server (void)
+server (struct params_res *params)
{
size_t t;
@@ -308,16 +346,20 @@ server (void)
gnutls_anon_set_server_dh_params (anoncred, dh_params);
- if (TLS_SESSION_CACHE != 0)
+ if (params->enable_db)
{
wrap_db_init ();
}
+#ifdef ENABLE_SESSION_TICKET
+ if (params->enable_session_ticket_server)
+ gnutls_session_ticket_key_generate (&session_ticket_key);
+#endif
for (t = 0; t < 2; t++)
{
client_len = sizeof (sa_cli);
- session = initialize_tls_session ();
+ session = initialize_tls_session (params);
sd = accept (listen_sd, (SA *) & sa_cli, &client_len);
@@ -374,7 +416,7 @@ server (void)
close (listen_sd);
- if (TLS_SESSION_CACHE != 0)
+ if (params->enable_db)
{
wrap_db_deinit ();
}
@@ -386,30 +428,39 @@ void
doit (void)
{
pid_t child;
+ int i;
- global_start ();
- if (error_count)
- return;
-
- child = fork ();
- if (child < 0)
+ for (i = 0; resume_tests[i].desc; i++)
{
- perror ("fork");
- fail ("fork");
- return;
- }
+ printf ("%s\n", resume_tests[i].desc);
- if (child)
- {
- int status;
- /* parent */
- server ();
- wait (&status);
- }
- else
- client ();
+ global_start ();
+ if (error_count)
+ return;
+
+ child = fork ();
+ if (child < 0)
+ {
+ perror ("fork");
+ fail ("fork");
+ return;
+ }
- global_stop ();
+ if (child)
+ {
+ int status;
+ /* parent */
+ server (&resume_tests[i]);
+ wait (&status);
+ global_stop ();
+ }
+ else
+ {
+ client (&resume_tests[i]);
+ global_stop ();
+ exit (0);
+ }
+ }
}
/* Functions and other stuff needed for session resuming.