diff options
author | Daiki Ueno <ueno@unixuser.org> | 2009-08-19 16:53:07 +0900 |
---|---|---|
committer | Simon Josefsson <simon@josefsson.org> | 2009-08-19 14:54:50 +0200 |
commit | 979cc233a4a6795e4af1c2f67e3276834e717ccf (patch) | |
tree | ae6433553519d26776e62cd0e6dd402c04034034 | |
parent | bdee4a4266b71eedd05938d139e0be50ce1dec8a (diff) | |
download | gnutls-979cc233a4a6795e4af1c2f67e3276834e717ccf.tar.gz |
session ticket support
Signed-off-by: Simon Josefsson <simon@josefsson.org>
-rw-r--r-- | doc/TODO | 1 | ||||
-rw-r--r-- | lib/Makefile.am | 8 | ||||
-rw-r--r-- | lib/ext_session_ticket.c | 622 | ||||
-rw-r--r-- | lib/ext_session_ticket.h | 35 | ||||
-rw-r--r-- | lib/gnutls_constate.c | 6 | ||||
-rw-r--r-- | lib/gnutls_extensions.c | 29 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 59 | ||||
-rw-r--r-- | lib/gnutls_int.h | 24 | ||||
-rw-r--r-- | lib/gnutls_session_pack.c | 40 | ||||
-rw-r--r-- | lib/gnutls_state.c | 4 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 7 | ||||
-rw-r--r-- | lib/libgnutls.map | 3 | ||||
-rw-r--r-- | lib/m4/hooks.m4 | 14 | ||||
-rw-r--r-- | src/cli.c | 5 | ||||
-rw-r--r-- | src/cli.gaa | 5 | ||||
-rw-r--r-- | src/serv.c | 18 | ||||
-rw-r--r-- | src/serv.gaa | 5 | ||||
-rw-r--r-- | tests/resume.c | 109 |
18 files changed, 948 insertions, 46 deletions
@@ -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 *) @@ -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. |