phase 2: task decomposition — 8-task port graph
- crate-init: skeleton, feature gates (ADR-003), TlsError (ADR-002) - three parallel foundation ports: identity types, fingerprint, pem+signing - port-server / port-client in parallel (each consumes the foundation; client also carries credentials.rs per ADR-005 co-location) - integration-suite: invariant pins + feature-matrix + seam round-trips - review-impl: spec-conformance gate — the API-freeze point before the alknet rewrite consumes the crate - validated: taskgraph topo (5 generations), no cycles, critical path len 5, risk-path 1.45; medium risk concentrated on the two broad ports + the suite (each a diff against a fixed extraction source, not open-ended work)
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
---
|
||||
id: port-client
|
||||
name: Port client side — TlsClientConfig, verifier selection, client auth (src/client.rs)
|
||||
status: pending
|
||||
depends_on: [port-identity-types, port-fingerprint, port-pem-signing]
|
||||
scope: broad
|
||||
risk: medium
|
||||
impact: phase
|
||||
level: implementation
|
||||
tags: [client, verifiers, port, invariants]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Port `src/client.rs` from alknet-tls per the ADRs: `TlsClientConfig`,
|
||||
`select_server_verifier`, `build_client_auth`,
|
||||
`RawKeyClientCertResolver`, `NoClientCertResolver`,
|
||||
`FingerprintPinVerifier`, `load_platform_root_cert_store`.
|
||||
|
||||
### The API deltas (from the extracted code)
|
||||
|
||||
- Types rewire: `ConnectionCredentials`/`RemoteIdentity` come from this
|
||||
crate's `credentials.rs` (ADR-005); fingerprint helpers from this
|
||||
crate's `fingerprint.rs`; the identity from this crate's
|
||||
`identity.rs`.
|
||||
- `for_noq(self)` replaces `for_quinn(self)` (consuming — ADR-004);
|
||||
`into_rustls_config(self)` unchanged.
|
||||
|
||||
### Credentials module (small, rides here)
|
||||
|
||||
`src/credentials.rs` — port `ConnectionCredentials` (`local_identity:
|
||||
Option<TlsIdentity>`, `remote_identity: Option<RemoteIdentity>`, the
|
||||
builder methods) and `RemoteIdentity` (`fingerprint: String`) from
|
||||
alknet-core `credentials.rs`, including the load-bearing doc comments
|
||||
(`None` is the public-X.509-endpoint state, not a placeholder — the
|
||||
`Option`s drive verifier selection). This task owns the module because
|
||||
the verifier selection is the semantic consumer of the bundle; the
|
||||
co-location prevents semantic drift (ADR-005).
|
||||
|
||||
### The invariants / selection matrix (test-pinned here)
|
||||
|
||||
- Every config: `enable_early_data = true` (the client half of the
|
||||
0-RTT invariant — ADR-001; pinned as a test) and the aws-lc-rs
|
||||
provider.
|
||||
- Verifier selection matrix: `Some(fingerprint)` →
|
||||
`FingerprintPinVerifier`; `None` → `WebPkiServerVerifier` over the
|
||||
root store. Fail-closed for unknown raw-key remotes is structural
|
||||
(the CA verifier is what `None` installs; a raw-key remote cannot
|
||||
satisfy it — the failure manifests at handshake, never via
|
||||
`TlsError`).
|
||||
- Root-store fallback: platform certs first; if empty, merge
|
||||
`webpki-roots` (never empty); native-certs load errors logged, not
|
||||
returned. Testable by asserting the merge path (construct with an
|
||||
empty platform store simulation if the API permits; otherwise assert
|
||||
the fallback branch by construction — `load_platform_root_cert_store`
|
||||
returns a non-empty store).
|
||||
- Client-auth presentation: RawKey → RFC 7250 SPKI cert with
|
||||
`only_raw_public_keys()` auto-detected from the DER; X509 → loaded
|
||||
chain via `CertifiedKey::from_der` (errors → `TlsError::Rustls` per
|
||||
ADR-002); `SelfSigned`/`None` → `NoClientCertResolver`
|
||||
(`has_certs() == false`); `Acme` → `TlsError::AcmeConfig`.
|
||||
- `FingerprintPinVerifier`: pin match / mismatch on
|
||||
`verify_server_cert`; TLS 1.2/1.3 signature verification routes
|
||||
Ed25519 SPKI through `verify_tls13_signature_with_raw_key`; a
|
||||
mismatched pin fails verification.
|
||||
|
||||
## Work
|
||||
|
||||
1. Port `credentials.rs` (types + builders + doc comments).
|
||||
2. Port `client.rs`; apply the deltas; rewire imports.
|
||||
3. Port the extracted in-module tests.
|
||||
4. Add the selection-matrix integration test (below).
|
||||
|
||||
## Verification
|
||||
|
||||
- [ ] Selection-matrix test: all four client-auth presentations × both
|
||||
verifier branches construct and select the expected resolver
|
||||
types (inspect via the config's client-auth/verifier state where
|
||||
the API permits; otherwise assert construction success/error
|
||||
kind per cell)
|
||||
- [ ] `Acme` local identity → `TlsError::AcmeConfig`
|
||||
- [ ] `enable_early_data == true` pinned
|
||||
- [ ] Root store non-empty (fallback exercised)
|
||||
- [ ] FingerprintPinVerifier unit tests ported (pin match, mismatch,
|
||||
raw-key signature routing)
|
||||
- [ ] `cargo test` (default), `cargo test --all-features`,
|
||||
`cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `for_noq(self)` / `into_rustls_config(self)` per ADR-004
|
||||
- [ ] The selection matrix has no fourth path (fail-closed structural)
|
||||
- [ ] `lib.rs` re-exports the client surface + `ConnectionCredentials`
|
||||
/ `RemoteIdentity`
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/client.md (the normative doc)
|
||||
- docs/architecture/decisions/002-tlserror-shape.md, 004, 005
|
||||
- alknet ADR-034 §3, ADR-088 §5, ADR-091
|
||||
- Prior art: `/workspace/@alkdev/alknet/crates/alknet-tls/src/client.rs`,
|
||||
`/workspace/@alkdev/alknet/crates/alknet-core/src/credentials.rs`
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
Reference in New Issue
Block a user