quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

TLS-SESSIONS.md (6955B)


      1 <!--
      2 Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      3 
      4 SPDX-License-Identifier: curl
      5 -->
      6 
      7 # TLS Sessions and Tickets
      8 
      9 The TLS protocol offers methods of "resuming" a previous "session". A
     10 TLS "session" is a negotiated security context across a connection
     11 (which may be via TCP or UDP or other transports.)
     12 
     13 By "resuming", the TLS protocol means that the security context from
     14 before can be fully or partially resurrected when the TLS client presents
     15 the proper crypto stuff to the server. This saves on the amount of
     16 TLS packets that need to be sent back and forth, reducing amount
     17 of data and even latency. In the case of QUIC, resumption may send
     18 application data without having seen any reply from the server, hence
     19 this is named 0-RTT data.
     20 
     21 The exact mechanism of session tickets in TLSv1.2 (and earlier) and
     22 TLSv1.3 differs. TLSv1.2 tickets have several weaknesses (that can
     23 be exploited by attackers) which TLSv1.3 then fixed. See
     24 [Session Tickets in the real world](https://words.filippo.io/we-need-to-talk-about-session-tickets/)
     25 for an insight into this topic.
     26 
     27 These difference between TLS protocol versions are reflected in curl's
     28 handling of session tickets. More below.
     29 
     30 ## curl's `ssl_peer_key`
     31 
     32 In order to find a ticket from a previous TLS session, curl
     33 needs a name for TLS sessions that uniquely identifies the peer
     34 it talks to.
     35 
     36 This name has to reflect also the various TLS parameters that can
     37 be configured in curl for a connection. We do not want to use
     38 a ticket from an different configuration. Example: when setting
     39 the maximum TLS version to 1.2, we do not want to reuse a ticket
     40 we got from a TLSv1.3 session, although we are talking to the
     41 same host.
     42 
     43 Internally, we call this name a `ssl_peer_key`. It is a printable
     44 string that carries hostname and port and any non-default TLS
     45 parameters involved in the connection.
     46 
     47 Examples:
     48 - `curl.se:443:CA-/etc/ssl/cert.pem:IMPL-GnuTLS/3.8.7` is a peer key for
     49    a connection to `curl.se:443` using `/etc/ssl/cert.pem` as CA
     50    trust anchors and GnuTLS/3.8.7 as TLS backend.
     51 - `curl.se:443:TLSVER-6-6:CA-/etc/ssl/cert.pem:IMPL-GnuTLS/3.8.7` is the
     52    same as the previous, except it is configured to use TLSv1.2 as
     53    min and max versions.
     54 
     55 Different configurations produce different keys which is just what
     56 curl needs when handling SSL session tickets.
     57 
     58 One important thing: peer keys do not contain confidential information. If you
     59 configure a client certificate or SRP authentication with username/password,
     60 these are not part of the peer key.
     61 
     62 However, peer keys carry the hostnames you use curl for. They *do*
     63 leak the privacy of your communication. We recommend to *not* persist
     64 peer keys for this reason.
     65 
     66 **Caveat**: The key may contain filenames or paths. It does not reflect the
     67 *contents* in the filesystem. If you change `/etc/ssl/cert.pem` and reuse a
     68 previous ticket, curl might trust a server which no longer has a root
     69 certificate in the file.
     70 
     71 
     72 ## Session Cache Access
     73 
     74 #### Lookups
     75 
     76 When a new connection is being established, each SSL connection filter creates
     77 its own peer_key and calls into the cache. The cache then looks for a ticket
     78 with exactly this peer_key. Peer keys between proxy SSL filters and SSL
     79 filters talking through a tunnel differ, as they talk to different peers.
     80 
     81 If the connection filter wants to use a client certificate or SRP
     82 authentication, the cache checks those as well. If the cache peer carries
     83 client cert or SRP auth, the connection filter must have those with the same
     84 values (and vice versa).
     85 
     86 On a match, the connection filter gets the session ticket and feeds that to
     87 the TLS implementation which, on accepting it, tries to resume it for a
     88 shorter handshake. In addition, the filter gets the ALPN used before and the
     89 amount of 0-RTT data that the server announced to be willing to accept. The
     90 filter can then decide if it wants to attempt 0-RTT or not. (The ALPN is
     91 needed to know if the server speaks the protocol you want to send in 0-RTT. It
     92 makes no sense to send HTTP/2 requests to a server that only knows HTTP/1.1.)
     93 
     94 #### Updates
     95 
     96 When a new TLS session ticket is received by a filter, it adds it to the
     97 cache using its peer_key and SSL configuration. The cache looks for
     98 a matching entry and, should it find one, adds the ticket for this
     99 peer.
    100 
    101 ### Put, Take and Return
    102 
    103 when a filter accesses the session cache, it *takes*
    104 a ticket from the cache, meaning a returned ticket is removed. The filter
    105 then configures its TLS backend and *returns* the ticket to the cache.
    106 
    107 The cache needs to treat tickets from TLSv1.2 and 1.3 differently. 1.2 tickets
    108 should be reused, but 1.3 tickets SHOULD NOT (RFC 8446). The session cache
    109 simply drops 1.3 tickets when they are returned after use, but keeps a 1.2
    110 ticket.
    111 
    112 When a ticket is *put* into the cache, there is also a difference. There
    113 can be several 1.3 tickets at the same time, but only a single 1.2 ticket.
    114 TLSv1.2 tickets replace any other. 1.3 tickets accumulate up to a max
    115 amount.
    116 
    117 By having a "put/take/return" we reflect the 1.3 use case nicely. Two
    118 concurrent connections do not reuse the same ticket.
    119 
    120 ## Session Ticket Persistence
    121 
    122 #### Privacy and Security
    123 
    124 As mentioned above, ssl peer keys are not intended for storage in a file
    125 system. They clearly show which hosts the user talked to. This maybe "just"
    126 privacy relevant, but has security implications as an attacker might find
    127 worthy targets among your peer keys.
    128 
    129 Also, we do not recommend to persist TLSv1.2 tickets.
    130 
    131 ### Salted Hashes
    132 
    133 The TLS session cache offers an alternative to storing peer keys:
    134 it provides a salted SHA256 hash of the peer key for import and export.
    135 
    136 #### Export
    137 
    138 The salt is generated randomly for each peer key on export. The SHA256 makes
    139 sure that the peer key cannot be reversed and that a slightly different key
    140 still produces a different result.
    141 
    142 This means an attacker cannot just "grep" a session file for a particular
    143 entry, e.g. if they want to know if you accessed a specific host. They *can*
    144 however compute the SHA256 hashes for all salts in the file and find a
    145 specific entry. They *cannot* find a hostname they do not know. They would
    146 have to brute force by guessing.
    147 
    148 #### Import
    149 
    150 When session tickets are imported from a file, curl only gets the salted
    151 hashes. The imported tickets belong to an *unknown* peer key.
    152 
    153 When a connection filter tries to *take* a session ticket, it passes its peer
    154 key. This peer key initially does not match any tickets in the cache. The
    155 cache then checks all entries with unknown peer keys if the passed key matches
    156 their salted hash. If it does, the peer key is recovered and remembered at the
    157 cache entry.
    158 
    159 This is a performance penalty in the order of "unknown" peer keys which
    160 diminishes over time when keys are rediscovered. Note that this also works for
    161 putting a new ticket into the cache: when no present entry matches, a new one
    162 with peer key is created. This peer key then no longer bears the cost of hash
    163 computes.