From 01e182d7537a5f18adf8af22d5f9b746dad780e9 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 16 Mar 2020 11:25:58 -0700 Subject: [PATCH 1/5] QUIC: Add SSL_new_session_ticket() API This API requests that the TLS stack generate a (TLS 1.3) NewSessionTicket message the next time it is safe to do so (i.e., we do not have other data pending write, which could be mid-record). For efficiency, defer actually generating/writing the ticket until there is other data to write, to avoid producing server-to-client traffic when not needed. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/11416) (cherry picked from commit 3bfacb5fd4679812a7b9ec61d296b1add64669c0) --- doc/man3/SSL_CTX_set_num_tickets.pod | 27 +++++++++++++++++++++++---- include/openssl/ssl.h | 1 + ssl/record/rec_layer_s3.c | 8 +++++--- ssl/ssl_lib.c | 9 +++++++++ ssl/ssl_local.h | 2 ++ ssl/statem/statem_srvr.c | 16 +++++++++++++--- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/doc/man3/SSL_CTX_set_num_tickets.pod b/doc/man3/SSL_CTX_set_num_tickets.pod index ad13ed15f4065..bc72776755f7d 100644 --- a/doc/man3/SSL_CTX_set_num_tickets.pod +++ b/doc/man3/SSL_CTX_set_num_tickets.pod @@ -5,7 +5,8 @@ SSL_set_num_tickets, SSL_get_num_tickets, SSL_CTX_set_num_tickets, -SSL_CTX_get_num_tickets +SSL_CTX_get_num_tickets, +SSL_new_session_ticket - control the number of TLSv1.3 session tickets that are issued =head1 SYNOPSIS @@ -16,6 +17,7 @@ SSL_CTX_get_num_tickets size_t SSL_get_num_tickets(SSL *s); int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets); size_t SSL_CTX_get_num_tickets(SSL_CTX *ctx); + int SSL_new_session_ticket(SSL *s); =head1 DESCRIPTION @@ -40,21 +42,38 @@ handshake then SSL_set_num_tickets() can be called again prior to calling SSL_verify_client_post_handshake() to update the number of tickets that will be sent. +To issue tickets after other events (such as application-layer changes), +SSL_new_session_ticket() is used by a server application to request that a new +ticket be sent when it is safe to do so. New tickets are only allowed to be +sent in this manner after the initial handshake has completed, and only for TLS +1.3 connections. The ticket generation and transmission are delayed until the +server is starting a new write operation, so that it is bundled with other +application data being written and properly aligned to a record boundary. +SSL_new_session_ticket() can be called more than once to request additional +tickets be sent; all such requests are queued and written together when it is +safe to do so. Note that a successful return from SSL_new_session_ticket() +indicates only that the request to send a ticket was processed, not that the +ticket itself was sent. To be notified when the ticket itself is sent, a +new-session callback can be registered with L that +will be invoked as the ticket or tickets are generated. + SSL_CTX_get_num_tickets() and SSL_get_num_tickets() return the number of tickets set by a previous call to SSL_CTX_set_num_tickets() or SSL_set_num_tickets(), or 2 if no such call has been made. =head1 RETURN VALUES -SSL_CTX_set_num_tickets() and SSL_set_num_tickets() return 1 on success or 0 on -failure. +SSL_CTX_set_num_tickets(), SSL_set_num_tickets(), and +SSL_new_session_ticket() return 1 on success or 0 on failure. SSL_CTX_get_num_tickets() and SSL_get_num_tickets() return the number of tickets that have been previously set. =head1 HISTORY -These functions were added in OpenSSL 1.1.1. +SSL_new_session_ticket() was added in OpenSSL 3.0.0. +SSL_set_num_tickets(), SSL_get_num_tickets(), SSL_CTX_set_num_tickets(), and +SSL_CTX_get_num_tickets() were added in OpenSSL 1.1.1. =head1 COPYRIGHT diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index c6f8e4d180106..17bd0bc2c9c9c 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1921,6 +1921,7 @@ int SSL_get_key_update_type(const SSL *s); int SSL_renegotiate(SSL *s); int SSL_renegotiate_abbreviated(SSL *s); __owur int SSL_renegotiate_pending(const SSL *s); +int SSL_new_session_ticket(SSL *s); int SSL_shutdown(SSL *s); __owur int SSL_verify_client_post_handshake(SSL *s); void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val); diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index b2a7a47eb0752..24ec0bdf4b1ce 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -374,10 +374,12 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len, s->rlayer.wnum = 0; /* - * If we are supposed to be sending a KeyUpdate then go into init unless we - * have writes pending - in which case we should finish doing that first. + * If we are supposed to be sending a KeyUpdate or NewSessionTicket then go + * into init unless we have writes pending - in which case we should finish + * doing that first. */ - if (wb->left == 0 && s->key_update != SSL_KEY_UPDATE_NONE) + if (wb->left == 0 && (s->key_update != SSL_KEY_UPDATE_NONE + || s->ext.extra_tickets_expected > 0)) ossl_statem_set_in_init(s, 1); /* diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index ab0bf907b2b20..69f59d39738d1 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2210,6 +2210,15 @@ int SSL_renegotiate_pending(const SSL *s) return (s->renegotiate != 0); } +int SSL_new_session_ticket(SSL *s) +{ + if (SSL_in_init(s) || SSL_IS_FIRST_HANDSHAKE(s) || !s->server + || !SSL_IS_TLS13(s)) + return 0; + s->ext.extra_tickets_expected++; + return 1; +} + long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) { long l; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 63b39378f3f5b..62e365686a5a1 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1320,6 +1320,8 @@ struct ssl_st { /* RFC4507 session ticket expected to be received or sent */ int ticket_expected; + /* TLS 1.3 tickets requested by the application. */ + int extra_tickets_expected; # ifndef OPENSSL_NO_EC size_t ecpointformats_len; /* our list */ diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 7f5f0db0c73a2..0283dbc7ee9ff 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -437,6 +437,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) st->hand_state = TLS_ST_SW_CERT_REQ; return WRITE_TRAN_CONTINUE; } + if (s->ext.extra_tickets_expected > 0) { + st->hand_state = TLS_ST_SW_SESSION_TICKET; + return WRITE_TRAN_CONTINUE; + } /* Try to read from the client instead */ return WRITE_TRAN_FINISHED; @@ -527,7 +531,9 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) * Following an initial handshake we send the number of tickets we have * been configured for. */ - if (s->hit || s->num_tickets <= s->sent_tickets) { + if (!SSL_IS_FIRST_HANDSHAKE(s) && s->ext.extra_tickets_expected > 0) { + return WRITE_TRAN_CONTINUE; + } else if (s->hit || s->num_tickets <= s->sent_tickets) { /* We've written enough tickets out. */ st->hand_state = TLS_ST_OK; } @@ -723,7 +729,8 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst) return WORK_FINISHED_CONTINUE; case TLS_ST_SW_SESSION_TICKET: - if (SSL_IS_TLS13(s) && s->sent_tickets == 0) { + if (SSL_IS_TLS13(s) && s->sent_tickets == 0 + && s->ext.extra_tickets_expected == 0) { /* * Actually this is the end of the handshake, but we're going * straight into writing the session ticket out. So we finish off @@ -4182,10 +4189,13 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) /* * Increment both |sent_tickets| and |next_ticket_nonce|. |sent_tickets| * gets reset to 0 if we send more tickets following a post-handshake - * auth, but |next_ticket_nonce| does not. + * auth, but |next_ticket_nonce| does not. If we're sending extra + * tickets, decrement the count of pending extra tickets. */ s->sent_tickets++; s->next_ticket_nonce++; + if (s->ext.extra_tickets_expected > 0) + s->ext.extra_tickets_expected--; ssl_update_cache(s, SSL_SESS_CACHE_SERVER); } From 3bcddea7fb1aa7bde49d6ab4d25bd7dbdcd24fee Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Tue, 17 Mar 2020 10:08:11 -0700 Subject: [PATCH 2/5] QUIC: Add test for SSL_new_session_ticket() Run a normal handshake and then request some extra tickets, checking that the new_session_cb is called the expected number of times. Since the tickets are generated in the same way as other tickets, there should not be a need to verify that these specific ones can be used to resume. Run the test with both zero and a non-zero number of tickets issued in the initial handshake. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/11416) (cherry picked from commit f0049b86cc5d745af97c087e54abaeb00de40b6b) --- test/sslapitest.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/test/sslapitest.c b/test/sslapitest.c index f00d5cb074dec..ab02b4e434507 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1626,6 +1626,148 @@ static int test_psk_tickets(void) return testresult; } + +static int test_extra_tickets(int idx) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + BIO *bretry = BIO_new(bio_s_always_retry()); + BIO *tmp = NULL; + int testresult = 0; + int stateful = 0; + size_t nbytes; + unsigned char c, buf[1]; + + new_called = 0; + do_cache = 1; + + if (idx >= 3) { + idx -= 3; + stateful = 1; + } + + if (!TEST_ptr(bretry) || !setup_ticket_test(stateful, idx, &sctx, &cctx)) + goto end; + SSL_CTX_sess_set_new_cb(sctx, new_session_cb); + /* setup_ticket_test() uses new_cachesession_cb which we don't need. */ + SSL_CTX_sess_set_new_cb(cctx, new_session_cb); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, + &clientssl, NULL, NULL))) + goto end; + + /* + * Note that we have new_session_cb on both sctx and cctx, so new_called is + * incremented by both client and server. + */ + if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE)) + /* Check we got the number of tickets we were expecting */ + || !TEST_int_eq(idx * 2, new_called) + || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_int_eq(idx * 2, new_called)) + goto end; + + /* Now try a (real) write to actually send the tickets */ + c = '1'; + if (!TEST_true(SSL_write_ex(serverssl, &c, 1, &nbytes)) + || !TEST_size_t_eq(1, nbytes) + || !TEST_int_eq(idx * 2 + 2, new_called) + || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(idx * 2 + 4, new_called) + || !TEST_int_eq(sizeof(buf), nbytes) + || !TEST_int_eq(c, buf[0]) + || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes))) + goto end; + + /* Try with only requesting one new ticket, too */ + c = '2'; + new_called = 0; + if (!TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_write_ex(serverssl, &c, sizeof(c), &nbytes)) + || !TEST_size_t_eq(sizeof(c), nbytes) + || !TEST_int_eq(1, new_called) + || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(2, new_called) + || !TEST_size_t_eq(sizeof(buf), nbytes) + || !TEST_int_eq(c, buf[0])) + goto end; + + /* Do it again but use dummy writes to drive the ticket generation */ + c = '3'; + new_called = 0; + if (!TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_write_ex(serverssl, &c, 0, &nbytes)) + || !TEST_size_t_eq(0, nbytes) + || !TEST_int_eq(2, new_called) + || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(4, new_called)) + goto end; + + /* + * Use the always-retry BIO to exercise the logic that forces ticket + * generation to wait until a record boundary. + */ + c = '4'; + new_called = 0; + tmp = SSL_get_wbio(serverssl); + if (!TEST_ptr(tmp) || !TEST_true(BIO_up_ref(tmp))) { + tmp = NULL; + goto end; + } + SSL_set0_wbio(serverssl, bretry); + bretry = NULL; + if (!TEST_false(SSL_write_ex(serverssl, &c, 1, &nbytes)) + || !TEST_int_eq(SSL_get_error(serverssl, 0), SSL_ERROR_WANT_WRITE) + || !TEST_size_t_eq(nbytes, 0)) + goto end; + /* Restore a BIO that will let the write succeed */ + SSL_set0_wbio(serverssl, tmp); + tmp = NULL; + /* These calls should just queue the request and not send anything. */ + if (!TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_int_eq(0, new_called)) + goto end; + /* Re-do the write; still no tickets sent */ + if (!TEST_true(SSL_write_ex(serverssl, &c, 1, &nbytes)) + || !TEST_size_t_eq(1, nbytes) + || !TEST_int_eq(0, new_called) + || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(0, new_called) + || !TEST_int_eq(sizeof(buf), nbytes) + || !TEST_int_eq(c, buf[0]) + || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes))) + goto end; + /* Now the *next* write should send the tickets */ + c = '5'; + if (!TEST_true(SSL_write_ex(serverssl, &c, 1, &nbytes)) + || !TEST_size_t_eq(1, nbytes) + || !TEST_int_eq(2, new_called) + || !TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(4, new_called) + || !TEST_int_eq(sizeof(buf), nbytes) + || !TEST_int_eq(c, buf[0]) + || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes))) + goto end; + + SSL_shutdown(clientssl); + SSL_shutdown(serverssl); + testresult = 1; + + end: + BIO_free(bretry); + BIO_free(tmp); + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + clientssl = serverssl = NULL; + sctx = cctx = NULL; + return testresult; +} #endif #define USE_NULL 0 @@ -7115,6 +7257,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_stateful_tickets, 3); ADD_ALL_TESTS(test_stateless_tickets, 3); ADD_TEST(test_psk_tickets); + ADD_ALL_TESTS(test_extra_tickets, 6); #endif ADD_ALL_TESTS(test_ssl_set_bio, TOTAL_SSL_SET_BIO_TESTS); ADD_TEST(test_ssl_bio_pop_next_bio); From 61073752bd1a6c1277c7424cc84514d9db65d409 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Fri, 9 Apr 2021 14:33:01 -0700 Subject: [PATCH 3/5] QUIC: make update for SSL_new_session_ticket() --- util/libssl.num | 1 + 1 file changed, 1 insertion(+) diff --git a/util/libssl.num b/util/libssl.num index 7c8f9463abff0..e4df4b580fabe 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -514,3 +514,4 @@ SSL_set_quic_transport_version 20012 1_1_1i EXIST::FUNCTION:QUIC SSL_get_peer_quic_transport_version 20013 1_1_1i EXIST::FUNCTION:QUIC SSL_get_quic_transport_version 20014 1_1_1i EXIST::FUNCTION:QUIC SSL_set_quic_early_data_enabled 20015 1_1_1j EXIST::FUNCTION:QUIC +SSL_new_session_ticket 20016 1_1_1k EXIST::FUNCTION: From 1809acdb463211c90bbb1e2accbe94bdb9b52186 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Mon, 4 May 2020 11:50:25 -0700 Subject: [PATCH 4/5] QUIC: Fix up whitespace nits introduced by PR #11416 Expand a couple literal tabs, and de-indent the body of a function. Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/11728) (cherry picked from commit 35774d5594af9beeb73792742b7ed901d202be70) --- ssl/ssl_lib.c | 10 +++++----- ssl/ssl_local.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 69f59d39738d1..b25e7a7bcbee9 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2212,11 +2212,11 @@ int SSL_renegotiate_pending(const SSL *s) int SSL_new_session_ticket(SSL *s) { - if (SSL_in_init(s) || SSL_IS_FIRST_HANDSHAKE(s) || !s->server - || !SSL_IS_TLS13(s)) - return 0; - s->ext.extra_tickets_expected++; - return 1; + if (SSL_in_init(s) || SSL_IS_FIRST_HANDSHAKE(s) || !s->server + || !SSL_IS_TLS13(s)) + return 0; + s->ext.extra_tickets_expected++; + return 1; } long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 62e365686a5a1..6dfe6e5546ee7 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -1320,8 +1320,8 @@ struct ssl_st { /* RFC4507 session ticket expected to be received or sent */ int ticket_expected; - /* TLS 1.3 tickets requested by the application. */ - int extra_tickets_expected; + /* TLS 1.3 tickets requested by the application. */ + int extra_tickets_expected; # ifndef OPENSSL_NO_EC size_t ecpointformats_len; /* our list */ From 457aadc7730fabdf24f7450b7197fd046d0edbb9 Mon Sep 17 00:00:00 2001 From: kaduk Date: Fri, 9 Apr 2021 14:16:29 -0700 Subject: [PATCH 5/5] QUIC: SSL_new_session_ticket() support (#26) * Let SSL_new_session_ticket() work immediately The initial implementation always deferred the generation of the requested ticket(s) until the next application write, but this means that the ticket cannot be written at all until there is application data ready to write. In some scenarios this application data may never arrive or may take a long time to arrive, so (when already at a record boundary) allow the application to explicitly call SSL_do_handshake() after SSL_new_session_ticket() to force an immediate write, even when there is no application data available. The default behavior remains to defer the generation of the ticket and coalesce the network traffic for the ticket and application data. * Test new SSL_new_session_ticket() functionality Now that we can become "in init" directly after the call, test the various scenarios where explicit SSL_do_handshake() calls can come into play. * Update SSL_new_session_ticket() manual for triggered send Document the recently added functionality. (cherry picked from commit 4fb1ff7ee88caed42acdd944347a4ff272b351a3) --- doc/man3/SSL_CTX_set_num_tickets.pod | 27 ++++++++++++++++----------- ssl/ssl_lib.c | 6 +++++- test/sslapitest.c | 26 +++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/doc/man3/SSL_CTX_set_num_tickets.pod b/doc/man3/SSL_CTX_set_num_tickets.pod index bc72776755f7d..67d9b7b2cab44 100644 --- a/doc/man3/SSL_CTX_set_num_tickets.pod +++ b/doc/man3/SSL_CTX_set_num_tickets.pod @@ -45,17 +45,22 @@ sent. To issue tickets after other events (such as application-layer changes), SSL_new_session_ticket() is used by a server application to request that a new ticket be sent when it is safe to do so. New tickets are only allowed to be -sent in this manner after the initial handshake has completed, and only for TLS -1.3 connections. The ticket generation and transmission are delayed until the -server is starting a new write operation, so that it is bundled with other -application data being written and properly aligned to a record boundary. -SSL_new_session_ticket() can be called more than once to request additional -tickets be sent; all such requests are queued and written together when it is -safe to do so. Note that a successful return from SSL_new_session_ticket() -indicates only that the request to send a ticket was processed, not that the -ticket itself was sent. To be notified when the ticket itself is sent, a -new-session callback can be registered with L that -will be invoked as the ticket or tickets are generated. +sent in this manner after the initial handshake has completed, and only for +TLS 1.3 connections. By default, the ticket generation and transmission are +delayed until the server is starting a new write operation, so that it is +bundled with other application data being written and properly aligned to a +record boundary. If the connection was at a record boundary when +SSL_new_session_ticket() was called, the ticket can be sent immediately +(without waiting for the next application write) by calling +SSL_do_handshake(). SSL_new_session_ticket() can be called more than once to +request additional tickets be sent; all such requests are queued and written +together when it is safe to do so and triggered by SSL_write() or +SSL_do_handshake(). Note that a successful return from +SSL_new_session_ticket() indicates only that the request to send a ticket was +processed, not that the ticket itself was sent. To be notified when the +ticket itself is sent, a new-session callback can be registered with +L that will be invoked as the ticket or tickets +are generated. SSL_CTX_get_num_tickets() and SSL_get_num_tickets() return the number of tickets set by a previous call to SSL_CTX_set_num_tickets() or diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index b25e7a7bcbee9..84ecda6bb7428 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2212,10 +2212,14 @@ int SSL_renegotiate_pending(const SSL *s) int SSL_new_session_ticket(SSL *s) { - if (SSL_in_init(s) || SSL_IS_FIRST_HANDSHAKE(s) || !s->server + /* If we are in init because we're sending tickets, okay to send more. */ + if ((SSL_in_init(s) && s->ext.extra_tickets_expected == 0) + || SSL_IS_FIRST_HANDSHAKE(s) || !s->server || !SSL_IS_TLS13(s)) return 0; s->ext.extra_tickets_expected++; + if (s->rlayer.wbuf[0].left == 0 && !SSL_in_init(s)) + ossl_statem_set_in_init(s, 1); return 1; } diff --git a/test/sslapitest.c b/test/sslapitest.c index ab02b4e434507..28217bd99a9f2 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1706,11 +1706,22 @@ static int test_extra_tickets(int idx) || !TEST_int_eq(4, new_called)) goto end; + /* Once more, but with SSL_do_handshake() to drive the ticket generation */ + c = '4'; + new_called = 0; + if (!TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_true(SSL_do_handshake(serverssl)) + || !TEST_int_eq(2, new_called) + || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes)) + || !TEST_int_eq(4, new_called)) + goto end; + /* * Use the always-retry BIO to exercise the logic that forces ticket * generation to wait until a record boundary. */ - c = '4'; + c = '5'; new_called = 0; tmp = SSL_get_wbio(serverssl); if (!TEST_ptr(tmp) || !TEST_true(BIO_up_ref(tmp))) { @@ -1726,9 +1737,14 @@ static int test_extra_tickets(int idx) /* Restore a BIO that will let the write succeed */ SSL_set0_wbio(serverssl, tmp); tmp = NULL; - /* These calls should just queue the request and not send anything. */ + /* + * These calls should just queue the request and not send anything + * even if we explicitly try to hit the state machine. + */ if (!TEST_true(SSL_new_session_ticket(serverssl)) || !TEST_true(SSL_new_session_ticket(serverssl)) + || !TEST_int_eq(0, new_called) + || !TEST_true(SSL_do_handshake(serverssl)) || !TEST_int_eq(0, new_called)) goto end; /* Re-do the write; still no tickets sent */ @@ -1741,8 +1757,12 @@ static int test_extra_tickets(int idx) || !TEST_int_eq(c, buf[0]) || !TEST_false(SSL_read_ex(clientssl, buf, sizeof(buf), &nbytes))) goto end; + /* Even trying to hit the state machine now will still not send tickets */ + if (!TEST_true(SSL_do_handshake(serverssl)) + || !TEST_int_eq(0, new_called)) + goto end; /* Now the *next* write should send the tickets */ - c = '5'; + c = '6'; if (!TEST_true(SSL_write_ex(serverssl, &c, 1, &nbytes)) || !TEST_size_t_eq(1, nbytes) || !TEST_int_eq(2, new_called)