review-001 decomposition: 6 remediation tasks from verified findings
Verify every review-001 finding before decomposition: - S-1 re-confirmed by fresh executable probe (X.509 + raw-key impersonation both complete the handshake with the victim's fingerprint extracted server-side) - U-2/U-3 uncovered-line inventory re-derived from cargo llvm-cov (--all-features); matches Part C exactly - rcgen 1975/4096 defaults, rustls cert-type negotiation arm, packaging list, doc texts: all verified against sources Tasks (all verified, none speculative): - fix-accept-any-cert-verifier-posture (S-1 + N-1 + OQ-TLS-09 + probe) - handshake-tests (U-3 suites 1-3; suite 4 lives in the S-1 task) - coverage-cheap-closes (U-2's seven groups) - acme-event-loop-test (U-1; depends on coverage-cheap-closes for the tracing-capture pattern) - config-validation-and-trivia (C-2 ALPN dedup, C-3 empty-domains, N-6 excludes, N-7 https doc line) - docs-pin-c1-c4-n3-n4 (C-1, C-4, N-3 decision note, N-4 negotiation note) Graph: acme-event-loop-test is generation 2; the rest run in generation 1. taskgraph validate: 14 tasks, no cycles. Verification: cargo test (default + --all-features) green before and after; probe file deleted after its run.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
---
|
||||
id: docs-pin-c1-c4-n3-n4
|
||||
name: Docs + pin batch — self-signed validity, fingerprint pin format-exactness, Clone-under-no-acme, cert-type negotiation note (C-1, C-4, N-3, N-4)
|
||||
status: pending
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [docs, review-001, c1, c4, n3, n4]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Four doc/doc+pin findings that close as rustdoc (plus one decided
|
||||
question):
|
||||
|
||||
1. **C-1** — `generate_self_signed_cert()` produces a cert valid
|
||||
1975→4096 (rcgen's `CertificateParams::default()` — verified
|
||||
against rcgen 0.13.2 source, certificate.rs:94-96) and has no SANs.
|
||||
"Dev cert" silently meaning "never expires" is a documented-behavior
|
||||
gap. One doc line on `generate_self_signed_cert` (and
|
||||
`SelfSignedCert`): the generated cert never expires in practice,
|
||||
carries no SANs, and pins against CA verification by design; if a
|
||||
tighter validity is ever wanted, `not_before`/`not_after` are
|
||||
additive params.
|
||||
2. **C-4** — `RemoteIdentity::fingerprint` accepts any string and the
|
||||
pin comparison is exact-string (src/client.rs:272): uppercase-hex
|
||||
pins, `sha256:` lowercase prefix, and cross-prefix pins
|
||||
(`SHA256:`-of-an-ed25519-remote) construct fine and reject at
|
||||
handshake — fail-closed, never a downgrade, but a config-author
|
||||
trap. Doc line on `RemoteIdentity::fingerprint` (and/or
|
||||
`FingerprintPinVerifier`): pins must be produced by
|
||||
`fingerprint_from_cert_der` — case- and format-exact
|
||||
(`ed25519:<lowercase hex>` / `SHA256:<lowercase hex>`); malformed
|
||||
pins fail closed at handshake.
|
||||
3. **N-3** — `TlsServerConfig` is not `Clone` even under
|
||||
`default = []` where the struct has no `JoinHandle` field. The
|
||||
all-features posture is what the API freeze pins (conditional
|
||||
`Clone` is its own trap: an API difference between feature
|
||||
configurations). Decision: keep non-Clone for v1; record the
|
||||
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.
|
||||
|
||||
## Work
|
||||
|
||||
1. C-1 doc lines (`generate_self_signed_cert` + `SelfSignedCert`).
|
||||
2. C-4 doc lines (`RemoteIdentity::fingerprint`,
|
||||
`FingerprintPinVerifier` — format-exactness + fail-closed).
|
||||
3. N-3: the one-sentence decision note on `TlsServerConfig`'s doc;
|
||||
close N-3 in the review's finding list (no code change).
|
||||
4. N-4: the negotiation note on `AcceptAnyCertVerifier`'s doc. If
|
||||
desired, add a pinned unit test asserting
|
||||
`requires_raw_public_keys() == false` stays default (it's a trait
|
||||
default — the test just documents the choice).
|
||||
5. Cross-check the review's finding numbering so each doc change
|
||||
cites its finding.
|
||||
|
||||
## Verification
|
||||
|
||||
- [ ] All four doc notes exist and render (`cargo doc --no-deps`
|
||||
warning-free)
|
||||
- [ ] The N-3 decision is recorded (doc + this task's Summary)
|
||||
- [ ] No code-behavior change beyond an optional unit pin
|
||||
- [ ] `cargo test`, clippy, fmt, doc green
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] A config author reading the rustdoc cannot mis-case a pin, pin
|
||||
the wrong prefix, or expect a never-expiring dev cert to expire
|
||||
- [ ] The raw-only-client negotiation trap is documented before a
|
||||
consumer hits it
|
||||
|
||||
## References
|
||||
|
||||
- docs/reviews/001-implementation-review.md §C-1, §C-4, §N-3, §N-4
|
||||
- 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)
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
Reference in New Issue
Block a user