Resolve the cert-type negotiation gap (review 001 §U-3, OQ-TLS-10) by deviation from alknet: the gap was a defect in the prior art (alknet's code never delivered its spec's raw-key-over-TCP promise — ADR-082 "works for both QUIC and TCP+TLS"), not behavior to preserve. - FingerprintPinVerifier::requires_raw_public_keys() derives from the pin format: ed25519: -> true (offer [RawPublicKey]), SHA256: -> false (X.509 offer). Crate pin client now completes against the crate raw-key server; SHA256: pins negotiate unchanged. - RawKeyClientCertResolver presents the SPKI under the X.509 offer (only_raw_public_keys() == false): a raw-only client offer can only negotiate against a requires_raw server verifier, and AcceptAnyCertVerifier correctly stays on the default (accepts both cert types). The server extracts the ed25519: fingerprint from the SPKI bytes either way. - Fail-closed preserved and strengthened: an ed25519: pin against an X.509 server now aborts at negotiation (suite 2b), never a downgrade; no API change (no public signature affected; the fix is invisible to consumers apart from working handshakes). - tests/handshake_behavior.rs: suite 3 now runs crate-native (no custom iroh-shaped verifier), new negotiation fail-closed suite, suite 3b inverted to end-to-end success; invariant_pins.rs resolver-offer assertions flipped; unused imports dropped. - Docs: ADR-007 written; OQ-TLS-10 -> resolved-by-deviation; client.md/server.md/overview/README/task postscript synced (incl. the strict-foreign-server limit in ADR-007 §Limits). Verification: cargo test 81 / --features tcp 94 / --all-features 105 green; clippy -D warnings clean (default + all-features); fmt clean; cargo doc warning-free.
9.7 KiB
9.7 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-09-11 |
Open Questions
Centralized tracker for alktls. Promoted from Phase 0
(docs/research/phase-0.md OQ-TLS-01..08) on 2026-09-10. Statuses here
are authoritative; the Phase 0 doc's statuses are the historical record.
Statuses at a glance
| OQ | Topic | Status | Priority |
|---|---|---|---|
| OQ-TLS-01 | Config-type ownership | resolved (ADR-005) | high |
| OQ-TLS-02 | SelfSigned on the client path |
resolved (documented behavior kept) | low |
| OQ-TLS-03 | for_tcp_tls() adoption |
resolved (ADR-004) | medium |
| OQ-TLS-04 | Accessor borrow-vs-consume | resolved (ADR-004) | medium |
| OQ-TLS-05 | Test surface | resolved (ADR-006) | low |
| 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 |
| OQ-TLS-10 | RFC 7250 over TCP: cert-type negotiation gap | resolved (ADR-007) | high |
Identity & types
OQ-TLS-01: Where do the config types live, and what moves?
- Origin: docs/research/phase-0.md §Gaps #3
- Status: resolved (2026-09-10)
- Priority: high
- Resolution: alktls owns the identity types (
TlsIdentity,Ed25519SecretKey,AcmeDirectory), the credential bundle (ConnectionCredentials,RemoteIdentity), and the fingerprint helpers. The auth layer (PeerEntry,AuthPolicy,IdentityProvider) stays out — peer-level identity is not TLS. Decision recorded in ADR-005. - Cross-references: ADR-001, ADR-005
OQ-TLS-02: SelfSigned on the client path — encode or document?
- Origin: docs/research/phase-0.md §Gaps #4
- Status: resolved (2026-09-10)
- Priority: low
- Resolution: keep the current behavior (present nothing via
NoClientCertResolver) and document it on the identity type and in the client spec. Type-level enforcement (config error, likeAcme) was rejected:SelfSignedas a local identity meaning "present nothing" is coherent — the dev cert exists for the server side, and presenting a self-signed client cert would add nothing the fingerprint path uses. - Consequences: a future dev client-auth use case would need a type-level change (additive, not a one-way door).
- Cross-references: ADR-001 (identity model), client spec
OQ-TLS-07: iroh relationship in the rewrite
- Origin: docs/research/phase-0.md OQ-TLS-07
- Status: resolved (2026-09-10)
- Priority: low
- Resolution: the requirement is pinned and verified —
Ed25519SecretKeykeeps 32-byte raw access (from_bytes/as_bytes) with the same byte-level surface iroh'siroh_base::SecretKeyconsumes (from_bytes/to_bytes; 32 raw bytes in/out — verified against iroh 1.1 in Phase 0). iroh stays key-not-config; nofor_iroh(). The rewrite's iroh dial consumes the type alktls owns (ADR-005); no alktls-side work remains. - Cross-references: ADR-003, ADR-005
API surface
OQ-TLS-03: for_tcp_tls() — adopt the spec accessor?
- Origin: docs/research/phase-0.md §Gaps #2
- Status: resolved (2026-09-10)
- Priority: medium
- Resolution: adopted —
for_tcp_tls(&self) -> tokio_rustls::TlsAcceptor, feature-gated ontcp, infallible. Decision and rationale in ADR-004. - Cross-references: ADR-004
OQ-TLS-04: for_quinn() — self or &self?
- Origin: docs/research/phase-0.md OQ-TLS-04
- Status: resolved (2026-09-10)
- Priority: medium
- Resolution: server accessors take
&self(one config feeds N transports — the ADR-082 story, directly expressible); client accessors consumeself(per-dial build, zero-costinto_rustls_config). Full rationale in ADR-004. - Cross-references: ADR-003, ADR-004
OQ-TLS-08: quinn feature vs noq feature — and the MSRV floor
- Origin: docs/research/phase-0.md §Prior art: noq
- Status: resolved (2026-09-10)
- Priority: high
- Resolution: the feature is
noq(noquinnfeature ever published; rename is pre-consumer and free). noq 1.2 pinned ("1.2", default-features off,rustlsfeature), bump deliberately. The MSRV half of the OQ was separately resolved the same day (ecosystem floor 1.88;timepin dropped). Decision in ADR-003. - 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:
AcceptAnyCertVerifiernever 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
AcceptAnyCertVerifieris the honest description until then. - (b) Add a
VerifyPresentedCertVerifiersibling (request-and-verify): same nine-scheme list, permissiveverify_client_cert, signature methods delegate torustls::crypto::verify_tls{12,13}_signature(_with_raw_key)— the routing the client-sideFingerprintPinVerifieralready 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.
- (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
- Constraints: the spoofable posture is pinned by
tests/impersonation_posture.rs(both cert types) — any decision must fail or update that test together with theAcceptAnyCertVerifierdoc note. - Cross-references: src/server.rs (
AcceptAnyCertVerifier), src/client.rs (FingerprintPinVerifier), docs/reviews/001-implementation-review.md §S-1, alknet ADR-034
OQ-TLS-10: How do RFC 7250 raw-key peers negotiate over rustls-driven TCP+TLS?
- Origin:
tasks/handshake-tests.md(review 001 §U-3 execution): the executed handshake suites found that the crate's own pin client cannot complete a handshake against the crate's own raw-key server, and a raw-key client resolver cannot present itself toAcceptAnyCertVerifier— both fail with rustls' HandshakeFailure alert (cert-type negotiation), not a verification outcome. Verified empirically and against the rustls 0.23.44 sources (server/hs.rs::process_cert_type_extension,client/hs.rs::process_cert_type_extension); pinned bytests/handshake_behavior.rs. - Status: resolved (2026-09-11) — by deviation from alknet,
ADR-007. Option (b) plus a
resolver change:
FingerprintPinVerifier::requires_raw_public_keys()derives from the pin format (ed25519:→true,SHA256:→false), andRawKeyClientCertResolverpresents the SPKI under the X.509 offer (only_raw_public_keys() == false). The gap was a bug in the prior art (alknet's code never delivered its spec's raw-key-over- TCP promise), not an alknet behavior to preserve — so the behavior-preservation invariant does not cover it. The two pin formats negotiate independently (per-connection verifier, never shared); fail-closed is preserved and strengthened (aned25519:pin against an X.509 server aborts at negotiation, never a downgrade). The original "defer until the first consumer" rationale was circular — the crate is the component that must enable the raw-key-over-TCP consumer, and the fix required no API change. - Cross-references: src/client.rs (
FingerprintPinVerifier,RawKeyClientCertResolver), src/server.rs (RawKeyCertResolver,AcceptAnyCertVerifier), review 001 §N-4, ADR-007, irohiroh/src/tls/verifier.rs(the working prior art)
Quality / process
OQ-TLS-05: Test surface for the invariants
- Origin: docs/research/phase-0.md §Gaps #5
- Status: resolved (2026-09-10)
- Priority: low
- Resolution: port the in-module seed tests AND add
tests/integration tests for the cross-module surfaces; pin the exact nine-scheme list (regression-proof). Decision in ADR-006. - Cross-references: ADR-006
OQ-TLS-06: Does the ACME state machine need a shutdown surface?
- Origin: docs/research/phase-0.md OQ-TLS-06
- Status: resolved (2026-09-10)
- Priority: low
- Resolution: detached-only — the handle is stored (keeping
TlsServerConfignon-Clone) and never aborted; the ACME task runs for the process lifetime. Documented on the type. - Consequences: a
shutdown()(abort + await) surface would be additive and cheap if the rewrite's graceful-shutdown design wants one later — not a one-way door. - Cross-references: ADR-001 (one-ACME-machine rule), server.md
Deferred / Blocked
- 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)).