Skip to content

Commit

Permalink
Add SSL_new_session_ticket() API
Browse files Browse the repository at this point in the history
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 <[email protected]>
(Merged from openssl#11416)
  • Loading branch information
kaduk committed May 1, 2020
1 parent 6250282 commit 3bfacb5
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 10 deletions.
27 changes: 23 additions & 4 deletions doc/man3/SSL_CTX_set_num_tickets.pod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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.
Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 5 additions & 3 deletions ssl/record/rec_layer_s3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/*
Expand Down
9 changes: 9 additions & 0 deletions ssl/ssl_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions ssl/ssl_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
16 changes: 13 additions & 3 deletions ssl/statem/statem_srvr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4161,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);
}

Expand Down

0 comments on commit 3bfacb5

Please sign in to comment.