Skip to content

Flower Shop verify_signature accepts every request and its docstring describes HMAC — spec requires RFC 9421 asymmetric signatures #121

Description

@vishkaty

The Python Flower Shop server does not actually verify request signatures, and its placeholder describes the wrong mechanism.

rest/python/server/dependencies.py (main @ ebb4935), lines 109-127:

async def verify_signature(
  request_signature: str = Header(..., alias="Request-Signature"),
) -> None:
  """Verify the request signature.

  Note: This is a placeholder implementation that bypasses validation if the
  signature is "test". A real implementation would verify the HMAC-SHA256
  signature of the request body.
  ...
  """
  if request_signature == "test":
    return
  # In sample implementation, we don't enforce signature validation
  return

Two problems:

  1. It verifies nothing — every request is accepted, and it reads a bespoke Request-Signature header that isn't part of the protocol.
  2. The docstring points implementers the wrong way. It describes HMAC-SHA256, but signatures.md mandates asymmetric signatures: RFC 9421 HTTP Message Signatures (Signature/Signature-Input), an RFC 9530 Content-Digest over the raw body, ES256 as the MUST-verify baseline in fixed-width raw r||s (explicitly not ASN.1/DER), and signer-key discovery from the UCP-Agent profile's signing_keys. A newcomer following this sample builds HMAC and a Request-Signature header, neither of which interoperates.

Since this is the reference server, it's the natural place to show the signature layer working end to end.

Would you accept a PR that replaces the stub with a real RFC 9421 verifier (and has the demo client sign)? I have one ready and would value your view on the approach before opening it. It is designed to change nothing by default:

  • Verification is real but enforcement is opt-in (a --require_signatures flag, default off). With it off, a present signature is verified and the result logged, but unsigned or invalid requests are still accepted — so existing clients and the official conformance suite are unaffected (no profile fetch happens unless a Signature-Input header is present).
  • The bespoke Request-Signature header stays accepted (optional).
  • ES256 (raw r||s) + Ed25519, the RFC 9421 coverage gate, SSRF-guarded profile fetch (with a localhost carve-out flag for demos), and the spec's error codes.
  • The demo client signs by default with an ephemeral key it publishes from a small local profile server, so the full sign-then-verify loop runs in the happy path.
  • Scope is inbound request verification + client signing; webhook and response signing would follow in a second PR (the spec's "webhooks MUST be signed").

The implementation is built and tested — correctness anchored to the RFC 9421 Appendix B and RFC 9530 test vectors, an explicit DER-must-fail check, and a differential cross-check against an independent RFC 9421 library; ~58 new tests; the official conformance suite still passes 13/13 with it applied.

Branch: https://github.com/vishkaty/samples/tree/feat/rfc9421-signatures — happy to open the PR whenever you'd like.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions