Skip to content

Commit

Permalink
Formalizing the RFC9421 profile.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikewest committed Nov 21, 2024
1 parent 8e94354 commit 81cbcac
Showing 1 changed file with 161 additions and 81 deletions.
242 changes: 161 additions & 81 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ urlPrefix: https://www.rfc-editor.org/rfc/rfc9651; type: dfn; spec: RFC9651
for: structured header
text: token; url: #name-tokens
text: list; url: #name-list
text: dictionary; url: #name-dictionary
urlPrefix: https://w3c.github.io/webappsec-subresource-integrity/; spec: SRI
type: dfn
text: valid SRI hash algorithm token
Expand All @@ -31,6 +32,14 @@ urlPrefix: https://www.ietf.org/archive/id/draft-pardue-http-identity-digest-01.
urlPrefix: https://www.rfc-editor.org/rfc/rfc9421.html; spec: RFC9421
type: dfn
text: signature base; url: name-creating-the-signature-base
text: component identifier; url: covered-components
text: signature parameters; url: signature-params
text: sf; url: http-field-structured
text: alg; url: section-2.3-4.8
text: created; url: section-2.3-4.2
text: expires; url: section-2.3-4.4
text: keyid; url: section-2.3-4.10
text: tag; url: section-2.3-4.12
type: http-header;
text: Accept-Signature; url: name-the-accept-signature-field
text: Signature-Input; url: name-the-signature-input-field
Expand Down Expand Up @@ -226,12 +235,20 @@ Patches to SRI {#monkey-patch-sri}

At a high level, we'll make the following changes to SRI:

1. We'll define the accepted algorithm values. Currently, these are left up to
1. We'll define a profile of HTTP Message Signatures that meets the specific
needs we have for this feature, specifying the requirements for signatures
intended as proofs of integrity/provenance that can be enforced upon by
clients without any pre-existing relationship to the server which
delivered them. This requires locking down the components and properties
of the signature itself, as well as some of the decision points available
during the generation of the signature base

2. We'll define the accepted algorithm values. Currently, these are left up to
user agents in order to allow for future flexibility: given that the years
since SRI's introduction have left the set of accepted algorithms and their
practical ordering unchanged, we should define that explicitly.

2. With known algorithms, we can adjust the prioritization model to return a
3. With known algorithms, we can adjust the prioritization model to return a
set of the strongest content-based and signature-based algorithms specified
in a given element. This would enable developers to specify both a hash and
signature expectation for a resource, ensuring both that known resources
Expand All @@ -242,10 +259,150 @@ At a high level, we'll make the following changes to SRI:
additional complexity in developers' mental model. So, consider it a
decision point.

3. Finally, we'll adjust the matching algorithm to correctly handle signatures
4. Finally, we'll adjust the matching algorithm to correctly handle signatures
by passing the public key in to the comparison operation.

The following sections adjust algorithms accordingly.
The following sections add content and adjust algorithms accordingly.

<h4 id="profile">The `SRI` HTTP Message Signature Profile</h4>

This document defines an HTTP Message Signature profile that specifies the
requirements for signatures intended as proofs of integrity/provenance that can
be enforced upon by clients without any pre-existing relationship to the server
which delivered them. This requires locking down the components and properties
of the signature itself, as well as some of the decision points
available during the generation of the signature base (Section 2.5 of
[[RFC9421]]).

At a high-level, the constraints are simple: this profile supports only Ed25519
signatures, requires that the public key portion of the verification key
material be included in the signature's input, and specifies the ordering of the
components and properties to remove potential ambiguity about the signature's
construction. The rest of this section spells out those constraints more
formally as the <dfn>verification requirements for SRI</dfn>, following the
guidelines from Section 1.4 of [[RFC9421]]:

: **Components and Parameters**:
:: The signature's input MUST:

1. Include the following [=component identifiers=] with their associated
constraints:

* `identity-digest`, which MUST include the <a>`sf`</a> parameter and
no other parameters.

2. Include the following [=signature parameters=] with their associated
constraints:

* <a>`alg`</a>, whose value MUST be the string `ed25519`
* <a>`keyid`</a>, whose value MUST be a string containing a
[=forgiving-base64 encode|base64 encoding=] of the public key
portion of the signature's verification key material.
* <a>`tag`</a>, whose value MUST be the string `sri`

ISSUE: Perhaps something more specific to make room for variants
in the future that have different constraints?
`enforce-ed25519-provenance`?

3. Order the signature's parameters alphabetically.

The signature's input MAY include the following [=signature parameters=],
with their associated constraints:

* <a>`created`</a>, an integer whose value MUST represent a time in the past.
* <a>`expires`</a>, an integer whose value MUST represent a time in the future.
* `nonce`, which is a string.

: **Structured Field Types**:
:: * The `identity-digest` component references the [:Identity-Digest:]
header defined in [[ID.pardue-http-identity-digest]]. It is a
[=structured header/Dictionary=] Structured Field.

: **Retrieving the Key Material**:
:: The public key of the verification key material can be directly extracted
from the signature input's <a>`keyid`</a> parameter, where it's represented
as a [=forgiving-base64 encode|base64 encoded=] string.

: **Signature Algorithms**:
:: The only signature algorithm allowed is `ed25519`.

: **Determine Key/Algorithm Appropriateness**:
:: Since the only accepted algorithm is `ed25519`, it is appropriate for any
context in which this profile will be used, and we require it to be
specified as the <a>`alg`</a> parameter to the signature's input.

: **Derivation Context**
:: The context for derivation of message components from an HTTP message and
its application context is the HTTP message itself, encompassing the
response with which the signature was delivered, and the request to which
it responds.

: **Error Reporting from Verifier to Signer**
:: No error reporting is required.

Clients MUST represent verification failures as [=network errors=],
consistent with [[FETCH]]'s handling of other server-specified constraints
on the usage of response data.

: **Security Considerations**
:: See [[#security]].


<div class="example" id="example-verification-requirements">
Valid [:Signature-Input:] header values would therefore include:

* `("identity-digest";sf);alg="ed25519";keyid="MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"`
</div>

<div class="note">
Note: These requirements are fairly draconian, allowing only a very small subset
of the flexibility allowed by the HTTP Message Signature format. It is entirely
probable that we can expand the scope of allowed signature inputs in the future,
but as we're figuring out how to do signature validation on the client it seems
prudent to provide as much strict guidance as possible in order to keep the
initial complexity under control.

For posterity, this set of requirements has a few helpful implications:

1. Specifying the `tag` parameter as "`sri`" is a pretty clear signal that the
developer is aiming to validate the integrity and/or provenance of a given
subresource, and can therefore be reasonably expected to adhere to the set
of constraints and processing instructions described in this document.
Developers specifying that tag can be expected to be unsurprised when
resources are blocked if their signatures don't properly validate.

2. Specifying the `keyid` parameter as a base64 encoding of the signer's public
key makes it possible for validation to be enforced whether or not the
resource was requested from a page requiring integrity.

3. Specifying the `alg` parameter as "`ed25519`" is a good place to start as
the keys are small and the algorithm is broadly supported. Choosing one
algorithm simplifies initial implementations, and reduces the set of choices
we ask developers to make about crypto primitives.

4. The [:Signature-Input:] header is very flexible as specified, and most of
the restrictions here aim to reduce its complexity as we gain implementation
experience on both the client and server sides of the signature generation
process. [[RFC9421]] leaves several important questions about the
serialization of the "[=signature base=]" open to agreement between the
signer and verifier: we're locking most of those joints down here in order
to ensure that we start with a simple story for both sides.

To that end, we're supporting signatures only over the one specific header
necessary to meaningfully assert something about the resource's body. We're
explicitly specifying strict serialization of that header, and we're
requiring it to be a header, not a trailer.

5. In order to avoid potential disagreements between servers and clients about
the serialization of a [=signature base=] for a given response, we're
specifying how both sides ought to "Determine an order for any signature
parameters" by locking in alphabetical sorting of the signature's
parameters. We really only need to do this when generating the signature
base: the [:Signature-Input:] header could in theory be arbitrarily sorted.
In practice, however, it seems prudent to ensure that we make the expected
representation as clear as possible.

</div>


<h4 id="parsing" algorithm>Parse |metadata|.</h4>
Expand Down Expand Up @@ -346,83 +503,6 @@ following steps. They return `valid` if the signature is valid, or `invalid` oth



The HTTP Message Signature <dfn>verification requirements for SRI</dfn> are the
following:

1. The components specified in the [:Signature-Input:] header MUST include
*only* a single item that [=string/is=] the string "`identity-digest`".
This item MUST include *only* the parameter `sf`.

2. The signature's parameters MUST satisfy all of the following requirements:
* The `alg` parameter is present, and its value [=string/is=] "`ed25519`".
* If the `created` parameter is present, its value represents a time in
the past.
* If the `expires` parameter is present, its value represents a time in
the future.
* The `keyid` parameter is present, and its value is a string containing
a base64 encoding of an Ed25519 public key.
* The `tag` parameter's value [=string/is=] "`sri`".
* The parameters are specified in alphabetical order.

<div class="example" id="example-verification-requirements">
Valid [:Signature-Input:] header values would therefore include:

* `("identity-digest";sf);alg="ed25519";keyid="MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=";tag="sri"`
</div>

<div class="note">
Note: These requirements are fairly draconian, allowing only a very small subset
of the flexibility allowed by the HTTP Message Signature format. It is entirely
probable that we can expand the scope of allowed signature inputs in the future,
but as we're figuring out how to do signature validation on the client it seems
prudent to provide as much strict guidance as possible in order to keep the
initial complexity under control.

For posterity, this set of requirements has a few helpful implications:

1. Specifying the `tag` parameter as "`sri`" is a pretty clear signal that the
developer is aiming to validate the integrity and/or provenance of a given
subresource, and can therefore be reasonably expected to adhere to the set
of constraints and processing instructions described in this document.
Developers specifying that tag can be expected to be unsurprised when
resources are blocked if their signatures don't properly validate.

2. Specifying the `keyid` parameter as a base64 encoding of the signer's public
key makes it possible for validation to be enforced whether or not the
resource was requested from a page requiring integrity.

3. Specifying the `alg` parameter as "`ed25519`" is a good place to start as
the keys are small and the algorithm is broadly supported. Choosing one
algorithm simplifies initial implementations, and reduces the set of choices
we ask developers to make about crypto primitives.

4. The [:Signature-Input:] header is very flexible as specified, and most of
the restrictions here aim to reduce its complexity as we gain implementation
experience on both the client and server sides of the signature generation
process. [[RFC9421]] leaves several important questions about the
serialization of the "[=signature base=]" open to agreement between the
signer and verifier: we're locking most of those joints down here in order
to ensure that we start with a simple story for both sides.

To that end, we're supporting signatures only over the one specific header
necessary to meaningfully assert something about the resource's body. We're
explicitly specifying strict serialization of that header, and we're
requiring it to be a header, not a trailer.

5. In order to avoid potential disagreements between servers and clients about
the serialization of a [=signature base=] for a given response, we're
specifying how both sides ought to "Determine an order for any signature
parameters" by locking in alphabetical sorting of the signature's
parameters. We really only need to do this when generating the signature
base: the [:Signature-Input:] header could in theory be arbitrarily sorted.
In practice, however, it seems prudent to ensure that we make the expected
representation as clear as possible.

</div>

</ins>


Patches to Fetch {#monkey-patch-fetch}
--------------------------------------

Expand Down

0 comments on commit 81cbcac

Please sign in to comment.