The protocol consists of two phases: the first time a particular client connects to a server, and subsequent connections.
This protocol supports full TLS handshakes, as well as 0-RTT handshakes. Below we present it in the context of a full handshake, but behavior in 0-RTT handshakes should be identical.
The document presents some similarities with the ticket resumption mechanism described in [
RFC 5077]. However the scope of this document differs from session resumption mechanisms implemented with [
RFC 5077] or with other mechanisms. Specifically, the pinning ticket does not carry any state associated with a TLS session and thus cannot be used for session resumption or client authentication. Instead, the pinning ticket only contains the encrypted pinning secret. The pinning ticket is used by the server to prove its ability to decrypt it, which implies ownership of the pinning protection key.
[
RFC 5077] has been obsoleted by [
RFC 8446], and ticket resumption is now defined by
Section 2.2 of
RFC 8446. This document references [
RFC 5077] as an informational document since it contains a more thorough discussion of stateless ticket resumption, and because ticket resumption benefits from significant operational experience with TLS 1.2 that is still widely deployed at the time of writing. This experience, as well as deployment experience, can easily be re-used for identity pinning.
With TLS 1.3, session resumption is based on a Pre-Shared Key (PSK). This is orthogonal to this protocol. With TLS 1.3, a TLS session can be established using PKI and a pinning ticket, and later resumed with PSK.
However, the protocol described in this document addresses the problem of misissued certificates. Thus, it is not expected to be used outside a certificate-based TLS key exchange, such as in PSK. As a result, PSK handshakes
MUST NOT include the extension defined here.
When a client first connects to a server, it requests a pinning ticket by sending an empty PinningTicket extension, and receives it as part of the server's first response, in the returned PinningTicket extension.
Client Server
ClientHello
+ key_share
+ signature_algorithms
+ PinningTicket -------->
ServerHello
+ key_share
{EncryptedExtensions
+ PinningTicket}
{CertificateRequest*}
{Certificate*}
{CertificateVerify*}
<-------- {Finished}
{Certificate*}
{CertificateVerify*}
{Finished} -------->
[Application Data] <-------> [Application Data]
* Indicates optional or situation-dependent
messages that are not always sent.
{} Indicates messages protected using keys
derived from the ephemeral secret.
[] Indicates messages protected using keys
derived from the master secret.
If a client supports the PinningTicket extension and does not have any pinning ticket associated with the server, the exchange is considered as an initial connection. Other reasons the client may not have a pinning ticket include the client having flushed its pinning ticket store, or the committed lifetime of the pinning ticket having expired.
Upon receipt of the PinningTicket extension, the server computes a pinning secret (
Section 4.1) and sends the pinning ticket (
Section 4.2) encrypted with the pinning protection key (
Section 4.3). The pinning ticket is associated with a lifetime value by which the server assumes the responsibility of retaining the pinning protection key and being able to decrypt incoming pinning tickets during the period indicated by the committed lifetime.
Once the pinning ticket has been generated, the server returns the pinning ticket and the committed lifetime in a PinningTicket extension embedded in the EncryptedExtensions message. We note that a PinningTicket extension
MUST NOT be sent as part of a HelloRetryRequest.
Upon receiving the pinning ticket, the client
MUST NOT accept it until the key exchange is completed and the server authenticated. If the key exchange is not completed successfully, the client
MUST ignore the received pinning ticket. Otherwise, the client computes the pinning secret and
SHOULD cache the pinning secret and the pinning ticket for the duration indicated by the pinning ticket lifetime. The client
SHOULD clean up the cached values at the end of the indicated lifetime.
When the client initiates a connection to a server it has previously seen (see
Section 2.3 on identifying servers), it
SHOULD send the pinning ticket for that server. The pinning ticket, pinning secret, and pinning ticket lifetime computed during the establishment of the previous TLS session are designated in this document as the "original" ones, to distinguish them from a new ticket that may be generated during the current session.
The server
MUST extract the original pinning_secret value from the ticket and
MUST respond with a PinningTicket extension, which includes:
-
A proof that the server can understand the ticket that was sent by the client; this proof also binds the pinning ticket to the server's (current) public key, as well as the ongoing TLS session. The proof is mandatory and MUST be included if a pinning ticket was sent by the client.
-
A fresh pinning ticket. The main reason for refreshing the ticket on each connection is privacy: to avoid the ticket serving as a fixed client identifier. While a fresh pinning ticket might be of zero length, it is RECOMMENDED to include a fresh ticket with a nonzero length with each response.
If the server cannot validate the received ticket, that might indicate an earlier MITM attack on this client. The server
MUST then abort the connection with a handshake_failure alert and
SHOULD log this failure.
The client
MUST verify the proof, and if it fails to do so, the client
MUST issue a handshake_failure alert and abort the connection (see also
Section 6.5). It is important that the client does not attempt to "fall back" by omitting the PinningTicket extension.
When the connection is successfully set up, i.e., after the Finished message is verified, the client
SHOULD store the new ticket along with the corresponding pinning_secret, replacing the original ticket.
Although this is an extension, if the client already has a ticket for a server, the client
MUST interpret a missing PinningTicket extension in the server's response as an attack, because of the server's prior commitment to respect the ticket. The client
MUST abort the connection in this case. See also
Section 5.5 on ramping down support for this extension.
Each pin is associated with a set of identifiers that include, among others, hostname, protocol (TLS or DTLS), and port number. In other words, the pin for port TCP/443 may be different from that for DTLS, or from the pin for port TCP/8443. These identifiers are expected to be relevant to characterize the identity of the server as well as the establishing TLS session. When a hostname is used, it
MUST be the value sent inside the Server Name Indication (SNI) extension. This definition is similar to the concept of a Web Origin [
RFC 6454], but does not assume the existence of a URL.
The purpose of ticket pinning is to pin the server identity. As a result, any information orthogonal to the server's identity
MUST NOT be considered in indexing. More particularly, IP addresses are ephemeral and forbidden in SNI, and therefore pins
MUST NOT be associated with IP addresses. Similarly, CA names or public keys associated with server
MUST NOT be used for indexing as they may change over time.