Skip to content

fix(merchant-backend): make signature verifier RFC 9421-conformant - #21

Open
chopmob-cloud wants to merge 1 commit into
visa:mainfrom
chopmob-cloud:fix/rfc9421-signature-verifier
Open

fix(merchant-backend): make signature verifier RFC 9421-conformant#21
chopmob-cloud wants to merge 1 commit into
visa:mainfrom
chopmob-cloud:fix/rfc9421-signature-verifier

Conversation

@chopmob-cloud

Copy link
Copy Markdown

Summary

The merchant backend's signature verifier (merchant-backend/app/security/signature_verification.py) cannot verify any RFC 9421 HTTP Message Signature, so a signature produced for the CDN proxy is always rejected at the merchant. The merchant backend README states this component provides "RFC 9421 HTTP Message Signatures support" and "Integration with CDN Proxy for signature validation", but the current verifier diverges from RFC 9421 and from the repository's own cdn-proxy reference.

Root cause

Comparing the verifier with cdn-proxy/server.js (parseRFC9421SignatureInput / buildRFC9421SignatureString):

  1. The signature base omits the mandatory @signature-params line (RFC 9421 section 2.5). The verifier instead appends bare nonce / created / expires lines, so the base it reconstructs can never match what a conformant signer signed. Verification fails for every RFC 9421 signature.
  2. Covered components are parsed as a single space joined quoted blob ("@authority @path"), whereas RFC 9421 and the CDN proxy use individually quoted identifiers ("@authority" "@path"). The regex also hardcodes the sig1 label and a fixed parameter order, so a conformant Signature-Input fails to parse at all.
  3. The alg parameter is ignored and only RSA-PSS is handled, so Ed25519 keys (supported by the agent registry and the CDN proxy) cannot be verified.

Fix

Bring the verifier in line with the CDN proxy's RFC 9421 implementation, with no change to the is_trusted_agent(...) or /auth/verify-signature contract:

  • Reconstruct the signature base with the @signature-params line as the final component, carrying the verbatim signature parameters.
  • Parse the covered component list as individually quoted identifiers, with an arbitrary label and unordered parameters.
  • Select the algorithm from alg (rsa-pss-sha256 and ed25519), with an explicit key type check on each path.
  • Require a nonce and reject reuse (the replay protection the CDN proxy already assumes), retaining each nonce until its signature expires and verifying the signature before recording the nonce.

Validation

  • The reconstructed signature base is byte for byte identical to cdn-proxy/server.js's buildRFC9421SignatureString output for the same inputs.
  • Against the live POST /api/auth/verify-signature endpoint: a conformant RSA-PSS and Ed25519 signature is accepted, while tampered, replayed, and expired signatures are rejected. The pre-fix verifier rejects the same valid signature with "Invalid signature format".
  • Adversarial checks pass: unknown agent, forged signature, algorithm confusion in both directions, and tampered Signature-Input parameters are all rejected. Verified on Python 3.12 with cryptography 41 and 48.

@chopmob-cloud
chopmob-cloud force-pushed the fix/rfc9421-signature-verifier branch from f411e56 to cd9caa1 Compare August 4, 2026 06:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant