Repository navigation
fix(server)!: attestation x5c key bounds, HAIP anchor interop, resource and embedder-binding fixes - #775
Merged
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
X5CAttesterChain parsed the certificates of an attestation's x5c and path-built over them before anything in the request was authenticated. crypto/x509 bounds neither an RSA modulus nor its exponent, so a certificate with a 31,744-bit modulus and exponent 2^31-1 cost about 60 ms of CPU per unauthenticated token request. Every x5c certificate's key is now held to the limits v0.63.0 set for any other RSA key a caller supplies, at most 4096 bits and exponent 65537, through the new internal jose.ValidateCallerCertificateKey, before isSelfSigned or chain verification uses it. Configured anchors are not limited. BREAKING CHANGE: X5CAttesterChain refuses with invalid_client an attestation whose x5c carries an RSA key over 4096 bits or with an exponent other than 65537, on the signing certificate or an intermediate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HAIP 1.0 §4.4.1 has the wallet leave the trust anchor out of x5c; it
asks nothing of the verifier. X5CAttesterChain refused any x5c that
carried a certificate for the anchor a verified chain ended at, so a
conformant x5c [leaf, intermediate] verified against anchors {root} but
was refused once the server also listed the intermediate as an anchor,
which a wallet has no way to know.
An attestation is now refused only when every verified chain ends at an
anchor x5c carries itself (compared by subject and public key, as
before); one chain ending at an anchor the wallet didn't send is enough.
A self-signed certificate below the leaf is still refused. The native
wallet guide no longer says HAIP requires the server to refuse, and the
v0.66.0 and v0.68.0 upgrade notes say what changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… auth method A request carrying attestation headers together with a client_assertion or client_assertion_type stays refused with invalid_request (RFC 6749 §2.3), so an assertion naming another client is never ignored in favour of the attestation. The attestation-based client authentication draft-12 §7.6 also allows an attestation as an additional signal beside another method; that use is not supported, and the docs now say so: Config.AttestationBasedClientAuthentication, authenticateClient and the native wallet guide. The error_description now says the attestation can't be combined with another client authentication method, rather than only that the request uses more than one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hen unsupported RFC 6749 §3.1 and §3.2: "Parameters sent without a value MUST be treated as if they were omitted from the request". An empty "resource" parameter at PAR or the token endpoint was refused with invalid_target; it is now dropped, alone or beside non-empty ones, as every other empty parameter already is. TokenEndpointRequest.Resources drops it too. With resource indicators disabled (neither Config.Resources nor a ResourcePolicy), one "resource" was ignored but a repeated one was refused with invalid_request as a duplicate parameter. RFC 8707 §2 lets a client repeat it, and an unrecognized parameter is ignored (RFC 6749 §3.1, §3.2), so it is now ignored however many times it appears. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… expiry IssueAccessToken documented that it accepts only a TokenBinding VerifyTokenRequestBinding returned, but checked only the client it was verified for: an embedder that changed the exported Thumbprint got an access token whose cnf named a key that never proved possession. In the same way, an AttestedClient whose exported AttestationExpiresAt was moved on passed the check that refuses a Client kept from an earlier request. TokenBinding now keeps an unexported copy of the thumbprint it verified, and AttestedClient of the expiry it verified. IssueAccessToken refuses a binding whose Thumbprint differs, and IssueAccessToken and IssueRefreshToken refuse a Client whose AttestationExpiresAt differs and judge the attestation's expiry by the verified copy. The exported fields are unchanged. BREAKING CHANGE: IssueAccessToken refuses with server_error a TokenBinding whose Thumbprint was changed after VerifyTokenRequestBinding returned it, and IssueAccessToken and IssueRefreshToken refuse an AttestedClient whose AttestationExpiresAt was changed after AuthenticateAttestedClient returned it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Config.Extensions said a parameter without a registered Definition is rejected, and Config.RAR described the same default-reject stance. The server ignores and strips such a parameter, as RFC 6749 §3.1 requires and extension.Registry.Parse documents. Only "authorization_details" is refused without Config.RAR, with invalid_authorization_details. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OIDC Core §5.5.1 releases a claim requested with "value" or "values" only when it equals one of them. internal/claimvalues decoded both sides into float64, so integers above 2^53 that differ compared equal, and a claim was released for a value the client didn't request. Numbers are now compared by the value their text denotes, reduced to sign, significant digits and a big.Int decimal exponent, so "100", "1e2" and "100.0" stay equal while 9007199254740993 and 9007199254740992 differ, without expanding a large exponent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The binding_message section's code block shared its closing fence with the next section's when both were added under v0.69.0, and lost it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
osanderson
force-pushed
the
fix/attestation-standards
branch
from
November 2, 2026 06:49
66c5d1b to
a1248f3
Compare
|
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.



Attestation, resource indicator and embedder-binding fixes from the 2026-11-02 review.
Breaking (UPGRADING.md
## v0.69.0):x5cRSA keys are bounded.X5CAttesterChainpath-built over the caller'sx5ccertificates before anything in the request was authenticated, andcrypto/x509bounds neither an RSA modulus nor its exponent: a 31,744-bit modulus with e = 2^31-1 cost about 60 ms of CPU per unauthenticated token request. Everyx5ccertificate's key is now held to the existing caller-key limits from internal/jose (at most 4096 bits, exponent 65537) beforeisSelfSignedor chain verification. Configured anchors are not limited. Other certificate paths were checked: mTLS client authentication only verifies a single leaf against configured pools, federation and JWKx5care only thumbprinted, and JWSx5cheaders aren't used for key resolution.IssueAccessToken/IssueRefreshTokenrefuse edited embedder inputs.TokenBindingnow keeps an unexported copy of the thumbprint it verified, andAttestedClientof the attestation expiry, so an editedThumbprintorAttestationExpiresAtis refused, as the doc comments already said. The exported fields are unchanged.Non-breaking:
x5cintermediate that is also an anchor. HAIP 1.0 §4.4.1 puts the "exclude the trust anchor" rule on the wallet. A conformantx5c = [leaf, intermediate]was refused once the server also listed the intermediate as an anchor. An attestation is now refused only when every verified chain ends at an anchorx5citself carries (same subject + SPKI comparison as before). A self-signed certificate below the leaf is still refused. The native wallet guide is corrected, and the v0.66.0 and v0.68.0 upgrade notes each get a short "relaxed in v0.69.0" note.client_assertion. This is still refused (RFC 6749 §2.3). The docs now say that draft-12 §7.6's use of an attestation as an additional signal isn't supported, and theerror_descriptionsays the attestation can't be combined with another client authentication method.resource=is treated as omitted (RFC 6749 §3.1/§3.2) at PAR and the token endpoint, including next to non-empty values. With resource indicators off,resourceis ignored however many times it appears. Before, two copies gaveinvalid_request.value/valuesequality. Numbers are compared exactly by the value their text denotes, not via float64, so integers above 2^53 that differ no longer match.Config.ExtensionsandConfig.RARnow say unregistered parameters are ignored and stripped, not rejected.Regression tests cover each item and fail without the fix.
🤖 Generated with Claude Code