Skip to content

Signatures: Add basic support for RFC-9421 #1849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: trunk
Choose a base branch
from
Open

Conversation

obenland
Copy link
Member

@obenland obenland commented Jun 23, 2025

Fixes #1808.

Proposed changes:

  • Refactored the signature verification logic in Signature::verify_http_signature to delegate to new standard-specific classes.
  • Added Draft_Cavage_Signature and Http_Message_Signature classes implementing a new Signature_Standard interface, supporting both the legacy draft-cavage and new HTTP Message Signature (RFC 9421) standards.
  • Deprecated and stubbed out legacy parsing and verification helpers in class-signature.php.

Other information:

  • Have you written new tests for your changes, if applicable?

Testing instructions:

  • No one is using the new standard yet, so unit tests probably suffice.
  • Apply the PR to a test site that's accessible from the internet.
  • Make sure receiving activities still works as expected.

Changelog entry

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Added - for new features
  • Changed - for changes in existing functionality
  • Deprecated - for soon-to-be removed features
  • Removed - for now removed features
  • Fixed - for any bug fixes
  • Security - in case of vulnerabilities

Message

Added basic support for RFC-9421 style signatures for incoming activities.

obenland added 2 commits June 22, 2025 11:53
Refactored the signature verification logic in Signature::verify_http_signature to delegate to new standard-specific classes. Added Draft_Cavage_Signature and Http_Message_Signature classes implementing a new Signature_Standard interface, supporting both the legacy draft-cavage and new HTTP Message Signature (RFC 9421) standards. Deprecated and stubbed out legacy parsing and verification helpers in class-signature.php. This improves maintainability and prepares for broader signature standard support.
Refactored the signature verification logic to support multiple signature labels by parsing and verifying each label individually. Extracted parsing and verification steps into dedicated private methods for better modularity and maintainability. Improved error handling and signature base string construction.
obenland added 7 commits June 23, 2025 12:52
Replaces unqualified WP_Error references with fully qualified \WP_Error in the Signature class.
Renamed class-draft-cavenage-signature.php to class-draft-cavage-signature.php to correct a typo. Updated date header handling for better clarity and reliability, and fixed regex modifiers for 'created' and 'expires' fields.
Moved digest verification logic into a new private method verify_content_digest, which now supports the Content-Digest header with multiple algorithms.
This update adds handling for the '@scheme' and '@request-target' pseudo-headers in the HTTP message signature base construction. It also improves query string handling and ensures correct formatting of signature parameters, quoting non-numeric values as needed.
Adds support for the @query-param component in signature base string construction and ensures all components are quoted in the @signature-params field. Also updates parameter quoting to properly escape backslashes and double quotes per RFC 9421.
@obenland
Copy link
Member Author

Done:

  • Parsing and verifying Signature-Input and Signature headers.
  • Dynamic label support (e.g., @method, @target-uri, etc.).
  • Parameter support (alg=, created=, expires=, nonce=, keyid=).
  • Canonicalization of headers (whitespace folding and trimming).
  • Digest validation.
  • Multiple signature label support (e.g., sig1=, sig2=).
  • Signature string composition separated out.
  • Algorithm resolution based on alg and key details (with PHP version check).

Skipped for now:

  • Structured field parsing
  • Nonce uniqueness tracking

What do you think @mediaformat?

obenland added 6 commits June 23, 2025 17:44
Introduced a call to reset the $_SERVER superglobal in tear_down to ensure test isolation. Also set specific $_SERVER values in the signature header test to better simulate HTTP request context.
Refines parsing of signature components to support query parameters per RFC-9421, updates signature base construction, and enhances test coverage for GET requests with query parameters. Also updates test URIs to use dynamic REST prefixes and namespaces for better compatibility.
@obenland obenland marked this pull request as ready for review June 24, 2025 15:33
@Copilot Copilot AI review requested due to automatic review settings June 24, 2025 15:33
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds modular support for both the legacy Draft Cavage and new RFC-9421 HTTP Message Signature standards by refactoring the centralized verification logic into standard‐specific classes.

  • Delegates signature verification in Signature::verify_http_signature to Draft_Cavage_Signature and Http_Message_Signature via a new Signature_Standard interface.
  • Implements Http_Message_Signature (RFC-9421) and Draft_Cavage_Signature classes, each handling parsing, validation, and verification for their respective standards.
  • Deprecates and stubs out the legacy parsing and verification helpers in class-signature.php.

Reviewed Changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/includes/rest/class-test-signature-verification.php Removed legacy HTTP signature tests; needs replacement for new classes
tests/fixtures/http-signature-keys.json Added key fixtures for EC and RSA variants used by new signature tests
includes/signature/interface-signature-standard.php Introduced Signature_Standard interface for pluggable verification
includes/signature/class-http-message-signature.php Added RFC-9421 HTTP Message Signature implementation
includes/signature/class-draft-cavage-signature.php Added Draft Cavage HTTP Signature implementation
includes/class-signature.php Updated verify_http_signature to dispatch to new standards; stubbed legacy methods
Comments suppressed due to low confidence (2)

includes/class-signature.php:251

  • [nitpick] The variable name $signature shadows the concept of the header and may be confusing; consider renaming it to $verifier or $signature_standard for clarity.
		$signature = isset( $headers['signature_input'] ) ? new Http_Message_Signature() : new Draft_Cavage_Signature();

Co-authored-by: Copilot <[email protected]>
@@ -59,6 +59,7 @@ jobs:
{"path": "includes/class-blocks.php", "label": "[Focus] Editor"},
{"path": "includes/collection", "label": "[Feature] Collections"},
{"path": "includes/rest", "label": "[Feature] REST API"},
{"path": "includes/signature", "label": "[Feature] Signature"},
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
{"path": "includes/signature", "label": "[Feature] Signature"},
{"path": "includes/signature", "label": "[Feature] Signature"},
{"path": "includes/class-signature.php", "label": "[Feature] Signature"},

Copy link
Member Author

Choose a reason for hiding this comment

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

I was planning on moving class-signature.php into /includes/signature in a follow-up PR, would that work for you?

Copy link
Member

Choose a reason for hiding this comment

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

I think best practice is to have the main class (or factory or however you want to call it) in the root and only the special cases in the subfolder, so I quite like the structure as is. that said, we havent't done that with transformers, so it would be at least consistent to move it 🫣

obenland added 4 commits June 25, 2025 10:45
Updated both Draft_Cavage_Signature and Http_Message_Signature classes to consistently use fully qualified PHP function names (e.g., \is_wp_error, \explode, \array_map). Changed several protected methods to private for encapsulation. Moved RSA-PSS algorithm version check into the verify_algorithm method for better separation of concerns and renamed resolve_algorithm to verify_algorithm for clarity.
Moved strtolower call to the start of verify_algorithm to ensure the algorithm string is always compared in lowercase. This prevents case sensitivity issues when matching algorithm names.
@mediaformat
Copy link
Contributor

  • Parsing and verifying Signature-Input and Signature headers.
  • Dynamic label support (e.g., @method, @target-uri, etc.).
  • Parameter support (alg=, created=, expires=, nonce=, keyid=).
  • Canonicalization of headers (whitespace folding and trimming).
  • Digest validation.
  • Multiple signature label support (e.g., sig1=, sig2=).
  • Signature string composition separated out
  • Algorithm resolution based on alg and key details (with PHP version check).

Only looked at the code so far, but looks great!

It was missing wrapping colons.
@obenland
Copy link
Member Author

@pfefferle I think this is ready for another look. Unit tests look firm now and #1858 helped polish out some remaining bugs. As long as legacy signatures still work this should be safe to merge.

@obenland obenland requested a review from pfefferle June 25, 2025 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Upgrade HTTP Message signatures to implement RFC-9421
4 participants