diff --git a/IETF-OCM.md b/IETF-OCM.md index 9a8bb50..172aac4 100644 --- a/IETF-OCM.md +++ b/IETF-OCM.md @@ -356,7 +356,7 @@ Share Creation Notification from an unknown Sending Party is received Whereas the precise syntax of the Invite Message and the Invite Acceptance Gesture will differ between implementations, the Invite -Acceptance Request SHOULD be a HTTP POST request: +Acceptance Request MUST be a HTTP POST request: * to the `/invite-accepted` path in the Invite Sender OCM Server's OCM API @@ -376,7 +376,12 @@ Acceptance Request SHOULD be a HTTP POST request: - REQUIRED: `name` - Human-readable name of the Invite Receiver, as a suggestion for display in the Invite Sender's address book * using TLS -* using httpsig [RFC9421] + +When HTTP Message Signatures are available, the Invite Acceptance +Request MUST be signed and verified as described in [HTTP Message +Signatures](#http-message-signatures). As the Invite flow establishes +the trust that later exchanges rely on, implementations SHOULD NOT use +it unless signing is available. The Invite Receiver OCM Server SHOULD apply its own policies for trusting the Invite Sender OCM Server before making the Invite @@ -429,10 +434,11 @@ A 403 response status means the Invite Receiver OCM Server is not trusted to accept this Invite. A 409 response status means the Invite was already accepted. -The Invite Sender OCM Server SHOULD verify the HTTP Signature on the -Invite Acceptance Request and apply its own policies for trusting the -Invite Receiver OCM Server before processing the Invite Acceptance -Request and sending the Invite Acceptance Response. +Before processing the Invite Acceptance Request and sending the Invite +Acceptance Response, the Invite Sender OCM Server SHOULD apply its own +policies for trusting the Invite Receiver OCM Server. Any HTTP +Signature on the request is verified as described in [HTTP Message +Signatures](#http-message-signatures). As with the `userID` in the Invite Acceptance Request, the one in the Response also doesn't need to be human-memorable, doesn't need to match @@ -760,6 +766,108 @@ contain the following information about its OCM API: provide this URL as well. Example: `"https://cloud.example.org/ocm/token"`. +# HTTP Message Signatures + +A number of OCM API requests are signed "using httpsig [RFC9421]", as +described in the respective sections. This section specifies the +normative requirements for producing and verifying those signatures. +Appendix B contains a complete example. + +Public keys for signature verification are published in the format +specified by [RFC7517] at the signer's `/.well-known/jwks.json` +endpoint, if the `http-sig` capability is included in the +[Discovery](#ocm-api-discovery) response. + +## Applicability + +Support for HTTP Message Signatures is negotiated through the +`http-sig` capability in the [Discovery](#ocm-api-discovery) response. +The following rules let deployments adopt signing incrementally while +remaining interoperable: + +* A Server that implements HTTP Message Signatures MUST use them when + interacting with another Server that advertises the `http-sig` + capability. +* Such a Server MAY nonetheless continue to interact, without signing, + with a Server that does not advertise the `http-sig` capability, for + backwards compatibility. +* A Server that implements HTTP Message Signatures MUST verify any + signature present on a request it receives, as specified below. +* A Server MAY accept an unsigned request from a Server that does not + advertise the `http-sig` capability; a Server that advertises the + `must-use-http-sig` criterion MUST reject unsigned requests. +* A Server that does not implement HTTP Message Signatures operates + without them. + +Because the [Invite Acceptance +Request](#invite-acceptance-request-details) and [Request for a +Share](#request-for-a-share) establish the trust that later exchanges +rely on, implementations SHOULD NOT use those features unless HTTP +Message Signatures are available. + +## Signing Requirements + +A signed request MUST cover at least the following Signature-Input +components: + +* "@method" - HTTP method +* "@target-uri" - full request URI (scheme, authority, + path, query) +* "content-digest" - [RFC9530] digest of the body +* "content-length" - message size + +The Signature-Input parameters MUST include `created`. Freshness and +replay protection are anchored on `created` (see Verification +Requirements). + +A signed request SHOULD additionally cover the `date` component when a +`Date` header is present. + +The `content-digest` component binds the request body to the signature, +protecting it against modification in transit. Its value MUST use a +hash algorithm from the IANA "Hash Algorithms for HTTP Digest Fields" +registry [IANA-DIGEST-ALG]; implementations MUST support `sha-256`. + +A request signed in the context of OCM MUST carry the signature +parameter `tag="ocm"` (see Section 2.3 of [RFC9421]). Unlike the +signature label, which is a dictionary key that is not covered by the +signature and MAY be rewritten in transit, the `tag` parameter is part +of the signature base and is therefore integrity-protected. + +A request MUST include one and only one signature carrying +`tag="ocm"`. The signature label MAY be any value; it is not +significant to OCM processing. + +The signature MUST use an asymmetric algorithm from the IANA "HTTP +Signature Algorithms" registry [IANA-SIG-ALG]; `ed25519` [RFC8032] is +RECOMMENDED. A symmetric algorithm, such as the HMAC-based +`hmac-sha256`, MUST NOT be used, as the Receiving Server would not be +able to verify the signature without prior access to the shared secret. + +## Verification Requirements + +Verifiers MUST reject signatures that omit any of the mandatory +components listed under Signing Requirements or the `created` +parameter, and MUST reject signatures whose `created` value is more +than a small implementation-defined skew tolerance in the future, or +older than the verifier's freshness window. + +A `Content-Digest` header value carrying multiple algorithms MUST have +every recognised digest match the body; a single match alongside a +recognised mismatch MUST be treated as an integrity failure. + +Verifiers MUST identify the OCM signature by its `tag="ocm"` +parameter, examining the parameters of each member of the +`Signature-Input` field and disregarding the dictionary labels. +Verifiers MUST verify only that signature. If more than one signature +carries `tag="ocm"`, the entire message MUST be rejected. A request +that carries no signature with `tag="ocm"` is unsigned and is handled +as described in Applicability (accepted only at the receiver's +discretion, or rejected when the receiver advertises +`must-use-http-sig`). Signatures without `tag="ocm"` MAY coexist (e.g. +proxy-attached signatures) but verifiers MUST NOT process them as part +of OCM signature processing. + # Share Creation Notification To create a Share, the Sending Server SHOULD make a HTTP POST request @@ -1098,7 +1206,8 @@ notification that this happened. # Request for a Share If the Receiving Party knows of a resource that has not yet -been shared, the Receiving Party MAY make an HTTP POST request +been shared, the Receiving Party MAY request that it be shared. +Such a Request for a Share MUST be an HTTP POST request * to the `/request-share` path in the Sending Server's OCM API * using `application/json` as the `Content-Type` HTTP request @@ -1106,7 +1215,13 @@ been shared, the Receiving Party MAY make an HTTP POST request * its request body containing a JSON document representing an object with the fields as described below * using TLS -* using httpsig [RFC9421] + +When HTTP Message Signatures are available, the Request for a Share +MUST be signed and verified as described in [HTTP Message +Signatures](#http-message-signatures). As requesting access to a +restricted resource relies on authenticating the requester, +implementations SHOULD NOT use this feature unless signing is +available. ## Fields @@ -1120,6 +1235,10 @@ been shared, the Receiving Party MAY make an HTTP POST request A unique identifier for the resource. Example: 1234567890abcdef or https://cloud.example.org/files/data.txt +Any HTTP Signature on the Request for a Share is verified as described +in [HTTP Message Signatures](#http-message-signatures) before the +Sending Server acts on it. + After receiving a request for a Share, the Sending Party MAY send a Share Creation Notification to the Receiving Party using the OCM address in the shareWith field. @@ -1283,11 +1402,12 @@ Content-Type: application/x-www-form-urlencoded Digest: SHA-256=ok6mQ3WZzKc8nb7s/Jt2yY1uK7d2n8Zq7dhl3Q0s1xk= Content-Length: 101 Signature-Input: - ocm=("@method" "@target-uri" "content-digest" "date"); + sig1=("@method" "@target-uri" "content-digest" "date"); created=1730815200; keyid="receiver.example.org#key1"; - alg="ed25519" -Signature: ocm=:bM2sV2a4oM8pWc4Q8r9Zb8bQ7a2vH1kR9xT0yJ3uE4wO5lV6bZ1cP + alg="ed25519"; + tag="ocm" +Signature: sig1=:bM2sV2a4oM8pWc4Q8r9Zb8bQ7a2vH1kR9xT0yJ3uE4wO5lV6bZ1cP 2rN3qD4tR5hC=: grant_type=authorization_code& @@ -1699,7 +1819,9 @@ discovery service. It is RECOMMENDED to use signed messages, "httpsig" [RFC9421], to verify that an OCM server is the server you expect it to be, and SHOULD -be done unless you have a niche use case. +be done unless you have a niche use case. Where signatures are used, +they MUST follow the requirements in +[HTTP Message Signatures](#http-message-signatures). ## Legacy shared secrets @@ -1726,6 +1848,12 @@ author, version, name of work, or endorsement information. ## Normative References +[IANA-DIGEST-ALG] IANA, "[Hash Algorithms for HTTP Digest Fields]( +https://www.iana.org/assignments/http-digest-hash-alg/http-digest-hash-alg.xhtml)". + +[IANA-SIG-ALG] IANA, "[HTTP Signature Algorithms]( +https://www.iana.org/assignments/http-message-signature/http-message-signature.xhtml#signature-algorithms)". + [RFC2119] Bradner, S. "[Key words for use in RFCs to Indicate Requirement Levels](https://datatracker.ietf.org/doc/html/rfc2119)", March 1997. @@ -1777,13 +1905,13 @@ https://datatracker.ietf.org/doc/html/rfc9553), May 2024" ## Informative References -[OCM-IP] Nordin, M., Lo Presti, G., and Baghbani, M. "[Open -Cloud Mesh Integration +[OCM-IP] Nordin, M., Lo Presti, G., and Baghbani, M. "[Open Cloud Mesh +Integration Protocol](https://datatracker.ietf.org/doc/draft-nordin-ocm-integration-protocol/)", Work in Progress, Internet-Draft. -[OCM-MLS] Nordin, M., Lo Presti, G., and Baghbani, M. "[Federated -Groups in Open Cloud Mesh using Messaging Layer +[OCM-MLS] Nordin, M., Lo Presti, G., and Baghbani, M. "[Federated Groups +in Open Cloud Mesh using Messaging Layer Security](https://datatracker.ietf.org/doc/draft-nordin-ocm-mls-federated-groups/)", Work in Progress, Internet-Draft. @@ -1879,71 +2007,47 @@ breaks in @signature-params for display purposes only): "content-length" "date"); created=[timestamp]; keyid="sender.example.org#key1"; - alg="ed25519" + alg="ed25519"; + tag="ocm" Sign this base using for example Ed25519 ([RFC8032]) to produce the -signature, using the `ocm` label, and then add headers (line breaks -for display purposes only): +signature, and then add headers (line breaks for display purposes +only). Note that the dictionary label (`sig1` below) is arbitrary; the +signature is marked as belonging to OCM by its `tag="ocm"` parameter, +which is part of the signature base above: Content-Digest: sha-256=:[digest-value]: Content-Length: [body-length] Date: [date] -Signature-Input: ocm=("@method" "@target-uri" "content-digest" +Signature-Input: sig1=("@method" "@target-uri" "content-digest" "content-length" "date"); created=[timestamp]; keyid="sender.example.org#key1"; - alg="ed25519" -Signature: ocm=:[signature-value]=: + alg="ed25519"; + tag="ocm" +Signature: sig1=:[signature-value]=: -A signed request MUST cover at least the following Signature-Input -components: - - - "@method" - HTTP method - - "@target-uri" - full request URI (scheme, authority, - path, query) - - "content-digest" - [RFC9530] digest of the body - - "content-length" - bound message size - - "date" - bound clock time - -The Signature-Input parameters MUST include `created`. Verifiers MUST -reject signatures that omit any of the above components or the `created` -parameter, and MUST reject signatures whose `created` value is more than -a small implementation-defined skew tolerance in the future, or older -than the verifier's freshness window. - -A `Content-Digest` header value carrying multiple algorithms MUST have -every recognised digest match the body; a single match alongside a -recognised mismatch MUST be treated as an integrity failure. - -A request signed in the context of OCM MUST include one and only one -signature with the label `ocm` in its Signature and Signature-Input -headers. - -A symmetric signing algorithm MUST NOT be used to sign the -request, as the Receiving Server would not be able to verify the -signature without having access to the shared secret in advance. +The covered components, the `created` parameter, the single `ocm` +tag, and the prohibition on symmetric algorithms shown here are +normative; see [HTTP Message Signatures](#http-message-signatures) for +the full requirements. ## Verifying a Signature (Receiver) -Verifiers MUST locate the ocm-labeled entry and verify only that one. -If multiple `ocm` signatures are present, the entire message MUST be -rejected. Verifiers MUST reject requests for which no ocm-labeled entry -is present. Other labels MAY coexist (e.g. proxy-attached signatures) -but verifiers MUST NOT process them as part of OCM signature -processing. - - -To verify an incoming signed request: +The normative verification requirements are specified in +[HTTP Message Signatures](#http-message-signatures). The following +illustrates the procedure to verify an incoming signed request: 1. Extract the provider domain from the `sender` field in the request body 2. Fetch the public key from `https:///.well-known/jwks.json` -3. Locate the unique signature with the label `ocm` in the - `Signature-Input` header +3. Locate the unique signature carrying the `tag="ocm"` parameter in + the `Signature-Input` header, disregarding its dictionary label + (here `sig1`) 4. Extract `keyid` from `Signature-Input` header and find the key matching the `kid` value in the [RFC7517] response 5. Reconstruct the signature base from the request using the @@ -2437,9 +2541,9 @@ Peter Szegedi, Ron Trompert, Benedikt Wegmann and Jonathan Xu. We would also like to thank Ishank Arora, Gianmaria Del Monte, Jörn Friedrich Dreyer, Richard Freitag, Hugo González Labrador, -Matthias Kraus, Maxence Lange, Lovisa Lugnegård, Sandro Mesterheide, -Antoon Prins and Björn Schießle for their direct contributions -to the specification. +Matthias Kraus, Maxence Lange, Lovisa Lugnegård, Thibault Meunier, +Sandro Mesterheide, Antoon Prins and Björn Schießle for their direct +contributions to the specification. Over the years many more people have been involved in the development of OCM. We would like to thank all of them for their contributions,