task 1: S-1 remediation — no-pop posture doc + OQ-TLS-09 + permanent impersonation pin
- AcceptAnyCertVerifier doc: the presented CertificateVerify signature
is not verified (no proof-of-possession) — the server-extracted
fingerprint is attacker-suppliable from observed public cert/SPKI
bytes; states the two safe patterns (auth-layer challenge-response /
a verifying verifier) and points at OQ-TLS-09
- FingerprintPinVerifier doc (N-1): fixed the "stolen-but-stale
fingerprint" phrasing (the cert is presented fresh each handshake;
the signature check defeats a stolen/observed cert used by a party
without the private key) and added the server-verifier cross-reference
- OQ-TLS-09 recorded (open, high): which layer owns server-path
proof-of-possession — three options; deferral noted (needs the
auth-layer design or an API call before the first consumer)
- tests/impersonation_posture.rs (tcp-gated): the S-1 probe made
permanent, both variants — X.509 victim cert + attacker key and RFC
7250 victim SPKI + attacker key complete the handshake, application
data flows, and the server extracts the victim's fingerprint; any
future pop change must fail/update this test with the doc + OQ
- server.md / client.md synced with the same posture
- task note: the review's N-4 parenthetical ("alknet's client resolver
offers both types") is inaccurate — rustls 0.23.41/0.23.44 offer
[RawPublicKey] iff the resolver's only_raw_public_keys() is true;
task 6 should write N-4 from the rustls sources
Verified: cargo test 68 default / 77 all-features (+2) green; clippy
-D warnings clean (default + all-features); fmt clean; cargo doc
--no-deps warning-free
This commit is contained in:
@@ -21,6 +21,7 @@ are authoritative; the Phase 0 doc's statuses are the historical record.
|
||||
| OQ-TLS-06 | ACME task shutdown surface | resolved (detached-only for v1) | low |
|
||||
| OQ-TLS-07 | iroh key surface | **resolved** (ADR-005, byte access pinned) | low |
|
||||
| OQ-TLS-08 | `quinn` → `noq` feature rename | **resolved** (ADR-003) | high |
|
||||
| OQ-TLS-09 | Server-path proof-of-possession | **open** | high |
|
||||
|
||||
## Identity & types
|
||||
|
||||
@@ -104,6 +105,44 @@ are authoritative; the Phase 0 doc's statuses are the historical record.
|
||||
[ADR-003](decisions/003-noq-replaces-quinn.md).
|
||||
- **Cross-references**: ADR-002, ADR-003, ADR-004
|
||||
|
||||
### OQ-TLS-09: Which layer owns proof-of-possession on the server path?
|
||||
|
||||
- **Origin**: docs/reviews/001-implementation-review.md §S-1 (the
|
||||
impersonation probe: a handshake with the victim's cert bytes + an
|
||||
attacker signer completes, and the server extracts the victim's
|
||||
fingerprint)
|
||||
- **Status**: open (recorded 2026-09-10)
|
||||
- **Priority**: high
|
||||
- **Question**: `AcceptAnyCertVerifier` never checks the client's
|
||||
CertificateVerify signature — the presented identity is spoofable by
|
||||
anyone holding the public cert/SPKI bytes, and the auth layer cannot
|
||||
detect it (the fingerprint it is handed *is* the victim's). alknet
|
||||
ADR-034 inherited the request-but-don't-require shape without
|
||||
recording this property. Who enforces possession?
|
||||
- **Options**:
|
||||
- **(a) Keep request-but-don't-require; the auth layer owns
|
||||
challenge-response** over the established channel, bound to the
|
||||
presented public key. No crate change; the S-1 doc note on
|
||||
`AcceptAnyCertVerifier` is the honest description until then.
|
||||
- **(b) Add a `VerifyPresentedCertVerifier` sibling**
|
||||
(request-and-verify): same nine-scheme list, permissive
|
||||
`verify_client_cert`, signature methods delegate to
|
||||
`rustls::crypto::verify_tls{12,13}_signature(_with_raw_key)` — the
|
||||
routing the client-side `FingerprintPinVerifier` already
|
||||
implements. Additive; must land before the first consumer (an API
|
||||
shape decision).
|
||||
- **(c) Make the auth layer's fingerprint resolution
|
||||
possession-checked** (a possession proof accompanies each
|
||||
fingerprint resolution). Cross-crate; the auth layer does not exist
|
||||
yet.
|
||||
- **Constraints**: the spoofable posture is pinned by
|
||||
`tests/impersonation_posture.rs` (both cert types) — any decision
|
||||
must fail or update that test together with the
|
||||
`AcceptAnyCertVerifier` doc note.
|
||||
- **Cross-references**: src/server.rs (`AcceptAnyCertVerifier`),
|
||||
src/client.rs (`FingerprintPinVerifier`),
|
||||
docs/reviews/001-implementation-review.md §S-1, alknet ADR-034
|
||||
|
||||
## Quality / process
|
||||
|
||||
### OQ-TLS-05: Test surface for the invariants
|
||||
@@ -133,5 +172,6 @@ are authoritative; the Phase 0 doc's statuses are the historical record.
|
||||
|
||||
## Deferred / Blocked
|
||||
|
||||
(none — all promoted OQs are resolved; new OQs added during review
|
||||
land here with their deferral half per `docs/sdd_process.md`)
|
||||
- OQ-TLS-09 (server-path proof-of-possession): open by design — the
|
||||
decision needs the rewrite's auth-layer design in hand (option (c))
|
||||
or an API-shape call before the first consumer (option (b)).
|
||||
Reference in New Issue
Block a user