record S-1/N-1 remediation status + the N-4 parenthetical correction
- review 001: §Status carries the remediation status (S-1 + N-1 landed
in e86b8ba, OQ-TLS-09 open, probe permanent) and the N-4 correction
summary; §S-1 remediation-task line updated; §N-1 marked remediated;
§N-4 gains the corrected mechanism chain (rustls 0.23.41/0.23.44 send
[RawPublicKey] iff the resolver's only_raw_public_keys() is true —
no "offers both types" behavior exists; a raw-key client fails
IncorrectCertificateTypeExtension against this verifier; the S-1
probe presents the SPKI under the default X.509 offer instead)
- task fix-accept-any-cert-verifier-posture: drop the placeholder
fill-in lines (Notes/Summary carry the actual record)
- task docs-pin-c1-c4-n3-n4: N-4 work item rewritten from the
corrected chain so the implementing agent does not re-derive it;
references point at the rustls source lines and the probe's
resolver choice
This commit is contained in:
@@ -42,18 +42,39 @@ question):
|
||||
reasoning in the type's doc (one sentence) and close the question
|
||||
— revisit only with a concrete consumer demanding it.
|
||||
4. **N-4** — the cert-type negotiation interaction needs an explicit
|
||||
doc note on `AcceptAnyCertVerifier`: `requires_raw_public_keys()`
|
||||
stays `false` (both cert types accepted), and — the subtle part,
|
||||
verified against rustls 0.23.44 `validate_client_cert_type_extension`
|
||||
in the decomposition session — **a client offering ONLY
|
||||
`RawPublicKey` fails the handshake** with
|
||||
`IncorrectCertificateTypeExtension`; it must offer both
|
||||
`[X509, RawPublicKey]` (or the verifier would have to set
|
||||
`requires_raw_public_keys() == true`). The extracted alknet client
|
||||
resolver offers both types, which is why production works. Without
|
||||
the note, the next reader may "fix" the verifier to `true` and
|
||||
break X.509 clients, or mis-diagnose the raw-only-client failure as
|
||||
a bug.
|
||||
doc note on `AcceptAnyCertVerifier`. **Read the corrected mechanism
|
||||
first** — the review's §N-4 original parenthetical ("alknet's own
|
||||
client resolver offers both types, which is why production works")
|
||||
is inaccurate; the review's §Status block and §N-4 now carry the
|
||||
correction (found during the S-1 remediation, commit `e86b8ba`).
|
||||
The accurate chain, from the rustls sources (0.23.41 AND 0.23.44):
|
||||
- rustls sends `client_certificate_types = [RawPublicKey]` (only)
|
||||
iff the *resolver's* `only_raw_public_keys()` is true
|
||||
(client/hs.rs:331-334 in 0.23.41, :355-358 in 0.23.44) — no
|
||||
"offers both types" behavior exists in either version.
|
||||
- Against `AcceptAnyCertVerifier`
|
||||
(`requires_raw_public_keys() == false`), a client offering only
|
||||
`[RawPublicKey]` hits the `(false, true, false)` arm of
|
||||
`process_cert_type_extension` (server/hs.rs:274-288 in 0.23.44)
|
||||
→ `IncorrectCertificateTypeExtension` → handshake failure.
|
||||
- A client with an X.509-typed resolver (or no resolver) offers no
|
||||
cert-type extension / `[X509]` → the `(false, _, true)` or
|
||||
`(false, false, false)` arm → default X.509 → works, and the
|
||||
server passes presented bytes through unparsed to a custom
|
||||
`verify_client_cert`.
|
||||
- So `requires_raw_public_keys()` must stay `false` (do not "fix"
|
||||
it to `true` — that would break X.509 clients), and the doc note
|
||||
must state that a raw-key *client* resolver makes rustls offer
|
||||
`[RawPublicKey]` only, which this verifier rejects
|
||||
(fail-closed, not a downgrade). Note the S-1 doc on the same
|
||||
type (landed, commit `e86b8ba`) already carries the no-pop
|
||||
section; add the negotiation note as a sibling section, and note
|
||||
that a raw-key *server* presentation (`RawKeyCertResolver`,
|
||||
`only_raw_public_keys() == true` on the server cert side) is a
|
||||
different knob (the `server_certificate_types` extension) that
|
||||
is unaffected. Without the note, the next reader may "fix" the
|
||||
verifier to `true` and break X.509 clients, or mis-diagnose the
|
||||
raw-only-client failure as a bug.
|
||||
|
||||
## Work
|
||||
|
||||
@@ -87,10 +108,18 @@ question):
|
||||
## References
|
||||
|
||||
- docs/reviews/001-implementation-review.md §C-1, §C-4, §N-3, §N-4
|
||||
(§N-4 — read the correction block; the original parenthetical is
|
||||
inaccurate), and the §Status block (the correction summary)
|
||||
- src/server.rs:226-256, src/client.rs:225-236, src/credentials.rs:35-39,
|
||||
src/identity.rs (SelfSigned doc)
|
||||
- rustls 0.23.44 `server/hs.rs` `validate_client_cert_type_extension`
|
||||
(the negotiation table N-4 documents)
|
||||
- rustls 0.23.44 `server/hs.rs` `process_cert_type_extension`
|
||||
(server/hs.rs:263-288 — the `(requires_raw_keys, offers_raw,
|
||||
offers_x509)` negotiation table N-4 documents) and
|
||||
`client/hs.rs:350-358` (the `[RawPublicKey]`-only offer rule) —
|
||||
both pinned in rustls 0.23.41 too (client/hs.rs:326-334)
|
||||
- tests/impersonation_posture.rs (the S-1 probe — its fixed resolver
|
||||
pins `only_raw_public_keys() == false` for the X.509-typed offer;
|
||||
do not confuse that with a raw-key client resolver)
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -109,8 +109,6 @@ finding, not a code-change mandate. What's missing:
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
- The probe used a tokio duplex pair + `TlsConnector`/`TlsAcceptor`
|
||||
(tokio-rustls, `tcp`-gated) rather than raw `complete_io` — same
|
||||
shape, cleaner await-based flow. The attacker client uses a
|
||||
@@ -139,8 +137,6 @@ finding, not a code-change mandate. What's missing:
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
|
||||
**Landed (this task):**
|
||||
|
||||
1. `src/server.rs` — `AcceptAnyCertVerifier` doc rewritten: a
|
||||
|
||||
Reference in New Issue
Block a user