fix(verify): require a trusted key, enforce freshness, validate JWK type#73
Merged
Conversation
Harden verify_record so it fails closed: - Require an explicit trusted key. verify_record no longer falls back to the key embedded in record.cnf.jwk by default, so a record can no longer vouch for itself. The embedded-key path is now gated behind an explicit allow_embedded_key=True opt-in that emits a loud UserWarning; with no trusted key and the opt-in off, it raises ValueError. - Enforce freshness. Add a max_age_seconds check (default 86400 = 24h, configurable, None to disable) against iat, and an optional constant-time expected_nonce comparison against runtime.nonce. Stale or mismatched records fail verification. - Validate JWK type before key reconstruction. Assert kty=="OKP" and crv=="Ed25519" before building an Ed25519PublicKey, so an EC key is never silently treated as Ed25519. - Robust base64url decode. Factor padding into one helper that raises ValueError (not binascii.Error) on malformed input, applied to both the signature and the JWK x field. Tests updated to pass a trusted key (or opt in), plus new tests for the no-key, wrong-key, expired, non-OKP, nonce, and malformed-signature paths. Doc code examples updated to verify against a trusted key. RFC 8785/JCS canonicalization and revocation enforcement are out of scope and tracked separately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hardens
verify_record(and the surrounding signing module) so that signature verification fails closed. Four changes:Require an explicit trusted key.
verify_recordpreviously fell back to the key embedded inrecord.cnf.jwk, which means a record could vouch for itself. The trusted key/JWK is now required. The embedded-key path is gated behind an explicitallow_embedded_key=Trueopt-in that emits a loudUserWarning(it proves only internal consistency, not authenticity). With no trusted key and the opt-in off, the function raisesValueError.Enforce freshness. Adds a
max_age_secondscheck (default86400= 24h, configurable; passNoneto disable) againstiat, and an optionalexpected_noncecompared in constant time againstruntime.nonce. Stale records or nonce mismatches fail verification.Validate JWK type before key reconstruction. Asserts
kty == "OKP"andcrv == "Ed25519"before building anEd25519PublicKey, so a mismatched key type (e.g. an EC key) is rejected explicitly rather than silently treated as Ed25519.Robust base64url decode. Factors the padding logic into a single helper that raises
ValueError(notbinascii.Error) on malformed input, applied to both the signature and the JWKxfield.API note:
verify_recordgains keyword-only paramsallow_embedded_key: bool = False,max_age_seconds: int | None = 86400, andexpected_nonce: str | None = None. Callers that relied on the implicit embedded-key fallback must now pass a trusted key or setallow_embedded_key=True.Tests: existing tests updated to pass a trusted key (or opt in). New tests cover: no trusted key raises; record signed by key A does not verify against key B; expired record fails; non-OKP JWK rejected; nonce match/mismatch; malformed signature.
pytest -q(65 passed) andruff check src/ tests/ --select E,F,W --ignore E501both green.RFC 8785/JCS canonicalization and revocation enforcement are out of scope here and tracked separately.
🤖 Generated with Claude Code