Repository navigation
fix: close the PPID deep-dive findings (pairwise, server, federation) - #656
Merged
Merged
Conversation
LookupInternalSubject authenticated the plaintext EncryptCTR returned, then parsed that same slice. An implementation reusing its output buffer (a pooled HSM or KMS client) could have it overwritten by a concurrent lookup in between, resolving one user's body to another user. The result is now copied, and ReversibleOps documents that implementations must not retain or modify their inputs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SubjectConfig.Derivation let a configuration label a reversible deriver (NewReversible, NewMapping) one-way, so it claimed unlinkability the deriver didn't give, and only the opposite mismatch was refused. Derivation and its pairwise.OneWay and pairwise.Reversible constants are gone: a deployment's pairwise subs are reversible exactly when Dependencies.PairwiseSubjects implements pairwise.Lookup. The built-in constructors now return concrete types, *HMACDeriver, *ReversibleDeriver and *MappingDeriver, so a reversible deriver can be given to a resource server as a pairwise.Lookup without a type assertion. Each reports its key custody through KeyCustody, the declared one or none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NewHMAC and NewReversible accepted any 32 bytes, including a passphrase or a hex or base64 key passed without decoding. A key made entirely of printable text is now refused: 32 random bytes are all text with probability about 4e-14. The published reversible vectors, whose keys are sequential bytes, use an unchecked test constructor. server.New refuses an empty subjects.prefix when pairwise_subjects is one-way and no resolver is set: nothing could then tell a pairwise sub from an internal one, and the signed UserInfo check would sign the internal subject for a pairwise client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NewHMACWith builds the one-way deriver over HMACOps, a single HMAC-SHA-256 operation an HSM or KMS performs with a key it never releases, producing exactly NewHMAC's bodies for the same key. Unlike the reversible construction it needs no raw AES-CTR, so AWS KMS, Google Cloud KMS, Azure Managed HSM, Vault Transit and PKCS#11 HSMs can all hold the key. NewHMAC now runs on the same path. The MAC is checked to be 32 bytes, and failures fail the derivation. The independent generator for the HMAC test vectors is committed beside them, and GETTING_STARTED documents the per-service options. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A set Sector was used verbatim, so "RP.example" and the "rp.example" a client derives from its redirect URIs were different sectors, and a URL such as "https://rp.example/x" was accepted as one, though OpenID Connect Core §8.1's sector is a host. A set Sector must now be a host name (letters, digits, '-', '.', '_', no empty label) and is lowercased like a derived one. The Sector doc also says it is the operator's to set, never a client's: two clients sharing a sector share every user's sub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…estation A client that may authenticate by attestation gets tokens through an embedder's own grant (Server.IssueAccessToken and IssueRefreshToken), with no redirect proving it controls its redirect URIs' host. Deriving its sector from them let it name another relying party's host and receive that relying party's pairwise subs, as CIBA clients could before. Like a CIBA client, it now derives no sector, so a pairwise one must set Sector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… default With a pairwise Config.Subjects.Default and no AutomaticRegistration.SubjectTypes, a Relying Party registering itself through OpenID Federation could ask for public subs and receive the internal subject, opting out of the deployment's privacy choice. An empty AutomaticRegistration.SubjectTypes now offers pairwise only under a pairwise default; listing public widens it explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The startup probe derived one fixed input and checked only the body's form, so a custom Deriver that returned the internal subject, or ignored the sector or the user, passed New. It now also derives the same input again, the same user in a second sector and a second user in the same sector, and refuses a deriver that isn't deterministic, puts the internal subject in the body, or gives a user one body in two sectors or two users one body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A refreshed grant kept the pairwise sub it was issued with, but a resource server and the signed UserInfo check strip the current Config.Subjects Prefix to resolve a sub, so after a prefix change every reversible grant's tokens failed there with invalid_token, contrary to the continuity the docs promised. Each pairwise grant now records the prefix it was issued under, and one issued under another prefix is refused at its next use (refresh, code exchange, CIBA token exchange) with invalid_grant, as grants issued with public subs are under SubjectTypesPairwiseOnly. The client authorizes again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ange SignUserInfoResponse looked a pairwise client's sub up under the client's current sector, so after a sector change it refused the sub an existing grant was issued with, which resource servers still accept (they use the access token's pairwise_sector). Its purpose is a backstop against the internal subject reaching a pairwise client, and a non-empty prefix already shows a well-formed sub isn't one, so the sector-bound lookup now runs only with an empty prefix, where nothing else can tell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s in A client whose sub couldn't be issued, one registered public at a server that issues only pairwise subs, or a pairwise one with no sector or no deriver, passed PAR and the backchannel authentication endpoint, and failed only at completion, after its user had logged in and consented. Both endpoints now refuse it with server_error up front; completion still checks, for a client changed in between. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ration When Config.AutomaticRegistration narrows the subject types federation Relying Parties may ask for, Server.Metadata still advertises everything the server issues, and an Entity Configuration built from it (as both in-repo builders do) told Relying Parties they could ask for types they'd be refused. With automatic registration configured, EntityConfiguration now sets the openid_provider object's subject_types_supported to AutomaticRegistrationSubjectTypes itself, on a copy of the caller's map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ARCHITECTURE: a subject-flow section (type, sector, derivation, continuity, outbound and inbound subs, who may reverse them). - pairwise: only the OP and its own resource servers may hold what reverses a sub (OpenID Connect Core 8.1). - storage: the CIBA pairwise sector is operator-set, departing from CIBA Core's jwks_uri-host sector. - federation: the Entity-host sector is stricter than 8.1; path-scoped tenants on one host share a sector; a sector_identifier_uri from a superior's metadata policy isn't supported either. - server: IDTokenClaims and GrantID mustn't re-identify a pairwise client's user. - GETTING_STARTED: the pairwise example gives every client pairwise subs (SubjectTypesPairwiseOnly); the sector, early refusal and prefix-change notes; NewHMACWith custody. - UPGRADING v0.55.0 and the federation guide: attestation clients, the prefix change, shared hosts, Entity Configuration subject types. - Test comments no longer name the removed pairwise.OneWay/Reversible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeps BeginBackchannelAuthentication within the cognitive-complexity limit after the early pairwise-client refusal was added to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
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.



Closes the pairwise subject (PPID) deep-dive findings in
pairwise,server,storageandfederationbefore v0.55.0. Everything changed here is new in 0.55, so nothing breaks a released API. Theresource/serverresourcefindings are in #655.API changes (all new in 0.55)
SubjectConfig.Derivation,pairwise.Derivation,pairwise.OneWayandpairwise.Reversibleare removed. A deployment's subs can be mapped back exactly when its deriver implementspairwise.Lookup(or aPairwiseSubjectResolveris declared), so the configuration can't claim more unlinkability than the deriver gives. A resolver alongside a reversible deriver is refused.*pairwise.HMACDeriver,*pairwise.ReversibleDeriver,*pairwise.MappingDeriver, each withKeyCustody(). Under production assurance, an undeclared custody fails with "must declare Durable".pairwise.NewHMACWith(HMACOps, ...): the one-way deriver over a key held in an HSM or KMS, with independently generated test vectors.AutomaticRegistration.SubjectTypesleft empty under a pairwise default now offers federation Relying Parties pairwise subs only.Server.EntityConfigurationnow setssubject_types_supportedinopenid_providertoAutomaticRegistrationSubjectTypes()when automatic registration is configured, on a copy of the caller's map.Fixes
Newprobes the deriver across two sectors and two users. It checks that derivation is deterministic, that the sub varies by sector and by user, and that no internal subject appears in the body.ReversibleOpsoutput is copied before it's authenticated. The interface is documented as "don't retain or modify inputs".Sectormust be a host name, and is lowercased.invalid_grantat refresh, code exchange or CIBA token exchange, since resource servers resolve subs under the current prefix.SignUserInfoResponseno longer requires a prefixed sub to resolve under the client's current sector, so a grant's signed UserInfo keeps working after a sector change. The lookup still runs when the prefix is empty.Docs
sector_identifier_uriadded by a superior's policy isn't supported.IDTokenClaims/GrantID: neither may re-identify the user.SubjectTypesPairwiseOnly; plus the one-way HSM/KMS material.pairwise,server,storageandfederationTesting
go vet;go teston Go 1.27 and 1.26.9;golangci-lint(0 issues);-racetests for the examples;🤖 Generated with Claude Code