[PATCH 01 of 11] SSL: disabled saving tickets to session cache

Sergey Kandaurov pluknet at nginx.com
Mon Sep 26 10:11:17 UTC 2022

> On 17 Sep 2022, at 00:58, Maxim Dounin <mdounin at mdounin.ru> wrote:
> Hello!
> On Thu, Sep 15, 2022 at 09:36:31AM +0400, Sergey Kandaurov wrote:
>>> On 26 Aug 2022, at 07:01, Maxim Dounin <mdounin at mdounin.ru> wrote:
>>> # HG changeset patch
>>> # User Maxim Dounin <mdounin at mdounin.ru>
>>> # Date 1661481945 -10800
>>> #      Fri Aug 26 05:45:45 2022 +0300
>>> # Node ID 2cd8fbeb4edc5a99b725585edc02a16a8a0c503e
>>> # Parent  069a4813e8d6d7ec662d282a10f5f7062ebd817f
>>> SSL: disabled saving tickets to session cache.
>>> OpenSSL for TLSv1.3 tries to save tickets into session cache "because some
>>> applications just want to know about the creation of a session".  To avoid
>>> trashing session cache with useless data, we do not save such sessions now.
>> For the record, BoringSSL doesn't seem to call new_session_cb for TLSv1.3
>> at all, so there is no way to resume sessions with SSL_OP_NO_TICKET set.
>> In contrary, OpenSSL emits stateful tickets in this case, which contain
>> dummy session id used then as a session cache lookup key on server
>> (much like session ids in TLSv1.2)
>> OTOH, without SSL_OP_NO_TICKET set, OpenSSL emits self-containing tickets
>> with enough info to resume session, so nothing to lookup in session cache.
>> The latter makes impractical storing something in session cache, except
>> to use the callback for things like tracking "the creation of a session".
>> Namely, OpenSSL puts session (i.e. something that SSL_get_session returns)
>> and supplementary info to session ticket message as the ticket value.
> It looks like you are trying to introduce "stateful tickets" and 
> "self-containing tickets" terms, which is somewhat confusing 
> unless carefully explained.  OpenSSL itself tries to use terms 
> "stateful tickets" and "stateless tickets", with the similar 
> drawbacks.

Indeed, OpenSSL SSL_OP_NO_TICKET documentation is what I refer to.
While OpenSSL terms may look odd, they are useful to describe the
difference (and tricks) in TLSv1.3 session resumption with and
without SSL_OP_NO_TICKET, as implemented to OpenSSL specifically.

> A better explanation would be to follow generic term "session 
> ticket", as originally introduced in RFC 4507 for TLS session 
> resumption without server-side state.
> In these terms (as always used before introduction of TLSv1.3 and 
> currently used in many places, including nginx own documentation 
> and the source code) there are two basic mechanisms to resume 
> sessions: server-side session cache and session tickets (used to 
> resume sessions without server-side state).
> Without SSL_OP_NO_TICKET set, OpenSSL uses tickets as long as 
> supported by the client.
> With SSL_OP_NO_TICKET set, OpenSSL does not use tickets, and uses 
> server-side session cache instead (if configured).
> The only difference between TLSv1.3 and previous protocols is how 
> session ids are sent to the client if server-side session cache is 
> used.  In case of SSL and TLS up to and including TLSv1.2, session 
> ids are sent in the dedicated fields of the ServerHello and 
> ClientHello handshake messages.  In case of TLSv1.3, dedicated 
> fields were removed, so session ids are sent in the 
> NewSessionTicket messages ("a database lookup key" in terms of RFC 
> 8446).
>> With these thoughts in mind, I think log could be clarified to emphasize:
>> - it's not tickets that are stored in cache
>> - with SSL_OP_NO_TICKET set TLSv1.3 session are still saved to lookup by id.
> Hope it is clear enough now.

What I'd like to clarify is the difference between session and (session)
ticket applied to session cache.  Ticket is a container used to envelope
session state (essentially, a session) and send in the NewSessionTicket
message "to resume sessions and avoid keeping per-client session state",
as seen in RFC 8446, 4.6.1 (and somewhat similar in 4507/5077).

      struct {
          uint32 ticket_lifetime;
          uint32 ticket_age_add;
          opaque ticket_nonce<0..255>;
          opaque ticket<1..2^16-1>;
          Extension extensions<0..2^16-2>;
      } NewSessionTicket;

So it looks inappropriate to say that tickets are saved in cache.
OTOH, "ticket" can be seen a correct wording if speaking in terms
of NewSessionTicket ticket field, or in contrast to "session id"
synthesized by OpenSSL for the SSL_OP_NO_TICKET case in TLSv1.3.
In that sense, I'm fine with using "ticket" (not to say changing
"ticket" to "session" or "session state" brings a tautology).
However this looks not so important to spend more time on this,
I'm fine with either case.

>>> diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
>>> --- a/src/event/ngx_event_openssl.c
>>> +++ b/src/event/ngx_event_openssl.c
>>> @@ -3815,6 +3815,22 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
>>>    ngx_ssl_session_cache_t  *cache;
>>>    u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
>>> +#ifdef TLS1_3_VERSION
>>> +
>>> +    /*
>>> +     * OpenSSL for TLSv1.3 tries to save tickets into session cache
>>> +     * "because some applications just want to know about the creation
>>> +     * of a session"; do not cache such sessions
>>> +     */
>>> +
>>> +    if (SSL_version(ssl_conn) == TLS1_3_VERSION
>>> +        && (SSL_get_options(ssl_conn) & SSL_OP_NO_TICKET) == 0)
>>> +    {
>>> +        return 0;
>>> +    }
>>> +
>>> +#endif
>>> +
>>>    len = i2d_SSL_SESSION(sess, NULL);
>>>    /* do not cache too big session */
>> Looks good.
>> [..]

Sergey Kandaurov

More information about the nginx-devel mailing list