Loading Signed Exchanges

Draft Community Group Report,

This version:
https://wicg.github.io/webpackage/loading.html
Issue Tracking:
GitHub
Inline In Spec
Editor:
(Google Inc.)

Abstract

How UAs load signed exchanges.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. Introduction

This section is non-normative.

The Signed Exchanges specification [draft-yasskin-http-origin-signed-responses] describes a way to provide one or more signatures for an HTTP exchange and to check whether any of those signatures is trusted as authoritative for a particular origin. This specification describes how web browsers load those exchanges. It is expressed as several monkeypatches to the [FETCH] specification which call algorithms defined here.

1.1. Overview

When fetching a resource (https://distributor.example.org/foo.sxg) with the application/signed-exchange MIME type, the UA parses it, checks its signatures, and then if all is well, redirects to its request URL (https://publisher.example.org/foo) with a "stashed" exchange attached to the request. The redirect applies all the usual processing, and then when it would normally check for an HTTP cache hit, it also checks whether the stashed request matches the redirected request and which of the stashed exchange or HTTP cache contents is newer. If the stashed exchange matches and is newer, the UA returns the stashed response.

A Service Worker for https://distributor.example.org/ gets to handle the original request. A Service Worker for https://publisher.example.org/ can then handle the redirect. If it needs to know that signed exchange content is available for the request it’s handling, it has two options:

  1. If navigationPreload is enabled, the signed response will be available in the FetchEvent's preloadResponse. Note that this will also cause a network request for requests that aren’t served from a signed exchange.

  2. clone() the request and set its cache to "only-if-cached", to retrieve the matching response from either the signed exchange or the HTTP cache. Note that fetch()ing a new Request with the same url will not retrieve the response from the signed exchange.

1.2. Other interesting details

2. Fetch monkeypatches

When fetching a signed exchange, the UA needs to look for a trusted and valid signature and then redirect to the contained resource. We don’t put the contained resource in the HTTP cache, so redirects get a new field to store it.

2.1. A request’s stashed exchange

A request has an associated stashed exchange, which is null or an exchange.

2.2. Request clone

Rewrite clone a request to run these steps:

  1. Let newRequest be a copy of request, except for its body and stashed exchange .
  2. If request’s body is non-null, set newRequest’s body to the result of cloning request’s body.
  3. If request’s stashed exchange is non-null, set newRequest’s stashed exchange to an exchange whose request URL is a copy of request’s stashed exchange's request URL and whose response is the clone of request’s stashed exchange's response.
  4. Return newRequest.

2.3. New response fields

A response has an associated came from a signed exchange boolean. Unless stated otherwise, it is false.

A response has an associated signed exchange outer header list (a header list). Unless stated otherwise it is empty.

A response has an associated header integrity value, either null or, for responses that came from a signed exchange, a byte sequence holding the SHA-256 hash that verified the response's header list. Unless stated otherwise, it is null.

Note: The header integrity value doesn’t change even if the publisher signs the content again or changes the signing key, but it does change if any of the headers or body change. (It catches changes to the body because a valid signed exchange’s headers have to include a Digest value that covers the body.)

2.4. Response date

A response response’s date is the result of:

  1. Let date be the result of extracting header list values given `Date` and response’s header list.

  2. If date is a failure, return the point in time of the beginning of the universe.

  3. Return the point in time represented by date, as interpreted for the Date header field.

2.5. Monkeypatch HTTP fetch

In HTTP fetch, before

  1. If actualResponse’s status is a redirect status, then: ...

add the following steps:

  1. If the signed exchange version of actualResponse is:

    undefined

    Do nothing.

    "b2" or "b3"
    1. Let report be the result of create a new signed exchange report with request and actualResponse.

    2. Let parsedExchange be the result of parsing a signed exchange of version b2 or b3, respectively, from actualResponse in the context of request’s client, reporting to report.

    3. If parsedExchange is not an exchange, run queue a signed exchange report report with parsedExchange as the result, and return a network error.

    4. In parallel, wait and queue a report for parsedExchange and report.

    5. Set actualResponse’s status to 303.

    6. Set actualResponse’s `Location` header to the ASCII encoding of the serialization of parsedExchange’s request URL.

    7. Set request’s stashed exchange to parsedExchange.

    Anything else
    1. Let fallbackUrlBytes be the result of extracting the fallback URL from actualResponse.

    2. If fallbackUrlBytes is a failure, return a network error.

    3. Set actualResponse’s status to 303.

    4. Set actualResponse’s `Location` header to fallbackUrlBytes.

    Note: The final [draft-yasskin-http-origin-signed-responses] will use a version of `1`, but this specification tracks what’s actually implemented in browsers, which still uses draft versions.

2.6. Monkeypatch HTTP-network-or-cache fetch

In HTTP-network-or-cache fetch, after

5.19. If httpRequest’s cache mode is neither "no-store" nor "reload", then: ...

add the following steps:

  1. If httpRequest’s stashed exchange isn’t null:

    1. Let stashedExchange be httpRequest’s stashed exchange.

    2. If

      then set response to httpRequest’s stashed exchange's response.

    3. If response is null and httpRequest’s initiator is "prefetch" or "preload", return a network error.

      Note: This ensures that prefetching a signed exchange from one origin won’t accidentally do a network request from another origin, which could compromise the user’s privacy.

Note: Applying the signed exchange’s response here has the effect of letting a newer HTTP cache entry override a signed exchange’s content, and of not storing the signed exchange’s response in the HTTP cache.

3. Subresource substitution

When prenavigating to a page held in a signed exchange, it can be useful to also prefetch subresources of that page as signed exchanges from the same server. To identify those transitive prefetchable resources, this section introduces an extension to the HTTP Link header.

3.1. New Document fields

At the end of the Document object section, add the following lines:

The Document has a map of prefetched signed exchanges for navigation, which is a map of URLs to exchanges, initially empty. This might merge with the set of prefetched resources when prefetch is specified more completely.

The Document has a set of prefetched subresource signed exchanges, which is a set of exchanges, initially empty.

3.2. New navigation params struct field

In the navigation params struct, add the following items:

prefetched subresource signed exchanges

A set of exchanges, empty unless specified otherwise.

Note: To prefetch the alternate signed exchanges when the UA receives a prefetched main resource signed exchange, this section monkeypatches Link type "prefetch". This algorithm gets all the alternate signed exchange links from the outer response, checks if they are allowed by the inner response’s allowed-alt-sxg links, and if they are, associates them with the inner response’s preload links.

Currently the behavior of recursive prefetch is not specified. This section monkeypatches Link type "prefetch" to add support only for the alternate signed exchanges subresources. When we change the HTML spec to support general recursive prefetching, this section needs to align with that change. <https://github.com/w3c/resource-hints/issues/77>

To process this type of linked resource ("prefetch"), given a link element el, boolean success, and response response:

  1. If success is true, fire an event named load at el.

  2. Otherwise, fire an event named error at el.

  3. If success is false, then return.

  4. If the response did not come from a signed exchange, then return.

  5. Let requestUrl be the first item of response’s URL list.

  6. Let clonedExchange be the result of creating a new exchange with requestUrl and the result of cloning response.

  7. Let prefetchedSignedExchanges be el’s node document's prefetched signed exchanges for navigation.

  8. Set prefetchedSignedExchanges[requestUrl] to clonedExchange.

  9. Let outerLinkHeader be the result of getting `Link` from response’s signed exchange outer header list.

  10. If outerLinkHeader is null, then return.

  11. Let outerLinks be the result of Parsing a Link Field Value from outerLinkHeader.

  12. If outerLinks is empty, then return.

  13. Let innerLinkHeader be the result of getting `Link` from response’s header list.

  14. If innerLinkHeader is null, then return.

  15. Let innerLinks be the result of Parsing a Link Field Value from innerLinkHeader.

  16. If innerLinks is empty, then return.

  17. Let alternateLinks be the result of getting alternate signed exchange link info from outerLinks.

  18. Let allowedSxgLinks be the result of getting allowed signed exchange link info from innerLink.

  19. For each innerLink of innerLinks:

    1. If innerLink’s Relation Type is not 'preload', then continue.

    2. Let linkTarget be innerLink’s Link Target.

    3. Let asAttribute be innerLink’s Target Attribute named "as".

    4. If asAttribute is not a potential destination, continue.

    5. If asAttribute is "image", then:

      1. Let imagesrcset be innerLink’s Target Attribute named "imagesrcset".

      2. Let imagesizes be innerLink’s Target Attribute named "imagesizes".

      3. Create a link element linkElement whose href attribute is linkTarget, and imagesrcset attribute is imagesrcset, and imagesizes attribute is imagesizes.

      4. Let selected source and selected pixel density be the URL and pixel density that results from selecting an image source given linkElement, respectively.

      5. If selected source is not null, then set linkTarget to the result of parsing selected source, with a base URL of response’s URL.

    6. For each allowedSxgLink of allowedSxgLinks:

      1. If allowedSxgLink’s target isn’t the same as linkTarget, then continue.

      2. Let storedExchange be the result of creating an exchange with linkTarget and a new response.

      3. If allowedSxgLink’s variants is not null, set `Variants`/allowedSxgLink’s variants in storedExchange’s response's header list.

      4. If allowedSxgLink’s variant key is not null, set `Variant-Key`/allowedSxgLink’s variant key in storedExchange’s response's header list.

      5. Let requestForMatch be the result of creating a potential-CORS request given a url of linkTarget, a destination of the result of translating asAttribute, and a corsAttributeState of No CORS.

      6. If requestForMatch doesn’t match the stored exchange storedExchange, then continue.

      7. Let alternateSxgUrl be the target of the first alternate signed exchange link info of alternateLinks whose

        or continue if no such link is present.

      8. Let sxgRequest be the result of creating a potential-CORS request given a url of alternateSxgUrl, a destination of the result of translating asAttribute, and a corsAttributeState of No CORS.

      9. Run the following steps in parallel:

        1. Let sxgResponse be the result of fetching sxgRequest.

        2. If sxgResponse’s came from a signed exchange is true, and sxgResponse’s URL is the same as linkTarget, then queue a task on the networking task source to:

          1. Let sxgExchange be a new exchange with a request URL of linkTarget and a response of sxgResponse.

          2. Append sxgExchange to el’s node document's prefetched subresource signed exchanges.

3.4. Monkeypatch process a navigate fetch

In process a navigate fetch before

  1. Let reservedEnvironment be null.

add the following steps:

  1. If sourceBrowsingContext’s active document's prefetched signed exchanges for navigation contains an entry for a key of request’s url, then:

    1. Let prefetchedExchange be sourceBrowsingContext’s active document's prefetched signed exchanges for navigation[request’s url].

    2. Set request’s stashed exchange to the result of creating a new exchange with prefetchedExchange’s request URL and the result of cloning prefetchedExchange’s response.

And in

  1. Let navigationParams be a new navigation params whose ...

add:

  1. ... prefetched subresource signed exchanges is sourceBrowsingContext’s active document's prefetched subresource signed exchanges, ...

Note: As browsers move toward partitioned HTTP caches, the source document’s cache will likely be separate from the target’s cache, so we can’t just pass prefetched content through the cache.

3.5. Monkeypatch Page load processing model for HTML files

Note: To use the prefetched subresource signed exchanges after the navigation, this section monkeypatches Page load processing model for HTML files. This gets all the allowed-alt-sxg links from the inner response that are also preloaded and uses the prefetched subresource signed exchanges if all of those links were prefetched.

Currently the processing model of the HTTP Link header is not defined in the HTML spec. This section monkeypatches only for Link rel=preload HTTP headers. When we will change the HTML spec to generally support Link HTTP headers, this section must be made to align with the change. <https://github.com/whatwg/html/issues/4224>

In Page load processing model for HTML files before

  1. Create an HTML parser and ...

add the following steps:

  1. Run the following steps in parallel:

    1. Wait until document’s viewport is known.

      Note: When the document’s viewport is known is not normatively defined in the HTML spec. Need to define the behavior of the preload scanner to define this.

    2. Let linkHeader be the result of getting `Link` from navigationParams’s response's header list.

    3. If linkHeader is null, then return.

    4. Let links be the result of Parsing a Link Field Value from linkHeader.

    5. Let allowedSxgLinks be the result of getting allowed signed exchange link info from links.

    6. Let preloadLinkItems be an empty list.

    7. Let canLoadAlternateSxg be true.

    8. For each link of links:

      1. If link’s Relation Type is not 'preload', then continue.

      2. Let linkTarget be link’s Link Target.

      3. Let asAttribute be link’s Target Attribute named "as".

      4. If asAttribute is not a potential destination, continue.

      5. If asAttribute is "image", then:

        1. Let imagesrcset be link’s Target Attribute named "imagesrcset".

        2. Let imagesizes be link’s Target Attribute named "imagesizes".

        3. Create a link element linkElement whose href attribute is linkTarget, and imagesrcset attribute is imagesrcset, and imagesizes attribute is imagesizes.

        4. Let selected source and selected pixel density be the URL and pixel density that results from selecting an image source given linkElement, respectively.

        5. If selected source is not null, then set linkTarget to the result of parsing selected source, with a base URL of navigationParams’s response's URL.

      6. Let headerIntegrity be null.

      7. For each allowedSxgLink of allowedSxgLinks:

        1. Let storedExchange be the result of creating an exchange with the URL of allowedSxgLink’s target and a new response.

        2. If allowedSxgLink’s variants is null, set `Variants`/allowedSxgLink’s variants in storedExchange’s response's header list.

        3. If allowedSxgLink’s variant key is not null, set `Variant-Key`/allowedSxgLink’s variant key in storedExchange’s response's header list.

        4. Let requestForMatch be the result of creating a potential-CORS request given a url of allowedSxgLink’s target, a destination of the result of translating asAttribute, and a corsAttributeState of No CORS.

        5. If requestForMatch matches the stored exchange storedExchange, then:

          1. Set headerIntegrity to allowedSxgLink’s header integrity.

          2. Break out of the allowedSxgLinks loop.

      8. Let prefetched alternate exchange be null.

      9. For each sxg of navigationParams’s prefetched subresource signed exchanges:

        1. If headerIntegrity is the same as the value of sxg’s response's header integrity value encoded as a [CSP] hash-source, then set prefetched alternate exchange to sxg.

      10. If headerIntegrity is not null and prefetched alternate exchange is null, then set canLoadAlternateSxg to false.

        Note: This means that there is a matching allowed-alt-sxg link for the preload link, but the matching signed exchange has not been prefetched. In this case the UA can’t use the prefetched subresource signed exchanges for other preload links. This is intended to prevent the referrer page from encoding a tracking ID into the set of subresources it prefetches.

      11. Append the alternate signed exchange preload info (link, linkTarget, prefetched alternate exchange) to preloadLinkItems.

    9. For each preloadLinkItem of preloadLinkItems:

      1. Let asAttribute be preloadLinkItem’s link's Target Attribute named "as".

      2. Assert: asAttribute is a potential destination.

      3. Let corsAttributeState be the state of a synthetic CORS settings attribute with a value of preloadLinkItem’s link's Target Attribute named "crossorigin".

      4. Let request be the result of creating a potential-CORS request given a url of preloadLinkItem’s target, a destination of the result of translating asAttribute, and a corsAttributeState of corsAttributeState.

      5. Set request’s synchronous flag.

      6. Set request’s client to document.

      7. Set request’s cryptographic nonce metadata to preloadLinkItem’s link's Target Attribute named "nonce".

      8. Set request’s integrity metadata to preloadLinkItem’s link's Target Attribute named "integrity".

      9. Set request’s referrer policy to be the referrer policy attribute of preloadLinkItem’s link's Target Attribute named "referrerpolicy".

      10. If canLoadAlternateSxg is true, then set request’s stashed exchange to preloadLinkItem’s prefetched alternate exchange.

        Note: When canLoadAlternateSxg if false or there is no matching prefetched alternate exchange, the original resource declared in the preload Link header link will be fetched.

      11. Fetch request in parallel.

4. Structures

4.1. Exchange

An exchange is a struct with the following items:

4.2. Read buffer

A read buffer is a struct with the following items:

4.3. Augmented Certificate

An augmented certificate is a tuple with the following items:

  1. certificate, a byte sequence that’s expected to hold a DER-encoded X.509v3 certificate ([RFC5280]).

  2. OCSP response, a byte sequence that’s expected to hold a DER-encoded OCSPResponse for the certificate.

  3. SCT, a byte sequence that’s expected to hold a SignedCertificateTimestampList for the certificate.

These fields are byte sequences instead of parsed and validated structures because we expect some UAs to pass them to other systems for validation, and some of those systems expect plain byte sequences.

A certificate contains a public key (Subject Public Key Info), which has an algorithm (AlgorithmIdentifier).

A certificate contains an extensions map (Certificate Extensions) from OIDs to byte sequences.

A certificate chain is a list of augmented certificates, of which the first item is the leaf.

4.4. Signed Exchange report

A signed exchange report is a struct with the following items:

result

The result string of loading signed exchange. This must be unset or one of "ok", "mi_error", "non_secure_distributor", "parse_error", "invalid_integrity_header", "signature_verification_error", "cert_verification_error", "cert_fetch_error", "cert_parse_error",

outer request

The request which the user agent sent to the server to load the signed exchange.

outer response

The response which the user agent received from the server.

inner URL

The logical URL of the signed exchange, if available. Otherwise, an empty string.

cert URL list

The list of URLs in "cert-url" parameters for the signed exchange’s signatures, if available. Otherwise, an empty list.

server IP

The IP address of the server from which the user agent received the signed exchange, if available. Otherwise, an empty string.

cert server IP list

The list of IP addresses of the servers from which the user agent received the certificates listed in cert URL list.

4.5. Exchange Signature

An exchange signature is a struct with the following items:

signature

A byte sequence holding a signature of the exchange.

certificate chain

A certificate chain whose leaf's public key can verify the signature and from which the UA will try to build a path from the leaf to a trusted root.

certSha256

A byte sequence holding the SHA-256 hash that verified the certificate chain's leaf.

integrity header

A list of ASCII strings that describes the response header and any of its parameters that guard the integrity of the response payload.

validityUrl

A URL describing where to update this signature.

validityUrlBytes

The bytes that validityUrl was parsed from.

date

The POSIX time at which the signature starts being valid.

expiration time

The POSIX time at which the signature stops being valid.

An allowed signed exchange link info is a struct with the following items, holding a parsed allowed-alt-sxg link:

target

A URL holding the value of the link’s Link Target.

header integrity

A string holding the value of the link’s Target Attribute named "header-integrity".

variants

A string holding the value of the link’s Target Attribute named "variants", or null.

variant key

A string holding the value of the link’s Target Attribute named "variant key", or null.

An alternate signed exchange link info is a struct with the following items, holding a parsed alternate link:

target

A URL holding the value of the link’s Link Target.

context

A URL holding the value of the link’s Link Context.

variants

A string holding the value of the link’s Target Attribute named "variants", or null.

variant key

A string holding the value of the link’s Target Attribute named "variant key", or null.

4.8. Alternate signed exchange preload info

An alternate signed exchange preload info is a struct with the following items:

link

A link object parsed from a HTTP Link header.

target

A URL to be preloaded. This can be different from link's Link Target, when "imagesrcset" is used for image preload.

prefetched alternate exchange

The exchange of the prefetched alternate signed exchange, or null.

5. Algorithms

5.1. Identifying signed exchanges

The signed exchange version of a response response is the result of the following steps:

  1. If determine nosniff on response’s header list returns false, return undefined.

    Note: This requires servers to include the X-Content-Type-Options: nosniff header when they serve signed exchanges, which prevents some clients that don’t understand signed exchanges from interpreting one as another content type.

  2. Let mimeType be the result of extracting a MIME type from response’s header list.

  3. If mimeType is a failure, return undefined.

  4. If mimeType’s essence is not "application/signed-exchange", return undefined.

  5. Let params be mimeType’s parameters

  6. If params["v"] exists, return it. Otherwise, return undefined.

5.2. Extracting the fallback URL

This section defines how to load a the fallback URL from its invariant location in an unrecognized signed exchange version.

Extracting the fallback URL from a response response returns the result of the following steps:

  1. Assert: This algorithm is running in parallel.

  2. Assert: The signed exchange version of response is not undefined.

  3. Let bodyStream be response’s body's stream.

  4. If bodyStream is null, return failure.

  5. Let stream be a new read buffer for bodyStream.

  6. Let (magic, fallbackUrlBytes, fallbackUrl) be the result of parsing the invariant prefix from stream. If returns a failure, return that failure.

  7. Return fallbackUrlBytes.

5.3. Parsing signed exchanges

This section defines how to load the formats defined in [draft-yasskin-httpbis-origin-signed-exchanges-impl-02] and [draft-yasskin-httpbis-origin-signed-exchanges-impl-03].

Parsing a signed exchange of version version from a response response in the context of an environment settings object client, reporting to a signed exchange report report, returns an exchange or a string which indicates a result as described by the following steps

  1. Assert: This algorithm is running in parallel.

  2. Assert: The signed exchange version of response is, if version is

    b2

    "b2"

    b3

    "b3"

  3. If response’s URL's origin is not a potentially trustworthy origin, return "non_secure_distributor".

    Note: This ensures that the privacy properties of retrieving an HTTPS resource via a signed exchange are no worse than retrieving it via TLS.

  4. Let bodyStream be response’s body's stream.

  5. If bodyStream is null, return "parse_error".

  6. Let stream be a new read buffer for bodyStream.

  7. Let (magic, requestUrlBytes, requestUrl) be the result of parsing the invariant prefix from stream. If returns a failure, return "parse_error".

  8. Set report’s inner URL to requestUrl.

  9. If magic is not the following value, depending on version, return "parse_error":

    b2

    `sxg1-b2\0`

    b3

    `sxg1-b3\0`

  10. Assert: requestUrlBytes should match the result of extracting the fallback URL from response.

  11. Let encodedSigLength be the result of reading 3 bytes from stream.

  12. Let encodedHeaderLength be the result of reading 3 bytes from stream.

  13. If encodedSigLength or encodedHeaderLength is a failure, return "parse_error".

  14. Let sigLength be the result of decoding encodedSigLength as a big-endian integer.

  15. Let headerLength be the result of decoding encodedHeaderLength as a big-endian integer.

  16. If sigLength > 16384 or headerLength > 524288, return "parse_error".

  17. Let signature be the result of reading sigLength bytes from stream.

  18. If signature is a failure, return "parse_error".

  19. Let parsedSignature be the result of parsing the Signature header field signature in the context of client reporting to with report.

  20. If parsedSignature is not an exchange signature, return it.

  21. Let headerBytes be the result of reading headerLength bytes from stream.

  22. If headerBytes is a failure, return "parse_error".

  23. If parsedSignature is not valid for headerBytes and requestUrlBytes, and signed exchange version version, return "signature_verification_error".

  24. Let parsedExchange be, if version is:

    b2

    the result of parsing b2 CBOR headers given headerBytes and requestUrl.

    b3

    the result of parsing b3 CBOR headers given headerBytes and requestUrl.

  25. Set parsedExchange’s response's came from a signed exchange to true.

  26. Set parsedExchange’s response's signed exchange outer header list to response’s header list.

  27. Set parsedExchange’s response's header integrity value to the SHA-256 hash of headerBytes.

  28. If parsedSignature does not establish cross-origin trust for parsedExchange, return "cert_verification_error".

  29. If parsedExchange’s response's status is a redirect status or the signed exchange version of parsedExchange’s response is not undefined, return "parse_error".

    Note: This might simplify the UA’s implementation, since it doesn’t have to handle nested signed exchanges.

  30. Read a body from stream into parsedExchange’s response using parsedSignature to check its integrity. If this returns an error string, return it.

    Note: Typically this body’s stream is still being enqueued to after returning.

  31. Return parsedExchange.

5.4. Parsing the invariant prefix

All signed exchange versions start with the same initial bytes, parsed by this section.

Parsing the invariant prefix from a read buffer stream returns a failure or the triple of a byte sequence magic, byte sequence fallbackUrlBytes, and URL fallbackUrl, as described by the following steps:

  1. Assert: This algorithm is running in parallel.

  2. Let magic be the result of reading 8 bytes from stream.

  3. If magic is a failure, return it.

  4. Let encodedFallbackUrlLength be the result of reading 2 bytes from stream.

  5. If encodedFallbackUrlLength is a failure, return it.

  6. Let fallbackUrlLength be the result of decoding encodedFallbackUrlLength as a big-endian integer.

  7. Let fallbackUrlBytes be the result of reading fallbackUrlLength bytes from stream.

  8. If fallbackUrlBytes is a failure, return it.

  9. Let fallbackUrlString be the result of UTF-8 decode without BOM or fail on fallbackUrlBytes.

  10. If fallbackUrlString is a failure, return it.

  11. Let fallbackUrl be the result of running the URL parser on fallbackUrlString.

  12. If fallbackUrl is a failure, if it has a non-null fragment, or if its scheme is something other than "https", return a failure.

  13. Return (magic, fallbackUrlBytes, fallbackUrl).

5.5. Parsing a Signature Header Field

Parsing the Signature header field signatureString in the context of an environment settings object client, reporting to a signed exchange report report, returns an exchange signature or a string which indicates a result, as described by the following steps:

  1. Assert: This algorithm is running in parallel.

  2. If signatureString contains any bytes that aren’t ASCII bytes, return "parse_error".

  3. Let parsed be the result of Parsing HTTP1 Header Fields into Structured Headers given an input_string of the ASCII decoding of signatureString and a header_type of "param-list".

  4. If parsed has more than one element, "parse_error".

    Note: This limitation of current implementations will go away in the future.

  5. If any of the parameters of parsed[0] listed here doesn’t have the associated type, "parse_error".

    Byte sequence

    "sig", "cert-sha256"

    String

    "integrity", "cert-url", "validity-url"

    Integer

    "date", "expires"

  6. Let result be a new exchange signature struct.

  7. Set result’s signature to the "sig" parameter of parsed[0].

  8. Set result’s integrity header to the result of strictly splitting the "integrity" parameter of parsed[0] on U+002F (/).

  9. Let certUrl be the result of running the URL parser on the "cert-url" parameter of parsed[0].

  10. Append certUrl to report’s cert URL list.

  11. If certUrl is a failure, if it has a non-null fragment, or if its scheme is something other than "https" or "data", return "parse_error".

  12. Set result’s certSha256 to the "cert-sha256" parameter of parsed[0].

  13. Set result’s validityUrlBytes to the ASCII encoding of the "validity-url" parameter of parsed[0].

  14. Let validityUrl be the result of running the URL parser on the "validity-url" parameter of parsed[0]..

  15. If validityUrl is a failure, if it has a non-null fragment, or if its scheme is something other than "https", return "parse_error".

  16. Set result’s validityUrl to validityUrl.

  17. Set result’s date to the "date" parameter of parsed[0].

  18. Set result’s expiration time to the "expires" parameter of parsed[0].

  19. If result’s expiration time or result’s date is less than 0 or greater than 263-1, return "parse_error".

  20. If result’s expiration time <= result’s date, return "parse_error".

  21. Set result’s certificate chain to the result of handling the certificate reference certUrl with a hash of result’s certSha256 and report in the context of client. If this is not a certificate chain, return it.

  22. Return result.

5.5.1. Handling the certificate reference

Handling the certificate reference certUrl with the SHA-256 hash certSha256 in the context of an environment settings object client, reporting to a signed exchange report report, returns a certificate chain or a string which indicates a result, as described by the following steps:

  1. Assert: This algorithm is running in parallel.

  2. Let certRequest be a new request with the following items:

    url

    certUrl

    header list

    «`Accept`: `application/cert-chain+cbor`»

    client

    client

    service-workers mode

    "none"

    mode

    "cors"

  3. Let certResponse be the result of fetching certRequest.

  4. Append the IP address of the server from which the user agent received the certResponse to report’s cert server IP list, if available.

  5. If certResponse’s status is not 200, return "cert_fetch_error".

  6. Let certMimeType be the result of extracting a MIME type from certResponse’s header list.

  7. If certMimeType is a failure or its essence is not "application/cert-chain+cbor", return "cert_fetch_error".

  8. If certResponse’s body is null or that body’s stream is null, return "cert_parse_error".

  9. Let reader be the result of getting a reader for certResponse’s body's stream.

  10. Assert: Getting a reader did not throw an exception, because the response was created in this algorithm and not passed anywhere that could create a reader for its body.

  11. Let bytes be the result of reading all bytes from reader.

  12. Wait for bytes to settle.

  13. If bytes was rejected, return "cert_parse_error".

  14. Let chain be the certificate chain produced by parsing bytes’ value using the cert-chain CDDL. If bytes’s value doesn’t match this CDDL or isn’t canonically-encoded CBOR, return "cert_parse_error".

  15. Assert: chain has at least one item.

  16. If the SHA-256 hash of chain’s leaf's certificate is not equal to certSha256, return "signature_verification_error".

  17. Return chain.

5.6. The signed message

The signed message for a version version, an exchange signature signature and byte sequences requestUrlBytes and headerBytes is the concatenation of the following byte sequences:

  1. The byte 0x20 (SP) repeated 64 times. This matches the TLS 1.3 ([RFC8446]) format to avoid cross- protocol attacks if anyone uses the same key in a TLS certificate and an exchange-signing certificate.

  2. A context string consisting of, if version is:

    b2

    `HTTP Exchange 1 b2`

    b3

    `HTTP Exchange 1 b3`

    Note: Each draft of [draft-yasskin-httpbis-origin-signed-exchanges-impl-02] and the final RFC for [draft-yasskin-http-origin-signed-responses] will use distinct context strings.

  3. A single 0x00 byte which serves as a separator.

  4. A single 0x20 (SP) byte, representing the length of the next field.

  5. signature’s certSha256.

  6. The 8-byte big-endian encoding of the length in bytes of signature’s validityUrlBytes.

  7. signature’s validityUrlBytes.

  8. The 8-byte big-endian encoding of signature’s date.

  9. The 8-byte big-endian encoding of signature’s expiration time.

  10. The 8-byte big-endian encoding of the length in bytes of requestUrlBytes.

  11. requestUrlBytes.

  12. The 8-byte big-endian encoding of the length in bytes of headerBytes.

  13. headerBytes.

5.7. Validating a signature

An exchange signature signature is valid for byte sequences requestUrlBytes and headerBytes, and signed exchange version version, if the following steps return valid:

  1. Let clockSkew be the uncertainty in the UA’s estimate of the current time caused by clock skew on the client. The UA MAY set this to 0 or use a more sophisticated estimate.

  2. If the UA’s estimate of the current time is more than clockSkew before signature’s date, return "untrusted".

    Note: We take estimated clock skew into account when checking the signature’s date because we want well-behaved servers to use the time they created the signature, but if they immediately start serving that signature, and skewed clients don’t try to correct for their skew, those clients will reject the signature.

    Our security reviewers aren’t sure we should allow UAs to take clock skew into account. <https://github.com/WICG/webpackage/issues/141>

  3. If the UA’s estimate of the current time is after signature’s expiration time, return "untrusted".

    Note: We use the client’s best guess of the current time to check the expiration time so that attackers trying to get an exchange trusted for longer, are constrained to modify the client’s clock and can’t also attack its estimate of its skew.

  4. Let message be the signed message for version, signature, requestUrlBytes, and headerBytes.

  5. Let publicKey be the public key of parsedSignature’s certificate chain's leaf. If the certificate can’t be parsed enough to find this public key, return invalid.

  6. If publicKey’s algorithm is not id-ecPublicKey on the secp256r1 named curve, return invalid.

  7. If parsedSignature’s signature is not a valid signature of message by publicKey using the ecdsa_secp256r1_sha256 algorithm, return invalid.

  8. Return valid.

5.8. Cross-origin trust

A valid exchange signature signature establishes cross-origin trust in an exchange exchange if the following steps return "trusted":

  1. Let requestUrl be exchange’s request URL.

  2. If signature’s validityUrl's origin is not same origin with requestUrl’s origin, return "untrusted".

  3. If exchange’s response's header list includes an uncached response header, return "untrusted".

  4. If signature’s expiration time is more than 604800 seconds (7 days) after signature’s date, return "untrusted".

  5. If signature’s certificate chain does not have a trusted leaf for requestUrl’s origin, return "untrusted".

  6. Return "trusted".

5.9. Establishing trust in a certificate

The certificate chain chain has a trusted leaf for an origin origin if the following steps return trusted:

  1. Let leaf be chain’s leaf.

  2. Attempt to build a trustworthy path from leaf’s certificate to a trusted root with

    as input, using [RFC5280] and any other conventions used in making TLS ([RFC8446]) connections. The UA SHOULD support Certificate Transparency ([RFC6962]) for this check. (See § 6.1 Certificate Transparency.) The UA MUST check that it has evidence the leaf’s certificate was not revoked 7 or more days ago (for example using the leaf’s OCSP response). If no such path can be built, return untrusted.

  3. If leaf’s certificate is not trusted for origin’s host, return untrusted.

  4. If leaf’s extensions don’t map a CanSignHttpExchanges OID to the ASN.1/DER encoding of NULL (0x05 0x00), return untrusted.

  5. Return trusted.

5.10. Parsing b2 CBOR headers

Parsing b2 CBOR headers from a byte sequence headerBytes and a URL requestUrl returns a failure or an exchange via the following steps:

  1. Let headers be the result of parsing a CBOR item from headerBytes, matching the following CDDL rule:

        headers = [
          {
            ':method': bstr,
            * bstr => bstr,
          },
          {
            ':status': bstr,
            * bstr => bstr,
          }
        ]
    
  2. If any of the following is true, return a failure:

    • headers is an error.

    • headers[0] contains any key starting with `:` that isn’t `:method`.

    • headers[0] contains a `host` key.

    • headers[0][`:method`] is not `GET`.

    • headers[1] contains any key starting with `:` that isn’t `:status`.

    • headers[1][`:status`] is not 200.

  3. Let requestHeaders be the result of creating a header list from the CBOR map headers[0].

  4. If requestHeaders is a failure, return it.

  5. Let responseHeaders be the result of creating a header list from the CBOR map headers[1].

  6. If responseHeaders is a failure, return it.

  7. If responseHeaders does not contain `Content-Type`, return a failure.

  8. Set `X-Content-Type-Options`/`nosniff` in responseHeaders.

  9. Let response be a new response with status headers[1][`:status`] and header list responseHeaders.

  10. Return an exchange of requestUrl and response.

    Note: This ignores requestHeaders, which can’t be encoded in b3 and later.

5.11. Parsing b3 CBOR headers

Parsing b3 CBOR headers from a byte sequence headerBytes and a URL requestUrl returns a failure or an exchange via the following steps:

  1. Let headers be the result of parsing a CBOR item from headerBytes, matching the following CDDL rule:

        headers = {
          ':status': bstr,
          * bstr => bstr,
        }
    
  2. If any of the following is true, return a failure:

    • headers is an error.

    • headers contains any key starting with `:` that isn’t `:status`.

    • headers[`:status`] is not 200.

  3. Let responseHeaders be the result of creating a header list from the CBOR map headers.

  4. If responseHeaders is a failure, return it.

  5. Let response be a new response with status headers[`:status`] and header list responseHeaders.

  6. Return an exchange of requestUrl and response.

5.11.1. Converting a map to a header list

The result of creating a header list from the CBOR map map is returned by the following steps:

  1. Let headers be a new empty header list.

  2. For each keyvalue of map:

    1. If key starts with `:`, continue.

    2. If the isomorphic decoding of key contains any ASCII upper alpha, return a failure.

    3. If key doesn’t match the constraints on a name or value doesn’t match the constraints on a value, return a failure.

    4. Assert: headers does not contain key.

    5. Append key/value to headers.

  3. Return headers.

5.12. Creating the response stream.

To read a body from a read buffer stream into a response response using an exchange signature signature to check its integrity, the UA MUST:

  1. If signature’s integrity header is:

    «"digest", "mi-sha256-03
    1. Let instance-digests be the result of getting, decoding, and splitting `digest` from response’s header list.

      Note: No Digest algorithm uses non-ASCII characters or 0x22 ("), so this is equivalent to parsing from the Digest ABNF <encoded digest output>.

    2. Let mi be the element of instance-digests that starts with "mi-sha256-03=". If there is no such element, return an error string "invalid_integrity_header".

    3. Let codings be the result of getting, decoding, and splitting `content-encoding` in response’s header list.

    4. If codings doesn’t include "mi-sha256-03", return an error string "invalid_integrity_header".

    5. Assert: Handle content codings used the value of mi as the integrity proof for the first record when decoding the mi-sha256-03 content encoding to produce the bytes in stream.

    Anything else

    Return an error string "invalid_integrity_header".

  2. Let body be a new body.

  3. Let cancel be the following steps, taking reason as an argument:

    1. Cancel stream’s stream with reason.

  4. Let outputStream be the result of creating a ReadableStream with a cancelAlgorithm of cancel.

  5. Set body’s stream to outputStream.

  6. Set response’s body to body.

  7. In parallel:

    1. Dump stream to outputStream.

5.13. Request matching

A request browserRequest matches the stored exchange storedExchange if the following steps return "match":

  1. If browserRequest’s method is not `GET` or `HEAD`, return "mismatch".

    Note: The browserRequest’s method can be something other than `GET` if a Service Worker intercepts the redirect and modifies the request before re-fetching it.

  2. If browserRequest’s url is not equal to storedExchange’s request URL, return "mismatch".

  3. If storedExchange’s response's header list contains:

    Neither a `Variants` nor a `Variant-Key` header

    Return "match".

    Note: This states that exactly one resource lives at the request URL, and no content negotiation is intended.

    A `Variant-Key` header but no `Variants` header

    Return "mismatch".

    Note: This indicates a likely misconfiguration, and returning "mismatch" makes that fail fast.

    A `Variants` header but no `Variant-Key` header

    Return "mismatch".

    Note: This behavior is implied by the below steps, but we make it explicit here.

    Both a `Variants` and a `Variant-Key` header

    Proceed to the following steps.

  4. If getting `Variants` from storedExchange’s response's header list returns a value that fails to parse according to the instructions for the Variants Header Field, return "mismatch".

  5. Let acceptableVariantKeys be the result of running the Variants Cache Behavior on an incoming-request of browserRequest and stored-responses of a list containing storedExchange’s response.

  6. Let variantKeys be the result of getting `Variant-Key` from storedExchange’s response's header list, and parsing it into a list of lists as described in the Variant-Key Header Field.

  7. If parsing variantKeys failed, return "mismatch".

  8. If the intersection of acceptableVariantKeys and variantKeys is empty, return "mismatch".

    This depends on the Variants Cache Behavior returning a list of lists. <https://github.com/httpwg/http-extensions/issues/744>

  9. Return "match".

5.14. Create a new signed exchange report

To create a new signed exchange report with request and actualResponse, the UA MUST:
  1. Let report be a new signed exchange report struct.

  2. Set report’s outer request to request.

  3. Set report’s outer response to actualResponse.

  4. Set report’s server IP to the IP address of the server from which the user agent received the actualResponse, if available.

  5. Return report.

5.15. Wait and queue a report

To wait and queue a report for parsedExchange and report, the UA MUST:
  1. Wait until parsedExchange’s body's stream is closed or errored.

  2. If parsedExchange’s body's stream is closed, run queue a signed exchange report report with "ok" as the result and abort these steps.

  3. If parsedExchange’s body's stream is errored, run queue a signed exchange report report with "mi_error" as the result.

5.16. Queuing signed exchange report

To queue a signed exchange report report with result as the result, the UA MUST:

  1. Set report’s result to result.

  2. Let report body and policy be the result of generate a network error report with report’s outer request. If the result is null, abort these steps.

  3. If report body’s "type" is "dns.address_changed", abort these steps.

    Note: This means that the NEL report was downgraded because the IP addresses of the server and the policy don’t match. In this case, the UA has called deliver a network report algorithm with the error report while handling the response. So we don’t need to send the same error report while processing the response as a signed exchange.

  4. Add a new property "sxg" to report body with a new ECMAScript object with the following properties:

  5. Set report body’s "phase" to "sxg".

  6. If the report’s result is "ok", set report body’s "type" to "ok". Otherwise, set report body’s "type" to the result of concatenating a string "sxg." and the report’s result.

  7. If report body’s "sxg"'s "cert_url"'s scheme is not "data" and report’s result is "signature_verification_error" or "cert_verification_error" or "cert_fetch_error" or "cert_parse_error":

    1. If report’s outer request's url's origin is different from any origin of the URLs in report’s cert URL list, or report’s server IP is different from any of the IP address in report’s cert server IP list:

      1. Set report body’s "type" to "sxg.failed".

      2. Set report body’s "elapsed_time" to 0.

    Note: This step "downgrades" a Signed Exchange report if the certificate was served from the different server from the server of "outer_url". This is intended to avoid leaking the information about the certificate server.

  8. Deliver a network report with report body and policy and report’s outer request.

    If a NEL policy was received from the distributor’s origin, distributor.example, this step will send the following JSON data to describe an invalid signature:
    {
      "type": "network-error",
      "url": "https://publisher.example/article.html",
      "age": 234,
      "user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) ...",
      "body": {
        "referrer": "https://aggregator.example/article.html",
        "sampling_fraction": 1,
        "server_ip": "192.0.2.42",  // The IP address of distributor.example.
        "protocol": "http/1.1",
        "method": "GET",
        "status_code": 200,
        "elapsed_time": 1234,
        "phase": "sxg",
        "type": "sxg.signature_verification_error",
        "sxg": {
          "outer_url": "https://distributor.example/publisher.example/article.html.sxg",
          "inner_url": "https://publisher.example/article.html",
          "cert_url": ["https://distributor.example/publisher.example/cert"]
        },
      }
    }
    

5.17. Stream algorithms

The algorithms in this section create and operate over ECMAScript objects like ReadableStream despite not having a Realm to attach them to. <https://github.com/whatwg/fetch/issues/730>

5.17.1. Create a read buffer

A new read buffer for a ReadableStream stream is a new read buffer struct whose items are:

stream

stream

reader

The result of getting a reader from stream.

bytes

An empty byte sequence.

5.17.2. Read up to bytes

To read up to N bytes from a read buffer buffer, the UA MUST:

  1. Assert: This algorithm is running in parallel.

  2. Let done be false.

  3. While done is false and the length of buffer’s bytes item is less than N bytes:

    1. Let chunk be the result of reading a chunk from buffer’s reader.

    2. Wait for chunk to settle.

    3. If chunk is :

      Fulfilled with an object whose done property is false and whose value property is a Uint8Array object:
      1. Let bs be the byte sequence represented by the Uint8Array object.

      2. Set buffer to the concatenation of buffer and bs.

      Fulfilled with an object whose done property is true:

      Set done to true.

      Rejected with e:

      Return a failure with reason e.

  4. If buffer’s bytes item is at least N bytes long:

    1. Let result be a byte sequence consisting of the first N bytes of buffer’s bytes item.

    2. Set buffer’s bytes item to a byte sequence consisting of the bytes after the Nth from its old value.

  5. Otherwise:

    1. Let result be buffer’s bytes item.

    2. Set buffer’s bytes item to an empty byte sequence.

  6. Return result.

5.17.3. Read bytes

To read N bytes from a read buffer buffer, the UA MUST:

  1. Assert: This algorithm is running in parallel.

  2. Let bytes be the result of reading up to N bytes from buffer.

  3. If bytes is a failure, return it.

  4. If bytes is exactly N bytes long, return it.

  5. Otherwise, return a failure.

5.17.4. Dump to another stream

To Dump a read buffer input to a ReadableStream output, the UA MUST:

  1. Assert: This algorithm is running in parallel.

  2. Enqueue a Uint8Array wrapping an ArrayBuffer containing input’s bytes into output.

  3. While input’s stream is readable:

    1. Wait until output is closed, errored, or needs more data.

    2. If output is closed or errored, cancel input’s stream and abort these steps.

    3. Let chunk be the result of reading a chunk with input’s reader.

    4. Wait for chunk to settle.

    5. If chunk is:

      Fulfilled with an object whose done property is false and whose value property is a Uint8Array object bytes:

      Enqueue a Uint8Array wrapping an ArrayBuffer containing bytes into output.

      Fulfilled with an object whose done property is true:

      Close output.

      Rejected with e:

      Error output with reason e.

5.18. Get value of Target Attributes

A link header value link’s Target Attribute named name is the second item of the first tuple of link’s Target Attributes whose first item matches the string name, or null if no such tuple is present.

The result of getting allowed signed exchange link info from a list links is returned by the following steps:

  1. Let allowedSxgLinks be an empty list.

  2. For each link of links:

    1. If link’s Relation Type is not 'allowed-alt-sxg', then continue.

    2. Let linkTarget be link’s Link Target.

    3. Let headerIntegrity be link’s Target Attribute named "header-integrity".

    4. If headerIntegrity is null, then continue.

    5. Let linkVariants be link’s Target Attribute named "variants".

    6. Let linkVariantKey be link’s Target Attribute named "variant-key".

    7. Append the allowed signed exchange link info (linkTarget, headerIntegrity, linkVariants, linkVariantKey) to allowedSxgLinks.

  3. Return allowedSxgLinks.

The result of getting alternate signed exchange link info from a list links is returned by the following steps:

  1. Let alternateSxgLinks be an empty list.

  2. For each link of links:

    1. If link’s Relation Type is not 'alternate', then continue.

    2. If link’s Target Attributes doesn’t contain ("type","application/signed-exchange"), then continue.

    3. Let linkTarget be link’s Link Target.

    4. Let linkContext be link’s Link Context.

    5. Let linkVariants be link’s Target Attribute named "variants".

    6. Let linkVariantKey be link’s Target Attribute named "variant-key".

    7. Append the alternate signed exchange link info (linkTarget, linkContext, linkVariants, linkVariantKey) to alternateSxgLinks.

  3. Return alternateSxgLinks.

6. Security Considerations

The Security Considerations of [draft-yasskin-http-origin-signed-responses] apply.

6.1. Certificate Transparency

To identify off-path attackers, § 5.9 Establishing trust in a certificate encourages UAs to implement Certificate Transparency, which requires that, in order for a certificate to be trusted, it must be logged publicly. This means that an off-path attacker who has managed to get a mis-issued certificate has to at least announce that certificate in a place the legitimate domain owner has a chance to notice. Once they notice, they can revoke the certificate, which will stop the UA from trusting it no more than 7 days later.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSP]
Mike West. Content Security Policy Level 3. 15 October 2018. WD. URL: https://www.w3.org/TR/CSP3/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[DRAFT-IETF-HTTPBIS-VARIANTS]
Mark Nottingham. HTTP Representation Variants. WD. URL: https://httpwg.org/http-extensions/draft-ietf-httpbis-variants.html
[DRAFT-THOMSON-HTTP-MICE]
Martin Thomson. Merkle Integrity Content Encoding. ED. URL: https://tools.ietf.org/html/draft-thomson-http-mice-03
[DRAFT-YASSKIN-HTTP-ORIGIN-SIGNED-RESPONSES]
Jeffrey Yasskin. Signed HTTP Exchanges. ED. URL: https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
[DRAFT-YASSKIN-HTTPBIS-ORIGIN-SIGNED-EXCHANGES-IMPL-02]
Jeffrey Yasskin; Kouhei Ueno. Signed HTTP Exchanges Implementation Checkpoints. ED. URL: https://tools.ietf.org/html/draft-yasskin-httpbis-origin-signed-exchanges-impl-02
[DRAFT-YASSKIN-WPACK-BUNDLED-EXCHANGES]
Jeffrey Yasskin. Web Bundles. ED. URL: https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html
[ENCODING]
Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MIMESNIFF]
Gordon P. Hemsley. MIME Sniffing Standard. Living Standard. URL: https://mimesniff.spec.whatwg.org/
[NETWORK-ERROR-LOGGING-1]
Douglas Creager; et al. Network Error Logging. 25 September 2018. WD. URL: https://www.w3.org/TR/network-error-logging-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[RFC5280]
D. Cooper; et al. Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile. May 2008. Proposed Standard. URL: https://tools.ietf.org/html/rfc5280
[RFC5480]
S. Turner; et al. Elliptic Curve Cryptography Subject Public Key Information. March 2009. Proposed Standard. URL: https://tools.ietf.org/html/rfc5480
[RFC6960]
S. Santesson; et al. X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP. June 2013. Proposed Standard. URL: https://tools.ietf.org/html/rfc6960
[RFC6962]
B. Laurie; A. Langley; E. Kasper. Certificate Transparency. June 2013. Experimental. URL: https://tools.ietf.org/html/rfc6962
[RFC7231]
R. Fielding, Ed.; J. Reschke, Ed.. Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content. June 2014. Proposed Standard. URL: https://httpwg.org/specs/rfc7231.html
[RFC8288]
M. Nottingham. Web Linking. October 2017. Proposed Standard. URL: https://httpwg.org/specs/rfc8288.html
[RFC8446]
E. Rescorla. The Transport Layer Security (TLS) Protocol Version 1.3. WD. URL: https://tools.ietf.org/html/draft-ietf-tls-tls13
[SECURE-CONTEXTS]
Mike West. Secure Contexts. 15 September 2016. CR. URL: https://www.w3.org/TR/secure-contexts/
[SHA2]
FIPS PUB 180-4, Secure Hash Standard. URL: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
[STREAMS]
Adam Rice; Domenic Denicola; 吉野剛史 (Takeshi Yoshino). Streams Standard. Living Standard. URL: https://streams.spec.whatwg.org/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WebIDL]
Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[DRAFT-YASSKIN-HTTPBIS-ORIGIN-SIGNED-EXCHANGES-IMPL-03]
Jeffrey Yasskin; Kouhei Ueno. Signed HTTP Exchanges Implementation Checkpoints. ED. URL: https://tools.ietf.org/html/draft-yasskin-httpbis-origin-signed-exchanges-impl-03
[HTTP-DIG-ALG]
Hypertext Transfer Protocol (HTTP) Digest Algorithm Values. LS. URL: https://www.iana.org/assignments/http-dig-alg/http-dig-alg.xhtml
[RFC3230]
J. Mogul; A. Van Hoff. Instance Digests in HTTP. January 2002. Proposed Standard. URL: https://tools.ietf.org/html/rfc3230
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. 19 November 2019. CR. URL: https://www.w3.org/TR/service-workers-1/

Issues Index

Currently the behavior of recursive prefetch is not specified. This section monkeypatches Link type "prefetch" to add support only for the alternate signed exchanges subresources. When we change the HTML spec to support general recursive prefetching, this section needs to align with that change. <https://github.com/w3c/resource-hints/issues/77>
Currently the processing model of the HTTP Link header is not defined in the HTML spec. This section monkeypatches only for Link rel=preload HTTP headers. When we will change the HTML spec to generally support Link HTTP headers, this section must be made to align with the change. <https://github.com/whatwg/html/issues/4224>
Our security reviewers aren’t sure we should allow UAs to take clock skew into account. <https://github.com/WICG/webpackage/issues/141>
This depends on the Variants Cache Behavior returning a list of lists. <https://github.com/httpwg/http-extensions/issues/744>
The algorithms in this section create and operate over ECMAScript objects like ReadableStream despite not having a Realm to attach them to. <https://github.com/whatwg/fetch/issues/730>