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);
*/
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;
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.
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) {
* 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:
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;
}
}
} 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)) {
/* SSLfatal() already called */
goto err;
}
+ s->sent_tickets++;
}
EVP_CIPHER_CTX_free(ctx);
HMAC_CTX_free(hctx);