[openssl] master update
kaduk at mit.edu
kaduk at mit.edu
Fri May 1 22:38:21 UTC 2020
The branch master has been updated
via e908f292de6383c5d4dbece9381b523d4ce41c69 (commit)
via f0049b86cc5d745af97c087e54abaeb00de40b6b (commit)
via 3bfacb5fd4679812a7b9ec61d296b1add64669c0 (commit)
via 6250282f7fc37c5903d051174a69053a80e1b1bd (commit)
from 90113096186e185cd07ee1c4c7267d0e68e67793 (commit)
- Log -----------------------------------------------------------------
commit e908f292de6383c5d4dbece9381b523d4ce41c69
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date: Wed Apr 1 17:08:10 2020 -0700
make update for SSL_new_session_ticket
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11416)
commit f0049b86cc5d745af97c087e54abaeb00de40b6b
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date: Tue Mar 17 10:08:11 2020 -0700
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 <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11416)
commit 3bfacb5fd4679812a7b9ec61d296b1add64669c0
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date: Mon Mar 16 11:25:58 2020 -0700
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 <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11416)
commit 6250282f7fc37c5903d051174a69053a80e1b1bd
Author: Benjamin Kaduk <bkaduk at akamai.com>
Date: Mon Mar 16 11:25:12 2020 -0700
Fix whitespace nit in ossl_statem_server_pre_work
An 'if' clause was nestled against a previous closing brace as it if was
an 'else if', but should properly stand on its own line.
Reviewed-by: Matt Caswell <matt at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11416)
-----------------------------------------------------------------------
Summary of changes:
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 | 19 ++++-
test/sslapitest.c | 143 +++++++++++++++++++++++++++++++++++
util/libssl.num | 1 +
8 files changed, 199 insertions(+), 11 deletions(-)
diff --git a/doc/man3/SSL_CTX_set_num_tickets.pod b/doc/man3/SSL_CTX_set_num_tickets.pod
index 84afe4ae6a..5d4bd6f5be 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,14 +42,29 @@ 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<SSL_CTX_sess_set_new_cb(3)> 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.
@@ -58,7 +75,9 @@ L<ssl(7)>
=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 5c2affb690..f293b035e3 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1959,6 +1959,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 d4198917d0..bceac72051 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -384,10 +384,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 63cbb3d904..fde726e0ba 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2303,6 +2303,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 21bf482bef..de7e9fde48 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -1539,6 +1539,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 c463f22ce2..d1d86ea5e6 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -441,6 +441,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;
@@ -531,7 +535,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;
}
@@ -727,7 +733,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
@@ -736,7 +743,8 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
* Calls SSLfatal as required.
*/
return tls_finish_handshake(s, wst, 0, 0);
- } if (SSL_IS_DTLS(s)) {
+ }
+ if (SSL_IS_DTLS(s)) {
/*
* We're into the last flight. We don't retransmit the last flight
* unless we need to, so we don't use the timer
@@ -4160,10 +4168,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);
}
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 779176a0f1..b8bad61fd2 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -2093,6 +2093,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
@@ -7395,6 +7537,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);
diff --git a/util/libssl.num b/util/libssl.num
index c2b162f3bd..b8e0982daa 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -513,3 +513,4 @@ SSL_CTX_load_verify_dir ? 3_0_0 EXIST::FUNCTION:
SSL_CTX_load_verify_store ? 3_0_0 EXIST::FUNCTION:
SSL_CTX_set_tlsext_ticket_key_evp_cb ? 3_0_0 EXIST::FUNCTION:
SSL_CTX_new_with_libctx ? 3_0_0 EXIST::FUNCTION:
+SSL_new_session_ticket ? 3_0_0 EXIST::FUNCTION:
More information about the openssl-commits
mailing list