Skip to content

feat(http-sig): Dual stack http-sig#60136

Open
mickenordin wants to merge 6 commits intomasterfrom
kano-dual-stack-rfc-9421-http-sig
Open

feat(http-sig): Dual stack http-sig#60136
mickenordin wants to merge 6 commits intomasterfrom
kano-dual-stack-rfc-9421-http-sig

Conversation

@mickenordin
Copy link
Copy Markdown
Contributor

@mickenordin mickenordin commented May 4, 2026

Nextcloud uses the old draft-cavage style http signatures, that was never adopted as an RFC by the IETF. This PR implements RFC 9421 style http signatures that is required for many of the new features of OCM. This implementation will allow both type of signatures to coexist as a dual stack implementation.

It also adds occ commands to rotate keys, by staging a new key, activating it, and remove the old one.

  • The content of this PR was partly or fully generated using AI

@mickenordin mickenordin requested a review from a team as a code owner May 4, 2026 10:13
@mickenordin mickenordin requested review from ArtificialOwl, nfebe, salmart-dev and sorbaugh and removed request for a team May 4, 2026 10:13
@mickenordin mickenordin marked this pull request as draft May 4, 2026 10:13
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch 6 times, most recently from d707a33 to 088dcbb Compare May 4, 2026 15:35
@mickenordin
Copy link
Copy Markdown
Contributor Author

I verified the flow end to end, using a mitm proxy, and old signatures are used talking to stock nextcloud and new style signatures used when talking to a build from this pr.

@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch 4 times, most recently from 16d70fc to b1cb1e4 Compare May 5, 2026 06:45
@mickenordin mickenordin marked this pull request as ready for review May 5, 2026 08:07
@mickenordin mickenordin added the 3. to review Waiting for reviews label May 5, 2026
@mickenordin mickenordin added this to the Nextcloud 34 milestone May 5, 2026
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch from 482dc14 to e096272 Compare May 5, 2026 09:30
Copy link
Copy Markdown
Member

@CarlSchwan CarlSchwan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense on paper, but there is too much crypto code which would be better to delegate to a third party library

Comment thread lib/private/Security/Jwks/Jwk.php Outdated
Comment thread lib/private/Security/Signature/Rfc9421/Algorithm.php
@mickenordin
Copy link
Copy Markdown
Contributor Author

Make sense on paper, but there is too much crypto code which would be better to delegate to a third party library

I will take a look at what I can replace with php-jwt. Also note that all the php libraries I was able to find that implements http-sig implemented draft-cavage signatures ~7 years ago, and has not been updated to implement the actual RFC9421, so we will need to implement the signature part ourselfs.

mickenordin added a commit to nextcloud/3rdparty that referenced this pull request May 5, 2026
The nextcloud/server PR nextcloud/server#60136
implements RFC9421 http-signatures. Rather than implementing some of the
JWK primitives our selfs, we can lean on firebase/php-jwt and that is
this commit adds that dependency here.

Signed-off-by: Micke Nordin <kano@sunet.se>
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch 3 times, most recently from 7d35e62 to 55c7f16 Compare May 5, 2026 12:40
@mickenordin
Copy link
Copy Markdown
Contributor Author

@CarlSchwan I have whittled a way quite a bit now, and reused as much as I can from firebase/JWT, I think.

Another thing I could do is replace a lot of the structured fields parsing in lib/private/Security/Signature/Rfc9421/SfParser.php with https://github.com/gapple/structured-fields, but that would be at the cost of another 3rdparty vendoring. What do you think?

@mickenordin mickenordin requested a review from CarlSchwan May 5, 2026 13:00
@CarlSchwan
Copy link
Copy Markdown
Member

And it's probably a good idea to use https://github.com/gapple/structured-fields if this remove some code.

4000 lines of code is very hard to review

@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch from 55c7f16 to 491d813 Compare May 5, 2026 13:19
mickenordin added a commit to nextcloud/3rdparty that referenced this pull request May 5, 2026
The gapple/structured-fields package implements RFC 8941 (HTTP
Structured Field Values) and RFC 9651. nextcloud/server's RFC 9421
HTTP Message Signatures verifier and signer use it to drop the
hand-rolled Signature-Input / Signature dictionary parser, per review
feedback on nextcloud/server#60136.

License: MIT.
Signed-off-by: Micke Nordin <kano@sunet.se>
mickenordin added a commit to nextcloud/3rdparty that referenced this pull request May 5, 2026
The gapple/structured-fields package implements RFC 8941 (HTTP
Structured Field Values) and RFC 9651. nextcloud/server's RFC 9421
HTTP Message Signatures verifier and signer use it to drop the
hand-rolled Signature-Input / Signature dictionary parser, per review
feedback on nextcloud/server#60136.

Signed-off-by: Micke Nordin <kano@sunet.se>
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch from 491d813 to be83c58 Compare May 5, 2026 14:45
@mickenordin
Copy link
Copy Markdown
Contributor Author

mickenordin commented May 5, 2026

And it's probably a good idea to use https://github.com/gapple/structured-fields if this remove some code.

4000 lines of code is very hard to review

The diff is now around ~3500 lines and I have tried to restructure the pr into 6 commits that should be easier to review, pretending that firebase/php-jwt and gapple/structured-fields were there from the beginning...

BTW: About ~1500 lines of that is tests.

Companion to nextcloud/3rdparty#2413. firebase/php-jwt handles JWK
parsing and JWS algorithm dispatch; gapple/structured-fields handles
RFC 8941 Structured Field parsing for Signature-Input / Signature.

Signed-off-by: Micke Nordin <kano@sunet.se>
Promote ext-sodium from recommended to required so RFC 9421 Ed25519
signing/verifying can rely on libsodium unconditionally. Add the
matching openssl + sodium psalm stubs.

Signed-off-by: Micke Nordin <kano@sunet.se>
Add the RFC 9421 (HTTP Message Signatures) sign/verify path alongside
the existing draft-cavage implementation:

- Algorithm: sodium for Ed25519, JWT::sign for RSA / ECDSA, ecdsaRawToDer
  for the ECDSA wire format. JWK parsing via JWK::parseKey.
- SignatureBase: RFC 9421 §2.5 base construction for the derived
  components OCM uses plus plain HTTP fields.
- ContentDigest: RFC 9530 helpers used as a covered component.
- Rfc9421IncomingSignedRequest / Rfc9421OutgoingSignedRequest:
  request models. Parsing of Signature-Input / Signature delegates
  to gapple\\StructuredFields\\Parser.
- IJwkResolvingSignatoryManager: capability bit signatory managers
  advertise to participate in RFC 9421 verification.
- OcmProfile: OCM-mandated dictionary label.
- SignatureManager: dispatch to RFC 9421 inbound when Signature-Input
  is present, outbound when rfc9421.format is set.

Plus tests for each primitive and a full round-trip across the model.

Signed-off-by: Micke Nordin <kano@sunet.se>
Add Manager::generateEd25519AppKey: persist a sodium-generated
Ed25519 keypair (raw 32-byte public, 64-byte secret) under the same
appdata layout the existing RSA path uses. Used by OCMSignatoryManager
for the slotted RFC 9421 signing keys.

Signed-off-by: Micke Nordin <kano@sunet.se>
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch from be83c58 to 4fbc2e3 Compare May 5, 2026 14:59
OCM dual-stack integration of RFC 9421 alongside the existing cavage
publicKey path:

- OCMSignatoryManager: Ed25519 active/pending/retiring slot rotation
  backed by numbered pool appkeys, getRemoteKey for inbound JWK lookup
  with per-origin cache + cache-miss refetch, and getLocalEd25519Jwks
  for the JWKS endpoint.
- Rfc9421SignatoryManager: per-call wrapper that swaps in the Ed25519
  signatory and toggles `rfc9421.format`.
- OCMJwksHandler: serves /.well-known/jwks.json (RFC 7517) when signing
  is enabled.
- OCMDiscoveryService: advertises `http-sig` in capabilities when
  signing is enabled, and picks the signature scheme on outbound based
  on the remote's advertised capabilities.
- Application.php: register the JWKS well-known handler.

Signed-off-by: Micke Nordin <kano@sunet.se>
  ocm:keys:list      list known keys with their slot and kid
  ocm:keys:stage     generate a pending key, advertise via JWKS
  ocm:keys:activate  promote pending -> active, demote previous active
  ocm:keys:retire    delete the retiring key (kid stops resolving)

Plus the autoloader regen covering the new classes from this branch.

Signed-off-by: Micke Nordin <kano@sunet.se>
@mickenordin mickenordin force-pushed the kano-dual-stack-rfc-9421-http-sig branch from 4fbc2e3 to 61147d0 Compare May 5, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants