summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2018-07-12 12:57:21 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2018-07-12 12:57:21 +0000
commit3c87793a2ce720bde6cf38c43806ea4ecf2105e2 (patch)
tree70faf951e14ba13755755c2ae7c0f51650fd1997
parent40b5e30494230f1e87d1622f14cf65cce5ba3bc9 (diff)
parentdf738136a71b545c61e639edee7bad4f68271bcc (diff)
downloadgnutls-3c87793a2ce720bde6cf38c43806ea4ecf2105e2.tar.gz
Merge branch 'tmp-fix-multi-async-msg' into 'master'
Fix issue preventing the parsing of certain async messages Closes #510 and #504 See merge request gnutls/gnutls!694
-rw-r--r--lib/buffers.c3
-rw-r--r--lib/gnutls_int.h3
-rw-r--r--lib/handshake-tls13.c182
-rw-r--r--lib/handshake.c14
-rw-r--r--lib/handshake.h7
-rw-r--r--lib/includes/gnutls/gnutls.h.in2
-rw-r--r--lib/record.c47
-rw-r--r--lib/tls13/session_ticket.c104
-rw-r--r--lib/tls13/session_ticket.h2
-rw-r--r--tests/tls13/post-handshake-with-cert-ticket.c53
10 files changed, 265 insertions, 152 deletions
diff --git a/lib/buffers.c b/lib/buffers.c
index 1ea55e33c4..100390b5dc 100644
--- a/lib/buffers.c
+++ b/lib/buffers.c
@@ -1086,6 +1086,9 @@ static int merge_handshake_packet(gnutls_session_t session,
inline static int cmp_hsk_types(gnutls_handshake_description_t expected,
gnutls_handshake_description_t recvd)
{
+ if (expected == GNUTLS_HANDSHAKE_ANY)
+ return 1;
+
#ifdef ENABLE_SSL2
if (expected == GNUTLS_HANDSHAKE_CLIENT_HELLO
&& recvd == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 99287b3726..6525282a69 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -300,7 +300,8 @@ typedef enum recv_state_t {
RECV_STATE_0 = 0,
RECV_STATE_DTLS_RETRANSMIT,
RECV_STATE_FALSE_START_HANDLING, /* we are calling gnutls_handshake() within record_recv() */
- RECV_STATE_FALSE_START /* gnutls_record_recv() should complete the handshake */
+ RECV_STATE_FALSE_START, /* gnutls_record_recv() should complete the handshake */
+ RECV_STATE_ASYNC_HANDSHAKE /* an incomplete async handshake message was seen */
} recv_state_t;
#include "str.h"
diff --git a/lib/handshake-tls13.c b/lib/handshake-tls13.c
index 8a8ae52774..ffd1b1531d 100644
--- a/lib/handshake-tls13.c
+++ b/lib/handshake-tls13.c
@@ -390,7 +390,7 @@ int _gnutls13_handshake_server(gnutls_session_t session)
/* fall through */
case STATE112:
- ret = _gnutls13_send_session_ticket(session, AGAIN(STATE112));
+ ret = _gnutls13_send_session_ticket(session, 1, AGAIN(STATE112));
STATE = STATE112;
IMED_RET("send session ticket", ret, 0);
@@ -412,93 +412,136 @@ int _gnutls13_handshake_server(gnutls_session_t session)
/* Processes handshake messages received asynchronously after initial handshake.
*
- * It is called once per message, with a read-only buffer in @buf,
- * and should return success, or a fatal error code.
+ * It is called once per message and should return success, or a fatal error code.
*/
int
-_gnutls13_recv_async_handshake(gnutls_session_t session, gnutls_buffer_st *buf)
+_gnutls13_recv_async_handshake(gnutls_session_t session)
{
- uint8_t type;
int ret;
- size_t handshake_header_size = HANDSHAKE_HEADER_SIZE(session);
- size_t length;
-
- if (buf->length < handshake_header_size) {
- gnutls_assert();
- return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
- }
+ handshake_buffer_st hsk;
/* The following messages are expected asynchronously after
* the handshake process is complete */
if (unlikely(session->internals.handshake_in_progress))
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
- ret = _gnutls_buffer_pop_prefix8(buf, &type, 0);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ do {
+ /* the received handshake message has already been pushed into
+ * handshake buffers. As we do not need to use the handshake hash
+ * buffers we call the lower level receive functions */
+ ret = _gnutls_handshake_io_recv_int(session, GNUTLS_HANDSHAKE_ANY, &hsk, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ session->internals.last_handshake_in = hsk.htype;
- ret = _gnutls_buffer_pop_prefix24(buf, &length, 1);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ ret = _gnutls_call_hook_func(session, hsk.htype, GNUTLS_HOOK_PRE, 1,
+ hsk.data.data, hsk.data.length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_PRE, 1, buf->data, buf->length);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ switch(hsk.htype) {
+ case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
+ if (!(session->security_parameters.entity == GNUTLS_CLIENT) ||
+ !(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)) {
+ ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+ goto cleanup;
+ }
+
+ _gnutls_buffer_reset(&session->internals.reauth_buffer);
+
+ /* include the handshake headers in reauth buffer */
+ ret = _gnutls_buffer_append_data(&session->internals.reauth_buffer,
+ hsk.header, hsk.header_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data(&session->internals.reauth_buffer,
+ hsk.data.data, hsk.data.length);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Application is expected to handle re-authentication
+ * explicitly. */
+ ret = GNUTLS_E_REAUTH_REQUEST;
+ goto cleanup;
+
+ case GNUTLS_HANDSHAKE_KEY_UPDATE:
+ ret = _gnutls13_recv_key_update(session, &hsk.data);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Handshake messages MUST NOT span key changes, i.e., we
+ * should not have any other pending handshake messages from
+ * the same record. */
+ if (session->internals.handshake_recv_buffer_size != 0) {
+ ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+ goto cleanup;
+ }
+ break;
+ case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
+ if (session->security_parameters.entity != GNUTLS_CLIENT) {
+ ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+ goto cleanup;
+ }
+
+ ret = _gnutls13_recv_session_ticket(session, &hsk.data);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ memcpy(session->internals.tls13_ticket.resumption_master_secret,
+ session->key.proto.tls13.ap_rms,
+ session->key.proto.tls13.temp_secret_size);
+
+ session->internals.tls13_ticket.prf = session->security_parameters.prf;
+ session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
+ break;
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_UNEXPECTED_PACKET;
+ goto cleanup;
+ }
- switch(type) {
- case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
- if (!(session->security_parameters.entity == GNUTLS_CLIENT) ||
- !(session->internals.flags & GNUTLS_POST_HANDSHAKE_AUTH)) {
- return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
- }
-
- _gnutls_buffer_reset(&session->internals.reauth_buffer);
-
- /* include the handshake headers in reauth buffer */
- ret = _gnutls_buffer_append_data(&session->internals.reauth_buffer,
- buf->data-4, buf->length+4);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- /* Application is expected to handle re-authentication
- * explicitly. */
- return GNUTLS_E_REAUTH_REQUEST;
-
- case GNUTLS_HANDSHAKE_KEY_UPDATE:
- ret = _gnutls13_recv_key_update(session, buf);
- if (ret < 0)
- return gnutls_assert_val(ret);
- break;
- case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
- if (session->security_parameters.entity != GNUTLS_CLIENT)
- return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
-
- ret = _gnutls13_recv_session_ticket(session, buf);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- memcpy(session->internals.tls13_ticket.resumption_master_secret,
- session->key.proto.tls13.ap_rms,
- session->key.proto.tls13.temp_secret_size);
-
- session->internals.tls13_ticket.prf = session->security_parameters.prf;
- session->internals.hsk_flags |= HSK_TICKET_RECEIVED;
- break;
- default:
+ ret = _gnutls_call_hook_func(session, hsk.htype, GNUTLS_HOOK_POST, 1, hsk.data.data, hsk.data.length);
+ if (ret < 0) {
gnutls_assert();
- return GNUTLS_E_UNEXPECTED_PACKET;
- }
+ goto cleanup;
+ }
+ _gnutls_handshake_buffer_clear(&hsk);
- ret = _gnutls_call_hook_func(session, type, GNUTLS_HOOK_POST, 1, buf->data, buf->length);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ } while (_gnutls_record_buffer_get_size(session) > 0);
+
+ session->internals.recv_state = RECV_STATE_0;
return 0;
+
+ cleanup:
+ /* if we have pending/partial handshake data in buffers, ensure that
+ * next read will read handshake data */
+ if (_gnutls_record_buffer_get_size(session) > 0)
+ session->internals.recv_state = RECV_STATE_ASYNC_HANDSHAKE;
+ else
+ session->internals.recv_state = RECV_STATE_0;
+
+ _gnutls_handshake_buffer_clear(&hsk);
+ return ret;
}
/**
* gnutls_session_ticket_send:
* @session: is a #gnutls_session_t type.
+ * @nr: the number of tickets to send
* @flags: must be zero
*
* Sends a fresh session ticket to the peer. This is relevant only
@@ -507,7 +550,7 @@ _gnutls13_recv_async_handshake(gnutls_session_t session, gnutls_buffer_st *buf)
*
* Returns: %GNUTLS_E_SUCCESS on success, or a negative error code.
**/
-int gnutls_session_ticket_send(gnutls_session_t session, unsigned flags)
+int gnutls_session_ticket_send(gnutls_session_t session, unsigned nr, unsigned flags)
{
int ret = 0;
const version_entry_st *vers = get_version(session);
@@ -515,6 +558,9 @@ int gnutls_session_ticket_send(gnutls_session_t session, unsigned flags)
if (!vers->tls13_sem || session->security_parameters.entity == GNUTLS_CLIENT)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ if (nr == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
switch (TICKET_STATE) {
case TICKET_STATE0:
ret = _gnutls_io_write_flush(session);
@@ -526,7 +572,7 @@ int gnutls_session_ticket_send(gnutls_session_t session, unsigned flags)
/* fall through */
case TICKET_STATE1:
ret =
- _gnutls13_send_session_ticket(session, TICKET_STATE==TICKET_STATE1?1:0);
+ _gnutls13_send_session_ticket(session, nr, TICKET_STATE==TICKET_STATE1?1:0);
TICKET_STATE = TICKET_STATE1;
if (ret < 0) {
gnutls_assert();
diff --git a/lib/handshake.c b/lib/handshake.c
index dd2e02908c..5feaed99fd 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -1154,14 +1154,21 @@ int _gnutls_call_hook_func(gnutls_session_t session,
(t == GNUTLS_HANDSHAKE_HELLO_REQUEST || t == GNUTLS_HANDSHAKE_KEY_UPDATE || \
(t == GNUTLS_HANDSHAKE_NEW_SESSION_TICKET && v->tls13_sem))
+int
+_gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
+ gnutls_handshake_description_t type)
+{
+ return _gnutls_send_handshake2(session, bufel, type, 0);
+}
+
/* This function sends a handshake message of type 'type' containing the
* data specified here. If the previous _gnutls_send_handshake() returned
* GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED, then it must be called again
* (until it returns ok), with NULL parameters.
*/
int
-_gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
- gnutls_handshake_description_t type)
+_gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel,
+ gnutls_handshake_description_t type, unsigned queue_only)
{
int ret;
uint8_t *data;
@@ -1244,6 +1251,9 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel,
return ret;
}
+ if (queue_only)
+ return 0;
+
/* Decide when to cache and when to send */
if (vers && vers->tls13_sem) {
diff --git a/lib/handshake.h b/lib/handshake.h
index 465ee03b80..248d6a1896 100644
--- a/lib/handshake.h
+++ b/lib/handshake.h
@@ -61,6 +61,11 @@ int _gnutls_recv_hello_request(gnutls_session_t session, void *data,
int _gnutls_recv_handshake(gnutls_session_t session,
gnutls_handshake_description_t type,
unsigned int optional, gnutls_buffer_st * buf);
+
+int
+_gnutls_send_handshake2(gnutls_session_t session, mbuffer_st * bufel,
+ gnutls_handshake_description_t type, unsigned queue_only);
+
int _gnutls_generate_session_id(uint8_t * session_id, uint8_t * len);
int _gnutls_gen_server_random(gnutls_session_t session, int version);
void _gnutls_set_client_random(gnutls_session_t session, uint8_t * rnd);
@@ -159,6 +164,6 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session,
gnutls_buffer_st *buf);
int
-_gnutls13_recv_async_handshake(gnutls_session_t session, gnutls_buffer_st *buf);
+_gnutls13_recv_async_handshake(gnutls_session_t session);
#endif
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index b675035f3e..f57d0d7cc7 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1480,7 +1480,7 @@ 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);
-int gnutls_session_ticket_send(gnutls_session_t session, unsigned flags);
+int gnutls_session_ticket_send(gnutls_session_t session, unsigned nr, unsigned flags);
/* SRTP, RFC 5764 */
diff --git a/lib/record.c b/lib/record.c
index ed82db20a5..9b485fd293 100644
--- a/lib/record.c
+++ b/lib/record.c
@@ -790,6 +790,13 @@ record_add_to_buffers(gnutls_session_t session,
}
}
+ /* application data cannot be inserted between (async) handshake
+ * messages */
+ if (type == GNUTLS_APPLICATION_DATA && session->internals.handshake_recv_buffer_size != 0) {
+ ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
+ goto unexpected_packet;
+ }
+
_gnutls_record_buffer_put(session, type, seq, bufel);
/* if we received application data as expected then we
@@ -956,17 +963,14 @@ record_add_to_buffers(gnutls_session_t session,
/* retrieve async handshake messages */
if (ver && ver->tls13_sem) {
- gnutls_buffer_st buf;
-
- _gnutls_ro_buffer_from_datum(&buf, &bufel->msg);
- ret = _gnutls13_recv_async_handshake(session,
- &buf);
- if (ret < 0) {
- gnutls_assert();
- } else {
- ret = GNUTLS_E_AGAIN;
- }
- goto cleanup;
+ _gnutls_record_buffer_put(session, recv->type, seq, bufel);
+
+ ret = _gnutls13_recv_async_handshake(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* bufel is now accounted */
+ return GNUTLS_E_AGAIN;
}
/* This is legal if HELLO_REQUEST is received - and we are a client.
@@ -1014,13 +1018,14 @@ record_add_to_buffers(gnutls_session_t session,
return 0;
- unexpected_packet:
+ unexpected_packet:
+
if (IS_DTLS(session) && ret != GNUTLS_E_REHANDSHAKE) {
_mbuffer_xfree(&bufel);
RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, ret);
}
- cleanup:
+ cleanup:
_mbuffer_xfree(&bufel);
return ret;
@@ -1491,7 +1496,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type,
/* Returns a value greater than zero (>= 0) if buffers should be checked
* for data. */
static ssize_t
-check_session_status(gnutls_session_t session)
+check_session_status(gnutls_session_t session, unsigned ms)
{
int ret;
@@ -1506,6 +1511,16 @@ check_session_status(gnutls_session_t session)
}
switch (session->internals.recv_state) {
+ case RECV_STATE_ASYNC_HANDSHAKE:
+ ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, -1, ms);
+ if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls13_recv_async_handshake(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return GNUTLS_E_AGAIN;
case RECV_STATE_FALSE_START_HANDLING:
return 1;
case RECV_STATE_FALSE_START:
@@ -1564,7 +1579,7 @@ _gnutls_recv_int(gnutls_session_t session, content_type_t type,
&& (data_size == 0 || data == NULL))
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- ret = check_session_status(session);
+ ret = check_session_status(session, ms);
if (ret <= 0)
return ret;
@@ -1678,7 +1693,7 @@ gnutls_record_recv_packet(gnutls_session_t session,
if (packet == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- ret = check_session_status(session);
+ ret = check_session_status(session, session->internals.record_timeout_ms);
if (ret <= 0)
return ret;
diff --git a/lib/tls13/session_ticket.c b/lib/tls13/session_ticket.c
index 77edbcda91..184c0ac271 100644
--- a/lib/tls13/session_ticket.c
+++ b/lib/tls13/session_ticket.c
@@ -227,12 +227,13 @@ generate_session_ticket(gnutls_session_t session, tls13_ticket_t *ticket)
return 0;
}
-int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned again)
+int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigned again)
{
int ret = 0;
mbuffer_st *bufel = NULL;
gnutls_buffer_st buf;
tls13_ticket_t ticket;
+ unsigned i;
/* Client does not send a NewSessionTicket */
if (unlikely(session->security_parameters.entity == GNUTLS_CLIENT))
@@ -249,70 +250,79 @@ int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned again)
return gnutls_assert_val(0);
if (again == 0) {
- memset(&ticket, 0, sizeof(tls13_ticket_t));
-
- ret = generate_session_ticket(session, &ticket);
- if (ret < 0) {
- if (ret == GNUTLS_E_INT_RET_0) {
- return gnutls_assert_val(0);
+ for (i=0;i<nr;i++) {
+ memset(&ticket, 0, sizeof(tls13_ticket_t));
+ bufel = NULL;
+
+ ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = generate_session_ticket(session, &ticket);
+ if (ret < 0) {
+ if (ret == GNUTLS_E_INT_RET_0) {
+ ret = gnutls_assert_val(0);
+ goto cleanup;
+ }
+ gnutls_assert();
+ goto cleanup;
}
- return gnutls_assert_val(ret);
- }
+ ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.lifetime);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.age_add);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.lifetime);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ /* append ticket_nonce */
+ ret = _gnutls_buffer_append_data_prefix(&buf, 8, ticket.nonce, ticket.nonce_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- ret = _gnutls_buffer_append_prefix(&buf, 32, ticket.age_add);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ /* append ticket */
+ ret = _gnutls_buffer_append_data_prefix(&buf, 16, ticket.ticket.data, ticket.ticket.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- /* append ticket_nonce */
- ret = _gnutls_buffer_append_data_prefix(&buf, 8, ticket.nonce, ticket.nonce_size);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- /* append ticket */
- ret = _gnutls_buffer_append_data_prefix(&buf, 16, ticket.ticket.data, ticket.ticket.size);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ _gnutls_free_datum(&ticket.ticket);
- ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ bufel = _gnutls_buffer_to_mbuffer(&buf);
- _gnutls_free_datum(&ticket.ticket);
+ ret = _gnutls_send_handshake2(session, bufel,
+ GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- bufel = _gnutls_buffer_to_mbuffer(&buf);
+ session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
+ }
}
- ret = _gnutls_send_handshake(session, bufel,
- GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
- if (ret > 0)
- session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT;
+ ret = _gnutls_handshake_io_write_flush(session);
return ret;
cleanup:
_gnutls_free_datum(&ticket.ticket);
_mbuffer_xfree(&bufel);
+ _gnutls_buffer_clear(&buf);
return ret;
}
diff --git a/lib/tls13/session_ticket.h b/lib/tls13/session_ticket.h
index 073c28f1f2..d2f637c209 100644
--- a/lib/tls13/session_ticket.h
+++ b/lib/tls13/session_ticket.h
@@ -23,7 +23,7 @@
#define SESSION_TICKET_H
int _gnutls13_recv_session_ticket(gnutls_session_t session, gnutls_buffer_st *buf);
-int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned again);
+int _gnutls13_send_session_ticket(gnutls_session_t session, unsigned nr, unsigned again);
int _gnutls13_unpack_session_ticket(gnutls_session_t session,
gnutls_datum_t *data,
diff --git a/tests/tls13/post-handshake-with-cert-ticket.c b/tests/tls13/post-handshake-with-cert-ticket.c
index 8ece3f1b4c..3de0d2b644 100644
--- a/tests/tls13/post-handshake-with-cert-ticket.c
+++ b/tests/tls13/post-handshake-with-cert-ticket.c
@@ -64,6 +64,7 @@ static void client_log_func(int level, const char *str)
fprintf(stderr, "client|<%d>| %s", level, str);
}
+static unsigned tickets_seen = 0;
static int ticket_callback(gnutls_session_t session, unsigned int htype,
unsigned post, unsigned int incoming, const gnutls_datum_t *msg)
{
@@ -80,6 +81,7 @@ static int ticket_callback(gnutls_session_t session, unsigned int htype,
d = gnutls_session_get_ptr(session);
if (post == GNUTLS_HOOK_POST) {
+ tickets_seen++;
if (d->data)
gnutls_free(d->data);
ret = gnutls_session_get_data2(session, d);
@@ -92,7 +94,7 @@ static int ticket_callback(gnutls_session_t session, unsigned int htype,
return 0;
}
-static void client(int fd)
+static void client(int fd, unsigned tickets)
{
int ret;
gnutls_certificate_credentials_t x509_cred;
@@ -102,6 +104,7 @@ static void client(int fd)
gnutls_datum_t session_data = {NULL, 0};
global_init();
+ tickets_seen = 0;
if (debug) {
gnutls_global_set_log_function(client_log_func);
@@ -178,6 +181,8 @@ static void client(int fd)
fail("error in recv: %s\n", gnutls_strerror(ret));
}
+ assert(tickets_seen == tickets+1);
+
gnutls_deinit(session);
if (try == 0) {
@@ -212,7 +217,7 @@ static void compare(const gnutls_datum_t *der, const void *ipem)
return;
}
-static void server(int fd)
+static void server(int fd, unsigned tickets)
{
int ret;
gnutls_session_t session;
@@ -265,10 +270,16 @@ static void server(int fd)
if (ret != 0)
fail("server: gnutls_reauth did not succeed as expected: %s\n", gnutls_strerror(ret));
- /* send a fresh ticket after re-auth */
- do {
- ret = gnutls_session_ticket_send(session, 0);
- } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+ if (tickets == 0) {
+ /* test whether the expected error code would be returned */
+ ret = gnutls_session_ticket_send(session, 0, 0);
+ assert(ret == GNUTLS_E_INVALID_REQUEST);
+ } else {
+ /* send tickets after re-auth */
+ do {
+ ret = gnutls_session_ticket_send(session, tickets, 0);
+ } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+ }
do {
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
@@ -297,11 +308,13 @@ static void server(int fd)
assert(gnutls_session_is_resumed(session) != 0);
/* check if cert is visible */
- clist = gnutls_certificate_get_peers(session, &clist_size);
- assert(clist != NULL);
- assert(clist_size > 0);
+ if (tickets > 0) {
+ clist = gnutls_certificate_get_peers(session, &clist_size);
+ assert(clist != NULL);
+ assert(clist_size > 0);
- compare(&clist[0], cli_ca3_cert.data);
+ compare(&clist[0], cli_ca3_cert.data);
+ }
gnutls_bye(session, GNUTLS_SHUT_RDWR);
gnutls_deinit(session);
@@ -324,14 +337,13 @@ static void ch_handler(int sig)
return;
}
-void doit(void)
+static void start(const char *name, unsigned tickets)
{
int fd[2];
int ret;
pid_t child;
- signal(SIGCHLD, ch_handler);
- signal(SIGPIPE, SIG_IGN);
+ success("testing: %s\n", name);
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
if (ret < 0) {
@@ -349,13 +361,24 @@ void doit(void)
if (child) {
/* parent */
close(fd[1]);
- server(fd[0]);
+ server(fd[0], tickets);
kill(child, SIGTERM);
} else {
close(fd[0]);
- client(fd[1]);
+ client(fd[1], tickets);
exit(0);
}
}
+
+void doit(void)
+{
+ signal(SIGCHLD, ch_handler);
+ signal(SIGPIPE, SIG_IGN);
+
+ start("no ticket", 0);
+ start("single ticket", 1);
+ start("8 tickets", 8);
+ start("16 tickets", 16);
+}
#endif /* _WIN32 */