diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-07-12 12:57:21 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-07-12 12:57:21 +0000 |
commit | 3c87793a2ce720bde6cf38c43806ea4ecf2105e2 (patch) | |
tree | 70faf951e14ba13755755c2ae7c0f51650fd1997 | |
parent | 40b5e30494230f1e87d1622f14cf65cce5ba3bc9 (diff) | |
parent | df738136a71b545c61e639edee7bad4f68271bcc (diff) | |
download | gnutls-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.c | 3 | ||||
-rw-r--r-- | lib/gnutls_int.h | 3 | ||||
-rw-r--r-- | lib/handshake-tls13.c | 182 | ||||
-rw-r--r-- | lib/handshake.c | 14 | ||||
-rw-r--r-- | lib/handshake.h | 7 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 2 | ||||
-rw-r--r-- | lib/record.c | 47 | ||||
-rw-r--r-- | lib/tls13/session_ticket.c | 104 | ||||
-rw-r--r-- | lib/tls13/session_ticket.h | 2 | ||||
-rw-r--r-- | tests/tls13/post-handshake-with-cert-ticket.c | 53 |
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 */ |