RFC 9163

Expect-CT Extension for HTTP

๐Ÿ“… published June 2022, from ietf

RFC 9163: Expect-CT Extension for HTTP ๐ŸŽ€

Okay bestie, let's talk about this one ๐Ÿ’… It's an IETF doc, and the author is E. Stark at Google. It's published as Request for Comments 9163, dated June 2022, and the category is Experimental ๐Ÿงช The ISSN is 2070-1721. It doesn't list anything it obsoletes or updates, so it's not replacing or patching any older RFCs ๐Ÿฆ‹

Abstract ๐Ÿ’–

This doc introduces a brand new HTTP header field called "Expect-CT" โœจ It lets web host operators tell user agents (UAs) to expect valid Signed Certificate Timestamps (SCTs) on connections to their hosts ๐Ÿ”ฅ That's how hosts can catch misconfigurations in their Certificate Transparency (CT) setup ๐Ÿ•ต๏ธโ€โ™€๏ธ And here's the iconic part: if a UA that supports Expect-CT accepts a misissued certificate, host operators can make sure that certificate still shows up in Certificate Transparency logs ๐Ÿซถ

Status of This Memo ๐ŸŒธ

Not an Internet Standards Track spec, babe. This one is published for examination, experimental implementation, and evaluation ๐Ÿงช

It defines an Experimental Protocol for the Internet community โœจ It's a product of the Internet Engineering Task Force (IETF), it represents the consensus of the IETF community, and it went through public review before the Internet Engineering Steering Group (IESG) approved it for publication ๐Ÿ’œ Not every IESG-approved doc is a candidate for any level of Internet Standard, though. See Section 2 of RFC 7841 for that ๐Ÿ™ˆ

If you want the current status, any errata, or a way to send feedback, check out https://www.rfc-editor.org/info/rfc9163 ๐Ÿ“

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

This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the publication date. Please actually read those, because they spell out your rights and restrictions for this doc ๐Ÿ“œ Any 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
  1.1.  Requirements Language
  1.2.  Terminology
2.  Server and Client Behavior
  2.1.  Response Header Field Syntax
    2.1.1.  The report-uri Directive
    2.1.2.  The enforce Directive
    2.1.3.  The max-age Directive
    2.1.4.  Examples
  2.2.  Host Processing Model
    2.2.1.  HTTP-over-Secure-Transport Request Type
    2.2.2.  HTTP Request Type
  2.3.  User Agent Processing Model
    2.3.1.  Missing or Malformed Expect-CT Header Fields
    2.3.2.  Expect-CT Header Field Processing
    2.3.3.  Reporting
  2.4.  Evaluating Expect-CT Connections for CT Compliance
    2.4.1.  Skipping CT Compliance Checks
3.  Reporting Expect-CT Failure
  3.1.  Generating a Violation Report
  3.2.  Sending a Violation Report
  3.3.  Receiving a Violation Report
4.  Usability Considerations
5.  Authoring Considerations
6.  Privacy Considerations
7.  Security Considerations
  7.1.  Hostile Header Attacks
  7.2.  Maximum max-age
  7.3.  Amplification Attacks
8.  IANA Considerations
  8.1.  Header Field Registry
  8.2.  Media Types Registry
9.  References
  9.1.  Normative References
  9.2.  Informative References
Author's Address

1. Introduction ๐Ÿฆ‹

Okay so the big idea: this doc defines a new HTTP header field ([RFC9110], Section 6.3) that lets UAs spot web hosts that expect Signed Certificate Timestamps (SCTs) [RFC9162] to show up on later Transport Layer Security (TLS) [RFC8446] connections ๐Ÿ” Iconic behavior, honestly.

Web hosts that serve the Expect-CT header field get labeled by the UA as "Known Expect-CT Hosts" ๐Ÿท๏ธ The UA checks every connection to a Known Expect-CT Host against its Certificate Transparency (CT) Policy โœ… If a connection breaks that policy, the UA either sends a report to a URI the Expect-CT Host configured, or it fails the connection, or both. It depends on what the host picked ๐Ÿ’…

Now the messy part ๐Ÿ˜ญ If it's misconfigured, Expect-CT can cause connection failures nobody wants. Like, a host turns on Expect-CT and then swaps to a legit certificate that isn't logged in CT logs. Or a host operator is totally sure their cert follows every UA's CT policy, and they're wrong ๐Ÿ™ˆ So the doc says host operators should deploy Expect-CT with precautions: use the reporting feature, and slowly increase the time window during which the UA treats the host as a Known Expect-CT Host ๐Ÿงš Those steps help operators feel confident their setup isn't breaking connections.

Expect-CT is a trust-on-first-use (TOFU) mechanism, which means the first time a UA connects to a host, it doesn't have the info it needs to require SCTs. So the UA can't detect or stop an attack on that very first connection ๐Ÿ˜ฌ Still, it's valuable for two reasons: 1) UAs can catch unlogged certificates after the initial contact, and 2) web hosts can be confident that UAs are only trusting publicly auditable certificates ๐Ÿ’œ

Expect-CT is kind of a cousin of HTTP Strict Transport Security (HSTS) [RFC6797] and HTTP Public Key Pinning (HPKP) [RFC7469] ๐Ÿ‘ฏโ€โ™€๏ธ HSTS lets websites declare they're only reachable over secure connections, and HPKP lets them declare their cryptographic identifiers. Expect-CT does the same kind of thing: it lets websites declare they're only reachable over connections that comply with CT Policy โœจ

This Expect-CT spec works with [RFC6962] and [RFC9162], but it isn't guaranteed to work with future versions of Certificate Transparency ๐Ÿคทโ€โ™€๏ธ UAs will ignore Expect-CT header fields from hosts running future versions of Certificate Transparency, unless a future version of this document says how they should be handled ๐ŸŒธ

1.1. Requirements Language ๐Ÿ’…

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 interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐ŸŽ€

1.2. Terminology ๐Ÿ“–

Here's the glossary, bestie ๐Ÿงš Each term is explained below.

  • "Certificate Transparency Policy": A policy the UA defines about the number, sources, and delivery mechanisms of Signed Certificate Timestamps linked to TLS connections. The policy spells out the properties a connection has to have before the UA considers it CT qualified. ๐Ÿ“œ
  • "Certificate Transparency Qualified": Describes a TLS connection where the UA has decided there's a sufficient quantity and quality of Signed Certificate Timestamps. ๐Ÿ”
  • "CT Qualified": Just the abbreviation for "Certificate Transparency Qualified". ๐Ÿ’ซ
  • "CT Policy": Just the abbreviation for "Certificate Transparency Policy". ๐Ÿ’ซ
  • "Effective Expect-CT Date": The time when a UA saw a valid Expect-CT header field for a given host. โฐ
  • "Expect-CT Host": A conformant host that implements the HTTP server side of Expect-CT. That means an Expect-CT Host returns the Expect-CT response header field in its HTTP response messages sent over secure transport. In this spec, "host" and "server" mean the same thing ๐Ÿซถ
  • "Known Expect-CT Host": An Expect-CT Host the UA has noted as one. See Section 2.3.2.1 for particulars. ๐Ÿท๏ธ
  • "User Agent (UA)": For this spec, a UA is an HTTP client application that a user is typically actively driving [RFC9110]. ๐Ÿ“ฑ
  • "Unknown Expect-CT Host": An Expect-CT Host the UA has not noted. ๐Ÿ‘€

2. Server and Client Behavior ๐Ÿ–ฅ๏ธ

2.1. Response Header Field Syntax ๐ŸŽ€

The Expect-CT response header field is brand new in this spec ๐ŸŒŸ A server uses it to tell UAs to check connections to the host that sent the header for CT compliance (Section 2.4) ๐Ÿ’…

Figure 1 is the syntax for the header field, written in Augmented Backus-Naur Form (ABNF). It uses the grammar from [RFC5234] and the rules from Section 5 of [RFC9110], and the "#" ABNF extension comes from Section 5.6.1 of [RFC9110] ๐Ÿง 

Expect-CT           = 1#expect-ct-directive
expect-ct-directive = directive-name [ "=" directive-value ]
directive-name      = token
directive-value     = token / quoted-string

            Figure 1: Syntax of the Expect-CT Header Field

The directives this spec defines are described below. Here are the overall rules for directives, babe ๐Ÿ“‹

  1. The order of directives doesn't matter ๐ŸŒˆ
  2. A given directive MUST NOT appear more than once in a given header field. Directives are either optional or required, depending on how they're defined ๐Ÿ™…โ€โ™€๏ธ
  3. Directive names are case insensitive ๐Ÿ”ค
  4. UAs MUST ignore any header fields that contain directives, or other header field value data, that doesn't follow the syntax defined in this spec. Specifically, UAs MUST NOT attempt to fix malformed header fields. No fixing, no vibes-based repairs ๐Ÿ› ๏ธ๐Ÿšซ
  5. If a header field has any directive the UA doesn't recognize, the UA MUST ignore those directives ๐Ÿซฅ
  6. If the Expect-CT header field meets the requirements above (1 through 5), and Expect-CT isn't turned off for local policy reasons (as discussed in Section 2.4.1), the UA MUST process the directives it recognizes โœจ That's the whole vibe, and I'll be back with the rest soon ๐Ÿ’–

2.1.1. The report-uri Directive โœจ

Okay so the OPTIONAL report-uri directive is basically the address for the drama ๐Ÿ“ฎ. It tells the UA where it SHOULD report Expect-CT failures (Section 2.4). The UA POSTs those reports to the given URI, as described in Section 3 ๐Ÿ’Œ.

Bestie, the report-uri directive is REQUIRED to have a directive value ๐Ÿงพ. The syntax is in Figure 2:

   report-uri-value = (DQUOTE absolute-URI DQUOTE) / absolute-URI

Figure 2: Syntax of the report-uri Directive Value

The 'report-uri-value' MUST be quoted if it has any character that isn't allowed in 'token' ๐Ÿ™…โ€โ™€๏ธ. absolute-URI is defined in Section 4.3 of [RFC3986].

UAs MUST ignore any report-uri that does not use the HTTPS scheme. Not HTTPS? Not invited ๐Ÿšซ. UAs MUST check Expect-CT compliance when the host in the report-uri is a Known Expect-CT Host. Similarly, UAs MUST apply HSTS [RFC6797] if the host in the report-uri is a Known HSTS Host. The vibes have to be secure ๐Ÿ”’.

UAs SHOULD make their best effort to report Expect-CT failures to the report-uri, but they may fail to report in exceptional conditions ๐Ÿซ . For example, if connecting to the report-uri itself runs into an Expect-CT failure or some other certificate validation failure, the UA MUST cancel the connection ๐Ÿ’€. Also, if Expect-CT Host A sets a report-uri pointing at Expect-CT Host B, and B sets a report-uri pointing back at A, and both hosts fail to comply with the UA's CT Policy, the UA SHOULD detect and break the loop. That means failing to send reports to and about those hosts ๐Ÿ”.

Note that the report-uri does not need to be in the same Internet domain or web origin as the host being reported about. Hosts are in fact encouraged to use a separate host as the report-uri, so that CT failures on the Expect-CT Host don't stop reports from being sent. Separate host = protected drama ๐ŸŽ€.

UAs SHOULD limit the rate at which they send reports. For example, it is unnecessary to send the same report to the same report-uri more than once in the same web-browsing session ๐ŸŒธ.

2.1.2. The enforce Directive ๐Ÿ”ฅ

The OPTIONAL enforce directive is a valueless directive. If it's present (i.e., it is "asserted"), it tells the UA that compliance with the CT Policy should be enforced (rather than report-only), and that the UA should refuse future connections that violate its CT Policy. When both the enforce directive and the report-uri directive (as defined in Figure 2) are present, that's called an "enforce-and-report" configuration. It tells the UA that compliance with the CT Policy should be enforced AND violations should be reported ๐Ÿ‘‘.

2.1.3. The max-age Directive โณ

The max-age directive sets how many seconds count from the moment the UA receives the Expect-CT header field. During that window, the UA SHOULD regard the host that sent the message as a Known Expect-CT Host ๐Ÿฆ‹.

If a response contains an Expect-CT header field, then the response MUST contain an Expect-CT header field with a max-age directive. (A max-age directive doesn't need to show up in every Expect-CT header field in the response, fr.) The max-age directive is REQUIRED to have a directive value. Its syntax (after quoted-string unescaping, if necessary) is in Figure 3 โœจ:

   max-age-value = delta-seconds
   delta-seconds = 1*DIGIT

Figure 3: Syntax of the max-age Directive Value

delta-seconds is used as defined in Section 1.3 of [RFC9111].

2.1.4. Examples ๐Ÿงš

These three examples show valid Expect-CT response header fields. The second one splits the directives across two field instances ๐Ÿ’…:

   Expect-CT: max-age=86400, enforce

   Expect-CT: max-age=86400,enforce
   Expect-CT: report-uri="https://foo.example/report"

   Expect-CT: max-age=86400,report-uri="https://foo.example/report"

Figure 4: Examples of Valid Expect-CT ResponseHeader Fields

2.2. Host Processing Model ๐ŸŒˆ

This section describes the processing model that Expect-CT Hosts implement. The model has 2 parts. Part (1) covers the processing rules for HTTP request messages received over a secure transport (e.g., authenticated, non-anonymous TLS). Part (2) covers the processing rules for HTTP request messages received over non-secure transports, such as TCP ๐Ÿ“.

2.2.1. HTTP-over-Secure-Transport Request Type ๐Ÿ”

An Expect-CT Host includes an Expect-CT header field in its response. The header field MUST satisfy the grammar specified in Section 2.1 ๐Ÿ’–.

Establishing a given host as an Expect-CT Host, in the context of a given UA, happens in these ways:

  1. Over the HTTP protocol running over secure transport, by correctly returning (per this specification) a valid Expect-CT header field to the UA.
  2. Through other mechanisms, such as a client-side preloaded Expect-CT Host list.

2.2.2. HTTP Request Type ๐Ÿ“ญ

Expect-CT Hosts SHOULD NOT include the Expect-CT header field in HTTP responses conveyed over non-secure transport ๐Ÿ™ˆ.

2.3. User Agent Processing Model ๐Ÿ’œ

The UA processing model relies on parsing domain names. Note that internationalized domain names SHALL be canonicalized by the UA according to the scheme in Section 10 of [RFC6797] ๐ŸŒ.

The UA stores Known Expect-CT Hosts and their associated Expect-CT directives. This whole bundle is collectively known as a host's "Expect-CT metadata" ๐Ÿ—‚๏ธ.

2.3.1. Missing or Malformed Expect-CT Header Fields ๐Ÿฅฒ

If an HTTP response does not include an Expect-CT header field that conforms to the grammar specified in Section 2.1, then the UA MUST NOT update any Expect-CT metadata. Nothing's changing, sis ๐Ÿ›‘.

2.3.2. Expect-CT Header Field Processing ๐Ÿ”

If the UA receives an HTTP response over a secure transport that includes an Expect-CT header field conforming to the grammar specified in Section 2.1, the UA MUST evaluate the connection on which the header field was received for compliance with the UA's CT Policy. Then it processes the Expect-CT header field as follows. UAs MUST ignore any Expect-CT header field received in an HTTP response conveyed over non-secure transport ๐Ÿšซ.

If the connection does not comply with the UA's CT Policy (i.e., the connection is not CT qualified), then the UA MUST NOT update any Expect-CT metadata. If the header field includes a report-uri directive, the UA SHOULD send a report to the specified report-uri (Section 2.3.3) ๐Ÿ“ฃ.

If the connection complies with the UA's CT Policy (i.e., the connection is CT qualified), then the UA MUST either:

  • Note the host as a Known Expect-CT Host if it is not already so noted (see Section 2.3.2.1), or
  • Update the UA's cached information for the Known Expect-CT Host if the enforce, max-age, or report-uri header field value directives convey information different from what the UA already maintains. If the max-age directive has a value of 0, the UA MUST remove its cached Expect-CT information if the host was previously noted as a Known Expect-CT Host, and MUST NOT note this host as a Known Expect-CT Host if it is not already noted ๐Ÿงน.

If a UA receives an Expect-CT header field over a CT-compliant connection that uses a version of Certificate Transparency other than [RFC6962] or [RFC9162], the UA MUST ignore the Expect-CT header field and clear any Expect-CT metadata associated with the host. Wrong CT version, we're clearing the whole thing ๐Ÿงผ.

2.3.2.1. Noting Expect-CT ๐Ÿ“

Upon receipt of the Expect-CT response header field over an error-free TLS connection (with X.509 certificate chain validation as described in [RFC5280], as well as the validation described in Section 2.4 of this document), the UA MUST note the host as a Known Expect-CT Host. It stores the host's domain name and its associated Expect-CT directives in non-volatile storage ๐Ÿ’พ.

To note a host as a Known Expect-CT Host, the UA MUST set its Expect-CT metadata in its Known Expect-CT Host cache (as specified in Section 2.3.2.2). It uses the metadata given in the most recently received valid Expect-CT header field ๐Ÿซถ.

For forward compatibility, the UA MUST ignore any unrecognized Expect-CT header field directives while still processing the directives it does recognize. Section 2.1 specifies the directives enforce, max-age, and report-uri, but future specifications and implementations might use additional directives. Future-proof era ๐Ÿ”ฎ.

2.3.2.2. Storage Model ๐Ÿ—„๏ธ

If the substring matching the host production from the Request-URI (of the message the host responded to) does not exactly match an existing Known Expect-CT Host's domain name, per the matching procedure for a Congruent Match specified in Section 8.2 of [RFC6797], then the UA MUST add this host to the Known Expect-CT Host cache. The UA caches:

  • the Expect-CT Host's domain name.
  • whether the enforce directive is present.
  • the Effective Expiration Date, which is the Effective Expect-CT Date plus the value of the max-age directive. Alternatively, the UA MAY cache enough information to calculate the Effective Expiration Date. The Effective Expiration Date is calculated from when the UA observed the Expect-CT header field, and it is independent of when the response was generated โฐ.
  • the value of the report-uri directive, if present.

If any other metadata from optional or future Expect-CT header directives is present in the Expect-CT header field, and the UA understands them, the UA MAY note them as well โœจ.

UAs MAY set an upper limit on the value of max-age, so that UAs that have noted erroneous Expect-CT Hosts (whether by accident or due to attack) have some chance of recovering over time ๐ŸŒฑ. If the server sets a max-age greater than the UA's upper limit, the UA may behave as if the server set the max-age to the UA's upper limit. For example, if the UA caps max-age at 5,184,000 seconds (60 days), and an Expect-CT Host sets a max-age directive of 90 days in its Expect-CT header field, the UA may behave as if the max-age were effectively 60 days. (One way to achieve this behavior is for the UA to simply store a value of 60 days instead of the 90-day value provided by the Expect-CT Host. Smart and simple ๐Ÿฐ.)

2.3.3. Reporting ๐Ÿ“ฌ

If the UA receives, over a secure transport, an HTTP response that includes an Expect-CT header field with a report-uri directive, and the connection does not comply with the UA's CT Policy (i.e., the connection is not CT qualified), and the UA has not already sent an Expect-CT report for this connection, then the UA SHOULD send a report to the specified report-uri as specified in Section 3. Report it, bestie ๐Ÿ’…๐Ÿฆ‹

2.4. Evaluating Expect-CT Connections for CT Compliance โœจ

okay bestie, so when a UA sets up a TLS connection, it checks whether the host is a Known Expect-CT Host by looking in its Known Expect-CT Host cache. An Expect-CT Host is "expired" if the Effective Expiration Date refers to a date in the past. The UA MUST ignore any expired Expect-CT Hosts in its cache and must not treat them as Known Expect-CT Hosts. bye to those ๐Ÿ’€

When a UA connects to a Known Expect-CT Host over TLS and the connection has no errors, the UA will run one more correctness check: compliance with a CT Policy. A UA should evaluate compliance with its CT Policy whenever it connects to a Known Expect-CT Host ๐Ÿ”ฅ But the check can be skipped for local policy reasons (see Section 2.4.1), or if other checks make the UA end the connection before CT compliance is evaluated. For example, a Public Key Pinning failure [RFC7469] could make the UA terminate the connection before CT compliance is checked. Similarly, if the UA terminates the connection due to an Expect-CT failure, that could cause the UA to skip later correctness checks. When the CT compliance check is skipped or bypassed, Expect-CT reports (Section 3) will not be sent. it's giving "some checks get skipped and that's fine" ๐Ÿ™ˆ

When CT compliance is evaluated for a Known Expect-CT Host, the UA MUST evaluate compliance when setting up the TLS session, before it begins an HTTP conversation over the TLS channel. no skipping ahead, we check first ๐Ÿซถ

If a connection to a Known Expect-CT Host violates the UA's CT Policy (meaning the connection is not CT qualified), and the Known Expect-CT Host's Expect-CT metadata indicates an enforce configuration, the UA MUST treat the CT compliance failure as an error. The UA MAY let the user bypass the error, unless connection errors should have no user recourse because of other policies in effect (such as HSTS, as described in Section 12.1 of [RFC6797]). main character energy for the policies, honestly ๐Ÿ‘‘

If a connection to a Known Expect-CT Host violates the UA's CT Policy, and the Known Expect-CT Host's Expect-CT metadata includes a report-uri, the UA SHOULD send an Expect-CT report to that report-uri (Section 3). ๐Ÿ“จ

2.4.1. Skipping CT Compliance Checks

It is acceptable for a UA to skip CT compliance checks for some hosts according to local policy. For example, a UA MAY disable CT compliance checks for hosts whose validated certificate chain ends at a user-defined trust anchor, rather than at a trust anchor built into the UA (or the underlying platform). local choices, valid ๐ŸŒธ

If the UA does not evaluate CT compliance, for example because the user has chosen to turn it off, or because a presented certificate chain chains up to a user-defined trust anchor, UAs SHOULD NOT send Expect-CT reports. no check, no report, simple as that ๐ŸŽ€


3. Reporting Expect-CT Failure ๐Ÿฆ‹

When the UA tries to connect to a Known Expect-CT Host and the connection is not CT qualified, the UA SHOULD report Expect-CT failures to the report-uri, if there is one, in the Known Expect-CT Host's Expect-CT metadata.

When the UA receives an Expect-CT response header field over a connection that is not CT qualified, and the UA has not already sent an Expect-CT report for this connection, then the UA SHOULD report Expect-CT failures to the configured report-uri, if there is one. no double reporting, we're efficient here ๐Ÿ’…

3.1. Generating a Violation Report

To generate a violation report object, the UA builds a JSON [RFC8259] object with the following keys and values:

  • "date-time": The value for this key is the UTC time that the UA observed the CT compliance failure. It is a string formatted according to Section 5.6 of [RFC3339], "Internet Date/Time Format". โฐ
  • "hostname": The value is the hostname the UA made the original request to, the one that failed the CT compliance check. It is provided as a string.
  • "port": The value is the port the UA made the original request to, the one that failed the CT compliance check. It is provided as an integer.
  • "scheme" (optional): The value is the scheme the UA used for the original request that failed the CT compliance check. It is provided as a string. This key is optional and is assumed to be "https" if it is not present. ๐Ÿ”
  • "effective-expiration-date": The value is the Effective Expiration Date (see Section 2.3.2.2) for the Expect-CT Host that failed the CT compliance check, in UTC. It is provided as a string formatted according to Section 5.6 of [RFC3339], "Internet Date/Time Format". ๐Ÿ—“๏ธ
  • "served-certificate-chain": The value is the certificate chain as served by the Expect-CT Host during TLS session setup. It is provided as an array of strings, and the strings MUST appear in the order the certificates were served. Each string in the array is the Privacy-Enhanced Mail (PEM) representation of one X.509 certificate, as described in [RFC7468]. ๐Ÿ“œ
  • "validated-certificate-chain": The value is the certificate chain as built by the UA during certificate chain verification. (This may differ from the value of the "served-certificate-chain" key.) It is provided as an array of strings, which MUST appear in the order matching the chain the UA validated. Each string in the array is the PEM representation of one X.509 certificate, as described in [RFC7468]. The first certificate in the chain is the end-entity certificate being verified. UAs that build certificate chains in more than one way during validation SHOULD send the last chain built. โœ…
  • "scts": The value represents the SCTs (if any) that the UA received for the Expect-CT Host, along with their validation statuses. It is provided as an array of JSON objects. The SCTs may appear in any order. Each JSON object in the array has the following keys:
    • A "version" key, with an integer value. The UA MUST set this value to 1 if the SCT is in the format defined in Section 3.2 of [RFC6962], or to 2 if it is in the format defined in Section 4.5 of [RFC9162].
    • The "status" key, with a string value that the UA MUST set to one of the following values: "unknown" (meaning the UA does not have, or does not trust, the public key of the log the SCT was issued by); "valid" (meaning the UA successfully validated the SCT as described in Section 5.2 of [RFC6962] or Section 8.1.3 of [RFC9162]); or "invalid" (meaning SCT validation failed because of a bad signature or an invalid timestamp).
    • The "source" key, with a string value that says where the UA got the SCT from, as defined in Section 3 of [RFC6962] and Section 6 of [RFC9162]. The UA MUST set the value to one of the following: "tls-extension", "ocsp", or "embedded". These match the three ways of delivering SCTs in the TLS handshake that are described in Section 3.3 of [RFC6962].
    • The "serialized_sct" key, with a string value. If the value of the "version" key is 1, the UA MUST set this value to the base64-encoded [RFC4648] serialized SignedCertificateTimestamp structure from Section 3.2 of [RFC6962]. The base64 encoding is defined in Section 4 of [RFC4648]. If the value of the "version" key is 2, the UA MUST set this value to the base64-encoded [RFC4648] serialized TransItem structure representing the SCT, as defined in Section 4.5 of [RFC9162]. ๐Ÿงš
  • "failure-mode": The value indicates whether the Expect-CT report was triggered by an Expect-CT policy in enforce or report-only mode. It is provided as a string. The UA MUST set this value to "enforce" if the Expect-CT metadata indicates an enforce configuration, and to "report-only" otherwise. โš ๏ธ
  • "test-report" (optional): The value is set to true if the report is being sent by a testing client to check that the report server behaves correctly. It is provided as a boolean and MUST be set to true if the report serves to test the server's behavior and can be discarded. ๐Ÿงช

3.2. Sending a Violation Report

The UA SHOULD report Expect-CT failures for Known Expect-CT Hosts. That is, when a connection to a Known Expect-CT Host does not comply with the UA's CT Policy and the host's Expect-CT metadata contains a report-uri.

The UA SHOULD also report Expect-CT failures for hosts that it has no stored Expect-CT metadata for. That is, when the UA connects to a host and receives an Expect-CT header field that contains the report-uri directive, the UA SHOULD report an Expect-CT failure if the connection does not comply with the UA's CT Policy. ๐Ÿฆ‹

The steps to report an Expect-CT failure are as follows:

  1. Prepare a JSON report object with the single key "expect-ct-report", whose value is the result of generating a violation report object as described in Section 3.1.
  2. Let report body be the JSON stringification of the report object.
  3. Let report-uri be the value of the report-uri directive in the Expect-CT header field.
  4. Send an HTTP POST request to report-uri with a Content-Type header field of application/expect-ct-report+json and an entity body consisting of report body.

The UA MAY perform other operations as part of sending the HTTP POST request, such as sending a Cross-Origin Resource Sharing (CORS) preflight as part of [FETCH]. extra steps are optional, we vibe ๐ŸŒˆ

Future versions of this specification may need to modify or extend the Expect-CT report format. They may do so by defining a new top-level key to contain the report, replacing the "expect-ct-report" key. Section 3.3 defines how report servers should handle report formats they do not support. ๐Ÿ”ฎ

3.3. Receiving a Violation Report

When an Expect-CT violation report arrives, the report server MUST respond with a 2xx (Successful) status code if it can parse the request body as valid JSON, the report conforms to the format described in Section 3.1, and it recognizes the scheme, hostname, and port in the "scheme", "hostname", and "port" fields of the report. If the report body cannot be parsed, or does not conform to the format described in Section 3.1, or the report server does not expect to receive reports for the scheme, hostname, or port in the report, then the report server MUST respond with a 400 Bad Request status code. ๐Ÿ™…โ€โ™€๏ธ

As described in Section 3.2, future versions of this specification may define new report formats that are sent with a different top-level key. If the report server does not recognize the report format, the report server MUST respond with a 501 Not Implemented status code. ๐Ÿคทโ€โ™€๏ธ

If the report's "test-report" key is set to true, the server MAY discard the report without further processing, but MUST still return a 2xx (Successful) status code. If the "test-report" key is absent or set to false, the server SHOULD store the report for processing and analysis by the owner of the Expect-CT Host. ๐Ÿ—‚๏ธ


4. Usability Considerations ๐Ÿ’–

When the UA detects a Known Expect-CT Host that violates the UA's CT Policy, end users will experience denials of service. It is advisable for UAs to explain to users why they cannot access the Expect-CT Host, for example in a user interface that explains that the host's certificate cannot be validated. Nobody should be left staring at a blank screen wondering what happened ๐Ÿ˜ญ๐Ÿซถ

5. Authoring Considerations โœจ

okay so Expect-CT could have been a TLS extension or an X.509 certificate extension instead of an HTTP response header field ๐Ÿค” but using an HTTP header creates a layering mismatch ๐Ÿ˜ฌ. the software that terminates TLS and validates Certificate Transparency info might know absolutely nothing about HTTP ๐Ÿ’€. still, an HTTP header field was picked mainly for ease of deployment ๐Ÿš€. ngl, deploying new certificate extensions means certificate authorities have to support them, and new TLS extensions need server software updates, possibly even on servers the site owner doesn't directly control (hi, third-party Content Delivery Networks ๐Ÿ™ƒ). ease of deployment is a top priority here, bestie, because Expect-CT is meant to be a temporary transition mechanism for user agents moving over to universal Certificate Transparency requirements ๐Ÿ’–


6. Privacy Considerations ๐Ÿซฃ

okay this part is kind of spooky ๐Ÿ‘€ Expect-CT can be used to infer which Certificate Transparency Policy a UA is using, by trying to retrieve specially configured websites that pass one user agent's policies but not another's ๐Ÿ•ต๏ธโ€โ™€๏ธ. and this is true for UAs that enforce CT policies without Expect-CT too, so it's not just on Expect-CT ๐Ÿ™ˆ

reports sent to the report-uri could also tell a third party which web page is being accessed and by which IP address, if people use individual report-uri values for individually tracked pages ๐Ÿ˜ญ. this could leak even if client-side scripting were disabled ๐Ÿ’€

implementations store state about Known Expect-CT Hosts, which means they store which domains the UA has contacted ๐Ÿ“š. implementations may choose to not store this state, subject to local policy (for example, in the private browsing mode of a web browser) ๐Ÿซฅ

violation reports (see Section 3) contain information about the certificate chain that violated the CT Policy ๐Ÿ“„. in some cases, like an organization-wide compromise of the end-to-end security of TLS, this may include info about the interception tools and design used by the organization, which the org would probably rather keep hidden ๐Ÿคซ

because Expect-CT causes remotely detectable behavior, it's advisable that UAs offer a way for privacy-sensitive end users to clear currently noted Expect-CT Hosts, and to query the current state of Known Expect-CT Hosts ๐Ÿงนโœจ


7. Security Considerations ๐Ÿ”

this section is serious and I'm not gonna sugarcoat it ๐Ÿ˜ค

7.1. Hostile Header Attacks

okay, so when UAs support the Expect-CT header field, it becomes a potential vector for hostile header attacks against site owners ๐Ÿ˜ฑ. if a site owner uses a certificate from a certificate authority that does not embed SCTs and does not serve SCTs via the Online Certificate Status Protocol (OCSP) or a TLS extension, a malicious server operator or attacker could temporarily reconfigure the host so it complies with the UA's CT Policy, and add the Expect-CT header field in enforcing mode with a long max-age ๐ŸŽญ. implementing user agents would note this as an Expect-CT Host (see Section 2.3.2.1). after doing this, the configuration could be reverted to not comply with the CT Policy, which prompts failures ๐Ÿ’ฅ

note that this scenario would require the attacker to have substantial control over the infrastructure in question, being able to obtain different certificates, change server software, or act as a man in the middle in connections ๐Ÿฆนโ€โ™€๏ธ

site operators can mitigate this situation by one of the following:

  • reconfiguring their web server to transmit SCTs using the TLS extension defined in Section 6.5 of [RFC9162] ๐Ÿ› ๏ธ
  • obtaining a certificate from an alternative certificate authority that provides SCTs by one of the other methods ๐Ÿ“œ
  • waiting for the user agent's persisted notation of this as an Expect-CT Host to reach its max-age โณ

user agents may choose to implement mechanisms for users to cure this situation, as noted in Section 4 ๐Ÿฉน

7.2. Maximum max-age

there's a real security trade-off here, so pay attention ๐Ÿ‘€

low maximum values provide a narrow window of protection for users who visit the Known Expect-CT Host only infrequently ๐Ÿ˜•. high maximum values, on the other hand, might result in a denial of service to a UA in the event of a hostile header attack, or simply an error on the part of the site owner ๐Ÿ’€

there is probably no ideal maximum for the max-age directive ๐Ÿคทโ€โ™€๏ธ. since Expect-CT is primarily a policy-expansion and investigation technology rather than an end-user protection, a value on the order of 30 days (2,592,000 seconds) may be considered a balance between these competing security concerns โš–๏ธ๐Ÿ’…

7.3. Amplification Attacks

another kind of hostile header attack uses the report-uri mechanism on many hosts that aren't currently exposing SCTs, as a method to cause a denial of service to the host receiving the reports ๐ŸŒŠ. if some highly trafficked websites emitted a non-enforcing Expect-CT header field with a report-uri, implementing UAs' reports could flood the reporting host ๐Ÿ˜ญ

it is noted in Section 2.1.1 that UAs should limit the rate at which they emit reports, but an attacker may alter the Expect-CT header fields to induce UAs to submit different reports to different URIs, still causing the same effect ๐Ÿฆ‹


8. IANA Considerations ๐Ÿ“‹

8.1. Header Field Registry

okay so this document registers the Expect-CT header field in the "Hypertext Transfer Protocol (HTTP) Field Name Registry", located at <https://www.iana.org/assignments/http-fields> ๐Ÿ—‚๏ธ here's the registration, verbatim:

Header field name:  Expect-CT

Applicable protocol:  http

Status:  permanent

Author/Change controller:  IETF

Specification document(s):  This document

Related information:  (empty)

8.2. Media Types Registry

this document also registers the application/expect-ct-report+json media type (which uses the suffix established in [RFC6839]) for Expect-CT violation reports in the "Media Types" registry ๐Ÿ“จโœจ. here's the registration template, exactly as written:

Type name:  application

Subtype name:  expect-ct-report+json

Required parameters:  n/a

Optional parameters:  n/a

Encoding considerations:  binary

Security considerations:  See Section 7

Interoperability considerations:  n/a

Published specification:  This document

Applications that use this media type:  UAs that implement
   Certificate Transparency compliance checks and reporting

Additional information:

   Deprecated alias names for this type: n/a

   Magic number(s): n/a

   File extension(s): n/a

   Macintosh file type code(s): n/a

Person & email address to contact for further information:
   Emily Stark (estark@google.com)

Intended usage:  COMMON

Restrictions on usage:  none

Author:  Emily Stark (estark@google.com)

Change controller:  IETF

9. References ๐Ÿ“š

9.1. Normative References

these are the must-read refs, bestie ๐Ÿค“ every entry, in full:

[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>.

[RFC3339]  Klyne, G. and C. Newman, "Date and Time on the Internet:
           Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002,
           <https://www.rfc-editor.org/info/rfc3339>.

[RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
           Resource Identifier (URI): Generic Syntax", STD 66,
           RFC 3986, DOI 10.17487/RFC3986, January 2005,
           <https://www.rfc-editor.org/info/rfc3986>.

[RFC4648]  Josefsson, S., "The Base16, Base32, and Base64 Data
           Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
           <https://www.rfc-editor.org/info/rfc4648>.

[RFC5234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
           Specifications: ABNF", STD 68, RFC 5234,
           DOI 10.17487/RFC5234, January 2008,
           <https://www.rfc-editor.org/info/rfc5234>.

[RFC5280]  Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
           Housley, R., and W. Polk, "Internet X.509 Public Key
           Infrastructure Certificate and Certificate Revocation List
           (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,
           <https://www.rfc-editor.org/info/rfc5280>.

[RFC6797]  Hodges, J., Jackson, C., and A. Barth, "HTTP Strict
           Transport Security (HSTS)", RFC 6797,
           DOI 10.17487/RFC6797, November 2012,
           <https://www.rfc-editor.org/info/rfc6797>.

[RFC6839]  Hansen, T. and A. Melnikov, "Additional Media Type
           Structured Syntax Suffixes", RFC 6839,
           DOI 10.17487/RFC6839, January 2013,
           <https://www.rfc-editor.org/info/rfc6839>.

[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>.

[RFC7468]  Josefsson, S. and S. Leonard, "Textual Encodings of PKIX,
           PKCS, and CMS Structures", RFC 7468, DOI 10.17487/RFC7468,
           April 2015, <https://www.rfc-editor.org/info/rfc7468>.

[RFC7469]  Evans, C., Palmer, C., and R. Sleevi, "Public Key Pinning
           Extension for HTTP", RFC 7469, DOI 10.17487/RFC7469, April
           2015, <https://www.rfc-editor.org/info/rfc7469>.

[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>.

[RFC8259]  Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
           Interchange Format", STD 90, RFC 8259,
           DOI 10.17487/RFC8259, December 2017,
           <https://www.rfc-editor.org/info/rfc8259>.

[RFC9110]  Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
           Ed., "HTTP Semantics", STD 97, RFC 9110,
           DOI 10.17487/RFC9110, June 2022,
           <https://www.rfc-editor.org/info/rfc9110>.

[RFC9111]  Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
           Ed., "HTTP Caching", STD 98, RFC 9111,
           DOI 10.17487/RFC9111, June 2022,
           <https://www.rfc-editor.org/info/rfc9111>.

[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>.

9.2. Informative References

and these are the nice-to-know ones ๐ŸŒธ

[FETCH]    WHATWG, "Fetch - Living Standard",
           <https://fetch.spec.whatwg.org>.

[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>.

Author's Address ๐Ÿ’Œ

Emily Stark
Google
Email: estark@google.com
๐Ÿ“ฆ where this page comes from