Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
---
|
|
|
|
|
id: KEY-WP-0019
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "Verify upstream Authelia ID tokens"
|
|
|
|
|
domain: infotech
|
|
|
|
|
repo: key-cape
|
2026-09-07 09:01:16 +02:00
|
|
|
status: finished
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
owner: claude
|
|
|
|
|
topic_slug: upstream-provider-token-verification
|
|
|
|
|
created: "2026-09-07"
|
|
|
|
|
updated: "2026-09-07"
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_workstream_id: "87ea18ea-dc60-52ce-baf4-476b46aa06f9"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Closes the remaining half of gap G01 in
|
|
|
|
|
`history/2026-09-05-011726-scope-intent-assessment.md`. The Authelia adapter
|
|
|
|
|
decodes upstream ID-token claims without verifying the signature, issuer,
|
|
|
|
|
audience or expiry, justified in a comment by a server-to-server TLS boundary.
|
|
|
|
|
|
|
|
|
|
**Operator decision (2026-09-07, Bernd):** verify the token itself. The
|
|
|
|
|
KeyCape→Authelia hop is to be HTTPS as defence in depth, but KeyCape will not
|
|
|
|
|
monitor, check or gate on that — transport enforcement is friction without
|
|
|
|
|
protection value here, and a check that must be configured correctly to help is
|
|
|
|
|
itself a failure mode. Verification is chosen precisely because it does not
|
|
|
|
|
depend on the transport being what we believe it is. No HTTPS validation, opt-in
|
|
|
|
|
flag or transport telemetry is to be added.
|
|
|
|
|
|
|
|
|
|
## Extract a shared RS256/JWKS verifier
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0019-T01
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_task_id: "68c1b099-96b4-5065-a4be-8592438a0ca9"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`internal/authclient` already contains a strict RS256 verifier — kid required,
|
|
|
|
|
no `crit`, RSA-only keys of at least 2048 bits with an odd exponent. The upstream
|
|
|
|
|
verification needs the same rules. Duplicating security-critical verification is
|
|
|
|
|
how two copies drift and one silently misses a fix, so extract the reusable half
|
|
|
|
|
into `internal/jose`: strict JWK-set parsing and signature verification returning
|
|
|
|
|
claims. Claim policy stays with each caller, whose audience, nonce and issuer
|
|
|
|
|
rules genuinely differ.
|
|
|
|
|
|
|
|
|
|
Added `internal/jose`: strict JWK-set parsing (RSA signing keys only, at least
|
|
|
|
|
2048 bits, odd exponent 3 or greater, no duplicate key ids) and RS256 signature
|
|
|
|
|
verification returning claims. All failures collapse to one `ErrVerification`
|
|
|
|
|
so a caller cannot leak which check failed back to whoever supplied the token.
|
|
|
|
|
`authclient` is not yet migrated onto it — see T05.
|
|
|
|
|
|
|
|
|
|
## Verify the Authelia ID token
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0019-T02
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_task_id: "8105030b-c91f-5a40-a221-4a38c8531e1c"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Before trusting any claim from the upstream ID token: verify the RS256 signature
|
|
|
|
|
against Authelia's published keys, require the issuer Authelia advertises, require
|
|
|
|
|
KeyCape's own client ID in the audience, and reject expired or not-yet-valid
|
|
|
|
|
tokens. Fail closed — an unavailable or unparseable key set denies the login
|
|
|
|
|
rather than falling back to unverified claims. Resolve Authelia's metadata and
|
|
|
|
|
key set from the server-side token base URL so a split-horizon deployment, where
|
|
|
|
|
the advertised public URL is not reachable from KeyCape, still verifies; allow
|
|
|
|
|
explicit issuer and JWKS overrides for deployments where that inference is wrong.
|
|
|
|
|
Refresh the key set once on an unknown key id so provider key rotation does not
|
|
|
|
|
require a KeyCape restart. Replace the comment claiming the TLS boundary as
|
|
|
|
|
justification.
|
|
|
|
|
|
|
|
|
|
`idTokenVerifier` in the adapter resolves the issuer and JWKS path from the
|
|
|
|
|
provider's discovery document, rebasing the advertised `jwks_uri` path onto the
|
|
|
|
|
server-side token base URL so split-horizon deployments resolve, with
|
|
|
|
|
`issuer`/`jwksUrl` config overrides where that inference is wrong. Key sets are
|
|
|
|
|
cached and refetched once on an unknown key id. `parseIDTokenClaims` remains for
|
|
|
|
|
diagnostics but is documented as outside the authentication path.
|
|
|
|
|
|
|
|
|
|
## Prove the rejections
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0019-T03
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_task_id: "163f64dd-aa87-5ce3-b3be-d134fa993eb6"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Negative tests per condition: forged signature, `alg: none` and other algorithms,
|
|
|
|
|
unknown key id, wrong issuer, missing and wrong audience, expired token, future
|
|
|
|
|
`iat`/`nbf`, malformed key set, and an unreachable JWKS endpoint. A positive case
|
|
|
|
|
must confirm a genuine token still authenticates, and a rotation case that a new
|
|
|
|
|
key id is picked up after one refresh.
|
|
|
|
|
|
|
|
|
|
Thirteen rejection cases in `verify_test.go` plus the algorithm and rotation
|
|
|
|
|
cases. Confirmed they catch the original defect rather than merely passing: with
|
|
|
|
|
the unverified parse restored, all fifteen fail. The existing adapter tests now
|
|
|
|
|
build genuinely signed tokens against a fixture provider, so they exercise the
|
|
|
|
|
real verification path instead of being routed around it.
|
|
|
|
|
|
|
|
|
|
## Reconcile the records
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0019-T04
|
|
|
|
|
status: done
|
|
|
|
|
priority: medium
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_task_id: "8a208092-7e85-5ad9-a8c4-0dddc66aaaee"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Update `SCOPE.md` and G01's status in the assessment to state that upstream
|
|
|
|
|
provider tokens are now verified independently of transport, and record the
|
|
|
|
|
operator decision and its reasoning so the absence of transport enforcement reads
|
|
|
|
|
as a choice rather than an oversight. G01 closes with this; complete profile
|
|
|
|
|
conformance is still not claimed.
|
|
|
|
|
|
|
|
|
|
SCOPE.md and G01's status record the verification and the operator decision,
|
|
|
|
|
including why no transport enforcement exists, so its absence reads as a choice.
|
|
|
|
|
|
|
|
|
|
## Consolidate the caller verifier
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0019-T05
|
2026-09-07 09:01:16 +02:00
|
|
|
status: done
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
priority: medium
|
2026-09-07 08:52:28 +02:00
|
|
|
state_hub_task_id: "0dc909fe-1772-5816-9e11-dbe7664a4e1f"
|
Verify upstream Authelia ID tokens
Closes the remaining half of gap G01. The adapter decoded upstream ID-token
claims without verifying anything, justified in a comment by a server-to-server
TLS boundary that nothing enforced.
Operator decision: verify the token rather than police the transport. The hop is
to be HTTPS as defence in depth, but KeyCape does not monitor, check or gate on
that -- a transport check helps only when it is configured correctly, which is
the assumption it was meant to remove. Verification holds regardless of how the
token arrived, so no HTTPS validation or opt-in flag is added.
HandleCallback now verifies the RS256 signature against Authelia's published
keys, the issuer Authelia advertises, KeyCape's own client ID in the audience,
and a sane validity window, before any claim is trusted. It fails closed: an
unreachable or unparseable key set denies the login. The advertised jwks_uri
path is rebased onto the server-side token base URL so split-horizon deployments
resolve, with config overrides where that inference is wrong, and an unknown key
id triggers one refresh so provider rotation needs no restart.
The reusable half lives in internal/jose rather than being copied from
authclient's verifier, since duplicated verification is how two copies drift and
one misses a fix. Migrating authclient onto it is tracked as KEY-WP-0019-T05,
kept separate so it does not destabilise a tested path in this change.
Thirteen rejection cases plus algorithm and rotation coverage; with the
unverified parse restored all fifteen fail, so they test the fix rather than
merely passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-07 08:51:42 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Move `internal/authclient`'s inline verification onto `internal/jose` so one
|
|
|
|
|
implementation serves both paths. Kept separate from T01/T02 deliberately: the
|
|
|
|
|
caller verifier is a tested security path, and destabilising it in the same
|
|
|
|
|
change that introduces upstream verification would confuse the evidence for both.
|
2026-09-07 09:01:16 +02:00
|
|
|
|
|
|
|
|
`Client.Verify` now fetches the raw key set and delegates parsing and signature
|
|
|
|
|
checking to `internal/jose`, keeping its own claim policy — audience and nonce
|
|
|
|
|
bindings are the caller's and cannot live in a shared verifier. Its existing
|
|
|
|
|
tests pass unchanged, which is the point: the migration preserved behaviour.
|
|
|
|
|
|
|
|
|
|
One deliberate strictness increase: a key set containing any malformed RSA
|
|
|
|
|
signing key is now refused outright, where the previous code would have used a
|
|
|
|
|
good key alongside a bad one. KeyCape's own `/jwks` publishes a single key, so
|
|
|
|
|
this affects no current deployment.
|
|
|
|
|
|
|
|
|
|
Also added direct tests for `internal/jose` (17 cases). It is now the single
|
|
|
|
|
verifier behind both paths, so testing it only through its callers would leave
|
|
|
|
|
its edges — duplicate key ids, `crit`, even exponents, undersized moduli — to be
|
|
|
|
|
covered by accident.
|
2026-09-07 09:05:16 +02:00
|
|
|
|
|
|
|
|
Follow-on evidence for the same task: "existing tests pass unchanged" shows the
|
|
|
|
|
move preserved behaviour, not that the behaviour is checked, so the check was
|
|
|
|
|
made explicit. Disabling the RSA comparison in `jose.Verify` fails both callers'
|
|
|
|
|
suites, which establishes the shared verifier is load-bearing on each path.
|
|
|
|
|
Added two caller-side cases the existing tamper case cannot reach, since it
|
|
|
|
|
alters signature bytes for a key that is legitimately published: a structurally
|
|
|
|
|
valid token signed by an unpublished key under a published kid, which fails only
|
|
|
|
|
if key selection is bound to the key set, and an undersized modulus in the
|
|
|
|
|
published set, which must deny rather than fall through to the claims.
|