summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2018-01-31 17:26:46 +0000
committerMatt Caswell <matt@openssl.org>2018-05-17 16:48:25 +0100
commit9d0a8bb71e3e411e9183e635122f17c1429c4116 (patch)
tree9d6615d9cbf0690d8c0f5c95e1ddff074f52f20f
parent029c11c21fdd018ec51badaafd34118223055274 (diff)
Enable the ability to set the number of TLSv1.3 session tickets sent
We send a session ticket automatically in TLSv1.3 at the end of the handshake. This commit provides the ability to set how many tickets should be sent. By default this is one. Fixes #4978 Reviewed-by: Viktor Dukhovni <viktor@openssl.org> Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5227)
-rw-r--r--include/openssl/ssl.h5
-rw-r--r--ssl/ssl_lib.c28
-rw-r--r--ssl/ssl_locl.h9
-rw-r--r--ssl/statem/statem_srvr.c65
-rw-r--r--util/libssl.num4
5 files changed, 93 insertions, 18 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1f4f2616b6..db0a2d5d82 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2095,6 +2095,11 @@ void SSL_set_record_padding_callback_arg(SSL *ssl, void *arg);
void *SSL_get_record_padding_callback_arg(SSL *ssl);
int SSL_set_block_padding(SSL *ssl, size_t block_size);
+int SSL_set_num_tickets(SSL *s, size_t 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);
+
# if OPENSSL_API_COMPAT < 0x10100000L
# define SSL_cache_hit(s) SSL_session_reused(s)
# endif
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 41574c4bf2..2c29d7f61c 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -699,6 +699,7 @@ SSL *SSL_new(SSL_CTX *ctx)
s->mode = ctx->mode;
s->max_cert_list = ctx->max_cert_list;
s->max_early_data = ctx->max_early_data;
+ s->num_tickets = ctx->num_tickets;
/* Shallow copy of the ciphersuites stack */
s->tls13_ciphersuites = sk_SSL_CIPHER_dup(ctx->tls13_ciphersuites);
@@ -3033,6 +3034,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
*/
ret->max_early_data = 0;
+ /* By default we send one session ticket automatically in TLSv1.3 */
+ ret->num_tickets = 1;
+
ssl_ctx_system_config(ret);
return ret;
@@ -4314,6 +4318,30 @@ int SSL_set_block_padding(SSL *ssl, size_t block_size)
return 1;
}
+int SSL_set_num_tickets(SSL *s, size_t num_tickets)
+{
+ s->num_tickets = num_tickets;
+
+ return 1;
+}
+
+size_t SSL_get_num_tickets(SSL *s)
+{
+ return s->num_tickets;
+}
+
+int SSL_CTX_set_num_tickets(SSL_CTX *ctx, size_t num_tickets)
+{
+ ctx->num_tickets = num_tickets;
+
+ return 1;
+}
+
+size_t SSL_CTX_get_num_tickets(SSL_CTX *ctx)
+{
+ return ctx->num_tickets;
+}
+
/*
* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
* variable, freeing EVP_MD_CTX previously stored in that variable, if any.
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index e02f5a1839..4aec810179 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1049,6 +1049,9 @@ struct ssl_ctx_st {
SSL_CTX_generate_session_ticket_fn generate_ticket_cb;
SSL_CTX_decrypt_session_ticket_fn decrypt_ticket_cb;
void *ticket_cb_data;
+
+ /* The number of TLS1.3 tickets to automatically send */
+ size_t num_tickets;
};
struct ssl_st {
@@ -1418,6 +1421,12 @@ struct ssl_st {
size_t block_padding;
CRYPTO_RWLOCK *lock;
+ RAND_DRBG *drbg;
+
+ /* The number of TLS1.3 tickets to automatically send */
+ size_t num_tickets;
+ /* The number of TLS1.3 tickets actually sent so far */
+ size_t sent_tickets;
};
/*
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 22786bed13..dfeba173a7 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -480,13 +480,9 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
case TLS_ST_SR_FINISHED:
/*
* Technically we have finished the handshake at this point, but we're
- * going to remain "in_init" for now and write out the session ticket
+ * going to remain "in_init" for now and write out any session tickets
* immediately.
- * TODO(TLS1.3): Perhaps we need to be able to control this behaviour
- * and give the application the opportunity to delay sending the
- * session ticket?
*/
- st->hand_state = TLS_ST_SW_SESSION_TICKET;
if (s->post_handshake_auth == SSL_PHA_REQUESTED) {
s->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
} else if (!s->ext.ticket_expected) {
@@ -495,7 +491,12 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
* handshake at this point.
*/
st->hand_state = TLS_ST_OK;
+ return WRITE_TRAN_CONTINUE;
}
+ if (s->num_tickets > s->sent_tickets)
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ else
+ st->hand_state = TLS_ST_OK;
return WRITE_TRAN_CONTINUE;
case TLS_ST_SR_KEY_UPDATE:
@@ -507,7 +508,14 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
case TLS_ST_SW_KEY_UPDATE:
case TLS_ST_SW_SESSION_TICKET:
- st->hand_state = TLS_ST_OK;
+ /* In a resumption we only ever send a maximum of one new ticket.
+ * Following an initial handshake we send the number of tickets we have
+ * been configured for.
+ */
+ if (s->hit || s->num_tickets <= s->sent_tickets) {
+ /* We've written enough tickets out. */
+ st->hand_state = TLS_ST_OK;
+ }
return WRITE_TRAN_CONTINUE;
}
}
@@ -3743,21 +3751,41 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
} age_add_u;
if (SSL_IS_TLS13(s)) {
- if (s->post_handshake_auth != SSL_PHA_EXT_RECEIVED) {
- void (*cb) (const SSL *ssl, int type, int val) = NULL;
+ void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+ if (s->info_callback != NULL)
+ cb = s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb = s->ctx->info_callback;
+
+ if (cb != NULL) {
/*
- * This is the first session ticket we've sent. In the state
- * machine we "cheated" and tacked this onto the end of the first
- * handshake. From an info callback perspective this should appear
- * like the start of a new handshake.
+ * We don't start and stop the handshake in between each ticket when
+ * sending more than one - but it should appear that way to the info
+ * callback.
*/
- if (s->info_callback != NULL)
- cb = s->info_callback;
- else if (s->ctx->info_callback != NULL)
- cb = s->ctx->info_callback;
- if (cb != NULL)
- cb(s, SSL_CB_HANDSHAKE_START, 1);
+ if (s->sent_tickets != 0) {
+ ossl_statem_set_in_init(s, 0);
+ cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+ ossl_statem_set_in_init(s, 1);
+ }
+ cb(s, SSL_CB_HANDSHAKE_START, 1);
+ }
+ /*
+ * If we already sent one NewSessionTicket then we need to take a copy
+ * of it and create a new session from it.
+ */
+ if (s->sent_tickets != 0) {
+ SSL_SESSION *new_sess = ssl_session_dup(s->session, 0);
+
+ if (new_sess == NULL) {
+ /* SSLfatal already called */
+ goto err;
+ }
+
+ SSL_SESSION_free(s->session);
+ s->session = new_sess;
}
if (!ssl_generate_session_id(s, s->session)) {
@@ -3968,6 +3996,7 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
/* SSLfatal() already called */
goto err;
}
+ s->sent_tickets++;
}
EVP_CIPHER_CTX_free(ctx);
HMAC_CTX_free(hctx);
diff --git a/util/libssl.num b/util/libssl.num
index 344d684a94..3495903e87 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -486,3 +486,7 @@ SSL_CTX_set_stateless_cookie_generate_cb 486 1_1_1 EXIST::FUNCTION:
SSL_CTX_set_stateless_cookie_verify_cb 487 1_1_1 EXIST::FUNCTION:
SSL_CTX_set_ciphersuites 488 1_1_1 EXIST::FUNCTION:
SSL_set_ciphersuites 489 1_1_1 EXIST::FUNCTION:
+SSL_set_num_tickets 490 1_1_1 EXIST::FUNCTION:
+SSL_CTX_get_num_tickets 491 1_1_1 EXIST::FUNCTION:
+SSL_get_num_tickets 492 1_1_1 EXIST::FUNCTION:
+SSL_CTX_set_num_tickets 493 1_1_1 EXIST::FUNCTION: