RFC 9261

Exported Authenticators in TLS

πŸ“… published July 2022, from ietf

RFC 9261: Exported Authenticators in TLS ✨

Okay bestie, RFC 9261 is here πŸ¦‹. It was written by N. Sullivan at Cloudflare Inc., it's a Standards Track doc, and it's dated July 2022. The ISSN is 2070-1721. The title block doesn't list anything it obsoletes or updates.


Abstract πŸ’œ

This doc describes a mechanism built on top of TLS or DTLS that lets peers prove they own an identity, like an X.509 certificate πŸ”. One peer can export that proof, send it to the other peer out of band, and the receiving peer checks it.

Status of This Memo πŸ“œ

This is an Internet Standards Track document. It's a product of the IETF and represents the consensus of the IETF community. It got public review and was approved for publication by the IESG. You can find more info on Internet Standards in Section 2 of RFC 7841. For the current status, any errata, and how to send feedback, check https://www.rfc-editor.org/info/rfc9261 🌸.

Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication. Please read these carefully, since they explain your rights and restrictions for this document. Code Components pulled out of this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Revised BSD License 🧾.

Table of Contents πŸ—‚οΈ

   1.  Introduction
   2.  Conventions and Terminology
   3.  Message Sequences
   4.  Authenticator Request
   5.  Authenticator
     5.1.  Authenticator Keys
     5.2.  Authenticator Construction
       5.2.1.  Certificate
       5.2.2.  CertificateVerify
       5.2.3.  Finished
       5.2.4.  Authenticator Creation
   6.  Empty Authenticator
   7.  API Considerations
     7.1.  The "request" API
     7.2.  The "get context" API
     7.3.  The "authenticate" API
     7.4.  The "validate" API
   8.  IANA Considerations
     8.1.  Update of the TLS ExtensionType Registry
     8.2.  Update of the TLS Exporter Labels Registry
     8.3.  Update of the TLS HandshakeType Registry
   9.  Security Considerations
   10. References
     10.1.  Normative References
     10.2.  Informative References
   Acknowledgements
   Author's Address

1. Introduction πŸŽ€

Okay so this doc gives you a way to authenticate one party of a Transport Layer Security (TLS) or Datagram Transport Layer Security (DTLS) connection to its peer, using authentication messages created after the session is already set up πŸ™Œ. That means both the client and the server can prove they own extra identities at any point after the handshake is done. The proof can also be exported and sent out of band from one party so its peer can validate it πŸ’….

This mechanism gives you two upgrades over the authentication TLS and DTLS already do natively πŸ‘‘:

  • multiple identities: Endpoints that are the authority for several identities, but don't have one single certificate covering all of them, can authenticate the extra identities over a single connection 🧚.
  • spontaneous authentication: Once a connection is up, endpoints can authenticate in response to events in a higher-layer protocol. They can also bring in more context, like context from the application πŸ’–.

Versions of TLS before TLS 1.3 used renegotiation to do post-handshake client authentication on an existing TLS connection πŸ™ˆ. The mechanism in this document can replace the post-handshake authentication that renegotiation used to provide. Unlike renegotiation, Exported Authenticator-based post-handshake authentication doesn't need any changes at the TLS layer ✨.

Post-handshake authentication is defined in TLS 1.3 Section 4.6.2 of [RFC8446], but it has a downside: it needs extra state stored as part of the TLS state machine 😩. On top of that, the authentication boundaries of TLS 1.3 post-handshake authentication line up with TLS record boundaries. Those often don't match the authentication boundaries of the higher-layer protocol, which is kind of a mess πŸ“. For example, multiplexed connection protocols like HTTP/2 [RFC9113] don't have any idea which TLS record a given message belongs to πŸ’€.

Exported Authenticators are meant to be a building block for application protocols 🧱. Stuff like advertising support and handling authentication errors isn't handled by TLS (or DTLS), so that's on the application protocol 🫢.

The minimum versions of TLS and DTLS needed to implement the mechanisms in this document are TLS 1.2 [RFC5246] and DTLS 1.2 [RFC6347]. (Those were obsoleted by TLS 1.3 [RFC8446] and DTLS 1.3 [RFC9147], just so you know 🌈.)

2. Conventions and Terminology πŸ“š

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, just like shown here πŸ”₯. Lowercase versions are just regular words πŸ™‚.

This document uses terms like client, server, connection, handshake, endpoint, and peer, which are defined in Section 1.1 of [RFC8446] 🧠. The term "initial connection" refers to the (D)TLS connection that the Exported Authenticator messages are derived from ✨.

3. Message Sequences 🧩

There are two types of messages defined in this doc: authenticator requests and authenticators πŸ’Œ. You can combine them in the following three sequences:

Client Authentication

  • Server generates authenticator request
  • Client generates Authenticator from Server's authenticator request
  • Server validates Client's authenticator

Server Authentication

  • Client generates authenticator request
  • Server generates authenticator from Client's authenticator request
  • Client validates Server's authenticator

Spontaneous Server Authentication

  • Server generates authenticator
  • Client validates Server's authenticator

4. Authenticator Request πŸ¦‹

The authenticator request is a structured message that either party of a (D)TLS connection can create, using data exported from that connection πŸ“¦. It can be sent to the other party of the (D)TLS connection at the application layer. The application-layer protocol used to send the authenticator request SHOULD use a secure transport channel with equivalent security to TLS, like QUIC [RFC9001], as its underlying transport so the request stays confidential πŸ”’. The application MAY reuse the existing (D)TLS connection to transport the authenticator.

Either the client or the server can construct an authenticator request message πŸ™Œ. Server-generated authenticator requests use the CertificateRequest message from Section 4.3.2 of [RFC8446]. Client-generated authenticator requests use a new message called "ClientCertificateRequest", which has the same structure as CertificateRequest. (Heads up: the latter isn't a request for a client certificate, it's a certificate request generated by the client πŸ‘€.) These message structures get used even when the connection protocol is TLS 1.2 or DTLS 1.2 ✨.

The CertificateRequest and ClientCertificateRequest messages define the parameters in a request for an authenticator 🧾. They're encoded as TLS handshake messages, including length and type fields. They don't include any TLS record-layer framing, and they aren't encrypted with a handshake or application-data key 🀫.

The structures are defined as:

   struct {
      opaque certificate_request_context<0..2^8-1>;
      Extension extensions<2..2^16-1>;
   } ClientCertificateRequest;

   struct {
      opaque certificate_request_context<0..2^8-1>;
      Extension extensions<2..2^16-1>;
   } CertificateRequest;

Here's what the fields mean 🍭:

  • certificate_request_context: An opaque string that identifies the authenticator request and gets echoed back in the authenticator message πŸͺͺ. A certificate_request_context value MUST be unique for each authenticator request within the scope of a connection (this is what prevents replay and context confusion 🚫). The certificate_request_context SHOULD be unpredictable to the peer, for example by generating it randomly, so an attacker who only has temporary access to the peer's private key can't precompute valid authenticators πŸ•΅οΈ. The application can also pick this value to match a value already used in an existing data structure in the software, which keeps the implementation simpler 🧸.
  • extensions: The set of extensions allowed in the CertificateRequest and ClientCertificateRequest structures is made up of those defined in the "TLS ExtensionType Values" IANA registry that have CR in the "TLS 1.3" column (see [IANA-TLS] and [RFC8447]) πŸ—ƒοΈ. On top of that, the set of extensions in the ClientCertificateRequest structure MAY include the server_name extension [RFC6066] 🌐.

The uniqueness requirements for certificate_request_context apply across CertificateRequest and ClientCertificateRequest messages that are used as part of authenticator requests πŸ”. A certificate_request_context value used in a ClientCertificateRequest cannot be used in an authenticator CertificateRequest on the same connection, and vice versa 🚷. And it's totally fine if the value of a certificate_request_context used in an authenticator request matches a certificate_request_context in the handshake or in a post-handshake message πŸ’β€β™€οΈ.

5. Authenticator πŸ”

The authenticator is a structured message that either party of a (D)TLS connection can export πŸ“€. It can be sent to the other party of the (D)TLS connection at the application layer. The application-layer protocol used to send the authenticator SHOULD use a secure transport channel with equivalent security to TLS, like QUIC [RFC9001], as its underlying transport to keep the authenticator confidential πŸ›‘οΈ. The application MAY reuse the existing (D)TLS connection to transport the authenticator.

An authenticator message can be built by either the client or the server, as long as they have an established (D)TLS connection, an identity (like an X.509 certificate), and a matching private key πŸ—οΈ. Clients MUST NOT send an authenticator without a preceding authenticator request πŸ™…β€β™€οΈ. For servers, an authenticator request is optional. For authenticators that don't correspond to authenticator requests, the server picks the certificate_request_context πŸŽ€.

To be continued in part 2 πŸ’–βœ¨

5.1. Authenticator Keys πŸ”‘βœ¨

okay so bestie, every authenticator is built from a Handshake Context and a Finished MAC Key, and both of those come from the (D)TLS connection itself πŸ¦‹ they're pulled out with an exporter, the way [RFC5705] does it for (D)TLS 1.2 (Section 4 of that one πŸ’…) or the way [RFC8446] does it for (D)TLS 1.3 (Section 7.5 of that one πŸŽ€). and for (D)TLS 1.3 you MUST use the exporter_master_secret, NOT the early_exporter_master_secret πŸ™ˆ no exceptions, periodt πŸ’€

the two values get different labels depending on who's sending:

  • the Handshake Context uses the label "EXPORTER-client authenticator handshake context" if the client is sending the authenticator, or "EXPORTER-server authenticator handshake context" if it's the server 🌸
  • the Finished MAC Key uses "EXPORTER-client authenticator finished key" for the client or "EXPORTER-server authenticator finished key" for the server 🧚

the context_value for the exporter is empty (zero length) for all four of these 🫢 we don't need extra context here, because the application-supplied context already rides along inside the authenticator itself, so it's giving efficiency ✨ the exported value is the same length as the output of the hash function tied to the selected ciphersuite (TLS 1.3) or the hash function behind the PRF (for (D)TLS 1.2) πŸ“ and this hash is what we call the "authenticator hash" πŸ’œ

now the tea β˜•: Exported Authenticators can't be used with (D)TLS 1.2 ciphersuites that skip the TLS PRF, and they also can't be used with TLS 1.3 ciphersuites that don't have an associated hash function. nope, not happening πŸ™…β€β™€οΈ

⚠️ to avoid key synchronization attacks, Exported Authenticators MUST NOT be generated or accepted on (D)TLS 1.2 connections that did NOT negotiate the extended master secret extension [RFC7627]. this one is seriously important, bestie. no shortcuts 😭πŸ”₯

5.2. Authenticator Construction 🧩

an authenticator is just the concatenation of TLS 1.3 Certificate, CertificateVerify, and Finished messages [RFC8446] πŸŽ€ these get encoded as TLS handshake messages (length and type fields included), but they have NO TLS record-layer framing and they are NOT encrypted with a handshake or application-data key πŸ¦‹

if the peer filling in certificate_request_context in an authenticator's Certificate message has already created or correctly validated an authenticator with that same value, then no authenticator SHOULD be constructed πŸ’… and if there's no authenticator request at all, the extensions get picked from the ones in the (D)TLS handshake's ClientHello. only servers can give an authenticator without a matching request πŸ‘‘

ClientHello extensions decide which extensions are allowed in the server's unsolicited Certificate message 🌈 this follows the general (D)TLS extension model: extensions can only show up in a Certificate message if they were previously sent in a CertificateRequest or ClientHello message. that way the recipient can actually process them, iykyk ✨

5.2.1. Certificate πŸ“œ

the Certificate message holds the identity used for authentication, like the end-entity certificate plus any supporting certificates in the chain 🌸 this structure is defined in Section 4.4.2 of [RFC8446] 🧚

the Certificate message has an opaque string called "certificate_request_context", which gets pulled from the authenticator request if there is one πŸ’– if there's no authenticator request, the certificate_request_context can be picked arbitrarily, BUT it MUST be unique within the scope of the connection and MUST be unpredictable to the peer πŸ™ˆ (lowkey the most important vibe check in this whole section)

certificates chosen for the Certificate message MUST conform to the requirements of a Certificate message in the negotiated version of (D)TLS 🫢 in particular, the entries of certificate_list MUST be valid for the signature algorithms the peer indicated in the "signature_algorithms" and "signature_algorithms_cert" extensions. see Section 4.2.3 of [RFC8446] for (D)TLS 1.3, or Sections 7.4.2 and 7.4.6 of [RFC5246] for (D)TLS 1.2 πŸ“

besides "signature_algorithms" and "signature_algorithms_cert", the "server_name" [RFC6066], "certificate_authorities" (Section 4.2.4 of [RFC8446]), and "oid_filters" (Section 4.2.5 of [RFC8446]) extensions help guide certificate selection πŸ’œ

only the X.509 certificate type defined in [RFC8446] is supported πŸ¦‹ alternative formats like Raw Public Keys (as described in [RFC7250]) are NOT supported in this version of the spec, and their use in this context hasn't been analyzed yet. not yet, bestie πŸ₯Ί

if an authenticator request was provided, the Certificate message MUST contain ONLY extensions present in the authenticator request πŸ‘‘ otherwise, it MUST contain only extensions present in the (D)TLS ClientHello. and unrecognized extensions in the authenticator request MUST be ignored 🌈

5.2.2. CertificateVerify πŸ”

this message gives explicit proof that an endpoint actually has the private key for its identity πŸ’… the format is taken from TLS 1.3:

   struct {
      SignatureScheme algorithm;
      opaque signature<0..2^16-1>;
   } CertificateVerify;

the algorithm field says which signature algorithm was used (see Section 4.2.3 of [RFC8446] for the definition of this field) πŸŽ€ and the signature is a digital signature made with that algorithm ✨

the signature scheme MUST be a valid signature scheme for TLS 1.3 πŸ™…β€β™€οΈ this excludes ALL RSASSA-PKCS1-v1_5 algorithms, plus any combos of Elliptic Curve Digital Signature Algorithm (ECDSA) and hash algorithms that aren't supported in TLS 1.3. bye bye πŸ‘‹

if an authenticator request is present, the signature algorithm MUST be chosen from one of the signature schemes in the authenticator request's "signature_algorithms" extension 🫢 otherwise, with spontaneous server authentication, the signature algorithm MUST be chosen from the "signature_algorithms" the peer sent in the ClientHello of the (D)TLS handshake 🌸 and if there are no available signature algorithms, then no authenticator SHOULD be constructed πŸ₯Ί

the signature is computed with the chosen signature scheme over the concatenation of:

  • a string made of octet 32 (0x20) repeated 64 times ✨
  • the context string "Exported Authenticator" (which is NOT NUL-terminated) πŸ¦‹
  • a single 0 octet that serves as the separator 🧚
  • the hashed authenticator transcript πŸ’œ

the authenticator transcript is the hash of the concatenated Handshake Context, authenticator request (if present), and Certificate message πŸ“

Hash(Handshake Context || authenticator request || Certificate)

Hash here is the authenticator hash defined in Section 5.1 πŸ’… if the authenticator request isn't present, it gets left out of this construction, i.e., it's zero-length 🌈

if the party generating the authenticator does it on a different connection than the party validating it, the Handshake Context won't match, so the CertificateVerify message won't validate πŸ™ˆ this includes situations where the application data goes through a TLS-terminating proxy πŸ‘€ if CertificateVerify validation fails, it may be helpful for the application to confirm both peers share the same connection, using a value derived from the connection secrets (like the Handshake Context), before taking any user-visible action 🫢

5.2.3. Finished βœ…

an HMAC [HMAC] over the hashed authenticator transcript is the concatenation of the Handshake Context, authenticator request (if present), Certificate, and CertificateVerify πŸ’– the HMAC is computed with the authenticator hash, using the Finished MAC Key as the key πŸ”‘

Finished = HMAC(Finished MAC Key, Hash(Handshake Context ||
     authenticator request || Certificate || CertificateVerify))

5.2.4. Authenticator Creation πŸ—οΈ

an endpoint builds an authenticator by serializing the Certificate, CertificateVerify, and Finished as TLS handshake messages and concatenating the octets πŸŽ€

Certificate || CertificateVerify || Finished

an authenticator is valid if the CertificateVerify message is correctly constructed given the authenticator request (if used) AND the Finished message matches the expected value πŸ’… when validating an authenticator, constant-time comparisons SHOULD be used for signature and MAC validation πŸ” (no timing leaks, bestie πŸ™ˆ)

6. Empty Authenticator πŸ«₯

if, given an authenticator request, the endpoint doesn't have an appropriate identity or doesn't want to return one, it builds an authenticated refusal called an "empty authenticator" πŸ™…β€β™€οΈ this is a Finished message sent WITHOUT a Certificate or CertificateVerify 🌸 it's an HMAC over the hashed authenticator transcript, with a Certificate message containing no CertificateEntries and the CertificateVerify message omitted 🧚 the HMAC is computed with the authenticator hash, using the Finished MAC Key as the key πŸ’œ this message is encoded as a TLS handshake message (length and type field included), with NO TLS record-layer framing, and it is NOT encrypted with a handshake or application-data key πŸ¦‹

Finished = HMAC(Finished MAC Key, Hash(Handshake Context ||
     authenticator request || Certificate))

7. API Considerations πŸ› οΈ

the creation and validation of both authenticator requests and authenticators SHOULD be implemented INSIDE the (D)TLS library, even if it's possible to do it at the application layer πŸ‘‘ (D)TLS implementations supporting Exported Authenticators SHOULD provide application programming interfaces so clients and servers can request and verify Exported Authenticator messages πŸ’–

notwithstanding the success conditions below, all APIs MUST fail if:

  • the connection uses a (D)TLS version of 1.1 or earlier, or
  • the connection is (D)TLS 1.2 and the extended master secret extension [RFC7627] was NOT negotiated

the next sections describe APIs considered necessary to implement Exported Authenticators. these are informative only 🌈

7.1. The "request" API πŸ“€

the "request" API takes as input:

  • certificate_request_context (from 0 to 255 octets)
  • the set of extensions to include (this MUST include signature_algorithms) and the contents thereof

it returns an authenticator request, which is a sequence of octets that comprises a CertificateRequest or ClientCertificateRequest message πŸ’Œ

7.2. The "get context" API πŸ”

the "get context" API takes as input:

  • authenticator or authenticator request

it returns the certificate_request_context ✨

7.3. The "authenticate" API ✨

okay so the "authenticate" API is the one that actually makes the authenticator πŸ’… it takes in:

  • a reference to the initial connection πŸ”—
  • an identity, like a set of certificate chains and their extensions (OCSP [RFC6960], SCT [RFC6962] (obsoleted by [RFC9162]), etc.) πŸͺͺ
  • a signer for each chain (either the private key tied to the identity, or the interface that does the private key operations) πŸ”‘
  • an authenticator request or certificate_request_context (anywhere from 0 to 255 octets) πŸ“¦

and it hands back either the authenticator or an empty authenticator, as a sequence of octets πŸ¦‹. It is RECOMMENDED that the logic for picking which certificates and extensions go into the exporter lives inside the TLS library 🏠. Why? Because then the library can use the extension and certificate selection logic it already has, and it's way easier to keep track of which extensions were sent in the ClientHello. no cap, that's a huge win πŸ™Œ

It's also possible to build this API outside of the TLS library, using TLS exporters 🧩. This might be the move when the application doesn't have access to a TLS library with these APIs, or when TLS is handled separately from the application-layer protocol 🌸.

7.4. The "validate" API πŸ”

the "validate" API takes in:

  • a reference to the initial connection πŸ”—
  • an optional authenticator request πŸ“
  • an authenticator πŸ¦‹
  • a function for validating a certificate chain πŸ›‘οΈ

and it returns a status that tells you whether the authenticator is valid, after the validation function has been run on the chain inside the authenticator. If validation works out, it also gives you back the identity, like the certificate chain and its extensions ✨.

the API should return a failure if the certificate_request_context of the authenticator was already used in a different authenticator that got validated before. ngl that's the anti-replay vibe πŸ™ˆ. And well-formed empty authenticators come back as invalid πŸ’€.

When you're validating an authenticator, constant-time comparison should be used πŸ”. no peeking at timing, periodt.

8. IANA Considerations 🌈

8.1. Update of the TLS ExtensionType Registry πŸŽ€

IANA has updated the entry for server_name(0) in the "TLS ExtensionType Values" registry [IANA-TLS] (defined in [RFC8446]). The value in the "TLS 1.3" column is now "CH, EE, CR", and this document is listed in the "Reference" column πŸ“‹.

IANA also added this note to the registry:

|  The addition of the "CR" to the "TLS 1.3" column for the
|  server_name(0) extension only marks the extension as valid in a
|  ClientCertificateRequest created as part of client-generated
|  authenticator requests.

8.2. Update of the TLS Exporter Labels Registry 🏷️

IANA added the following entries to the "TLS Exporter Labels" registry [IANA-EXPORT] (defined in [RFC5705]) 🧚:

  • "EXPORTER-client authenticator handshake context"
  • "EXPORTER-server authenticator handshake context"
  • "EXPORTER-client authenticator finished key"
  • "EXPORTER-server authenticator finished key"

Each one has "DTLS-OK" and "Recommended" set to "Y", and this document is listed as the reference πŸ’œ.

8.3. Update of the TLS HandshakeType Registry 🀝

IANA added this entry to the "TLS HandshakeType" registry [IANA-HANDSHAKE] (defined in [RFC8446]): "client_certificate_request" (17), with "DTLS-OK" set to "Y" and this document listed as the reference. The "Comment" column also got this note:

|  Used in TLS versions prior to 1.3.

9. Security Considerations 🚨

okay bestie, this part is SERIOUS 😭 so read it all 🫢

The Certificate/Verify/Finished pattern is on purpose, so it looks like the TLS 1.3 pattern. That pattern has now been analyzed several times πŸ”. For example, [SIGMAC] gives a relevant framework for analysis, and Appendix E.1.6 of [RFC8446] has a comprehensive set of references πŸ“š.

Authenticators are independent and unidirectional πŸ›€οΈ. There is no explicit state change inside TLS when an authenticator is created or validated. An application that has a validated authenticator can rely on any semantics tied to the data in the certificate_request_context 🎯.

  • This property makes it hard to formally prove that a server is jointly authoritative over multiple identities, rather than individually authoritative over each one 🫠.
  • (D)TLS gives no indication of which point in time an authenticator was computed ⏰. If you need any feedback about when an authenticator was created or validated, it should be tracked as part of the application-layer semantics πŸ“.

The signatures made with this API cover the context string "Exported Authenticator", so they can't be transplanted into other protocols πŸš«πŸ”. protected!! πŸ›‘οΈ

In TLS 1.3, the client can't explicitly learn from the TLS layer whether its Finished message was accepted 😬. The application traffic keys don't depend on the client's final flight, so getting messages from the server doesn't prove the server received the client's Finished message. To stop the client and server from disagreeing about the authentication status of Exported Authenticators, servers MUST verify the client Finished message before sending an EA or processing a received Exported Authenticator πŸŒˆπŸ‘‘. this is the main character rule, no exceptions ✨.

10. References πŸ“š

10.1. Normative References πŸ’–

[HMAC]     Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
           Hashing for Message Authentication", RFC 2104,
           DOI 10.17487/RFC2104, February 1997,
           <https://www.rfc-editor.org/info/rfc2104>.

[RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119,
           DOI 10.17487/RFC2119, March 1997,
           <https://www.rfc-editor.org/info/rfc2119>.

[RFC5246]  Dierks, T. and E. Rescorla, "The Transport Layer Security
           (TLS) Protocol Version 1.2", RFC 5246,
           DOI 10.17487/RFC5246, August 2008,
           <https://www.rfc-editor.org/info/rfc5246>.

[RFC5705]  Rescorla, E., "Keying Material Exporters for Transport
           Layer Security (TLS)", RFC 5705, DOI 10.17487/RFC5705,
           March 2010, <https://www.rfc-editor.org/info/rfc5705>.

[RFC6066]  Eastlake 3rd, D., "Transport Layer Security (TLS)
           Extensions: Extension Definitions", RFC 6066,
           DOI 10.17487/RFC6066, January 2011,
           <https://www.rfc-editor.org/info/rfc6066>.

[RFC6347]  Rescorla, E. and N. Modadugu, "Datagram Transport Layer
           Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347,
           January 2012, <https://www.rfc-editor.org/info/rfc6347>.

[RFC7627]  Bhargavan, K., Ed., Delignat-Lavaud, A., Pironti, A.,
           Langley, A., and M. Ray, "Transport Layer Security (TLS)
           Session Hash and Extended Master Secret Extension",
           RFC 7627, DOI 10.17487/RFC7627, September 2015,
           <https://www.rfc-editor.org/info/rfc7627>.

[RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
           2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
           May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
           Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
           <https://www.rfc-editor.org/info/rfc8446>.

[RFC8447]  Salowey, J. and S. Turner, "IANA Registry Updates for TLS
           and DTLS", RFC 8447, DOI 10.17487/RFC8447, August 2018,
           <https://www.rfc-editor.org/info/rfc8447>.

[RFC9147]  Rescorla, E., Tschofenig, H., and N. Modadugu, "The
           Datagram Transport Layer Security (DTLS) Protocol Version
           1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022,
           <https://www.rfc-editor.org/info/rfc9147>.

10.2. Informative References 🧠

[IANA-EXPORT]
           IANA, "TLS Exporter Labels",
           <https://www.iana.org/assignments/tls-parameters/>.

[IANA-HANDSHAKE]
           IANA, "TLS HandshakeType",
           <https://www.iana.org/assignments/tls-parameters/>.

[IANA-TLS] IANA, "TLS ExtensionType Values",
           <https://www.iana.org/assignments/tls-extensiontype-
           values/>.

[RFC6960]  Santesson, S., Myers, M., Ankney, R., Malpani, A.,
           Galperin, S., and C. Adams, "X.509 Internet Public Key
           Infrastructure Online Certificate Status Protocol - OCSP",
           RFC 6960, DOI 10.17487/RFC6960, June 2013,
           <https://www.rfc-editor.org/info/rfc6960>.

[RFC6962]  Laurie, B., Langley, A., and E. Kasper, "Certificate
           Transparency", RFC 6962, DOI 10.17487/RFC6962, June 2013,
           <https://www.rfc-editor.org/info/rfc6962>.

[RFC7250]  Wouters, P., Ed., Tschofenig, H., Ed., Gilmore, J.,
           Weiler, S., and T. Kivinen, "Using Raw Public Keys in
           Transport Layer Security (TLS) and Datagram Transport
           Layer Security (DTLS)", RFC 7250, DOI 10.17487/RFC7250,
           June 2014, <https://www.rfc-editor.org/info/rfc7250>.

[RFC9001]  Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure
           QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021,
           <https://www.rfc-editor.org/info/rfc9001>.

[RFC9113]  Thomson, M., Ed. and C. Benfield, Ed., "HTTP/2", RFC 9113,
           DOI 10.17487/RFC9113, June 2022,
           <https://www.rfc-editor.org/info/rfc9113>.

[RFC9162]  Laurie, B., Messeri, E., and R. Stradling, "Certificate
           Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162,
           December 2021, <https://www.rfc-editor.org/info/rfc9162>.

[SIGMAC]   Krawczyk, H., "A Unilateral-to-Mutual Authentication
           Compiler for Key Exchange (with Applications to Client
           Authentication in TLS 1.3)", Proceedings of the 2016 ACM
           SIGSAC Conference on Computer and Communications Security,
           DOI 10.1145/2976749.2978325, August 2016,
           <https://eprint.iacr.org/2016/711.pdf>.

Acknowledgements 🫢

Big thanks to Martin Thomson for commenting on this proposal πŸ’œ. Karthikeyan Bhargavan gave suggestions for Section 9 🌸.

Author's Address πŸ’Œ

Nick Sullivan
Cloudflare Inc.
Email: nick@cloudflare.com
πŸ“¦ where this page comes from