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,