Commit Graph
11 Commits
Author SHA1 Message Date
glm-5.3-flash 49d4432247 ADR-007: RFC 7250 cert-type negotiation — the offer follows the identity (OQ-TLS-10 resolved)
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.
2026-09-11 10:26:28 +00:00
glm-5.3-flash 4a4fae64af task 2: handshake-level suites — pin, fail-closed, RFC 7250 paths executed (U-3)
tests/handshake_behavior.rs (tcp-gated, tokio duplex + tokio-rustls,
no new deps) turns the fail-closed / pin / raw-key language into
executed behavior:

- pin match: X.509 server + SHA256 pin -> handshake completes, app
  data round-trips, server extracts the client cert fingerprint
- pin mismatch: wrong pin -> handshake error (the pin IS the anchor)
- fail closed: remote_identity None + raw-key server -> HandshakeFailure
- raw-key server path end-to-end: completes with the iroh-shaped
  client verifier (requires_raw_public_keys == true); presented cert
  asserted to be the SPKI carrying the raw Ed25519 key
- N-4's interop trap executed: raw-key client resolver vs
  AcceptAnyCertVerifier -> IncorrectCertificateTypeExtension alert

Major finding, recorded as OQ-TLS-10 (open): a crate-built pin
client cannot reach a crate-built raw-key server over rustls TCP+TLS
— the raw-key resolver requires the client to offer [RawPublicKey]
server cert types, sent only when the client verifier overrides
requires_raw_public_keys() == true. FingerprintPinVerifier keeps the
trait default false (AcceptAnyCertVerifier too); iroh's verifier
overrides true on both sides. Gap inherited from alknet
(behavior-preserving); pinned both ways by the suite.

client.md / server.md carry the interop notes; task file updated
(premise adjustments documented in Notes, summary filled).

Verification: 81 default / 91 tcp / 99 all-features tests green
(+5 new), clippy -D warnings clean both configs, fmt clean,
cargo doc warning-free, taskgraph validate 14 tasks.
2026-09-11 08:17:28 +00:00
glm-5.3-flash d82956385b 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
2026-09-11 07:38:21 +00:00
glm-5.3-flash e86b8ba1b5 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
2026-09-10 22:00:57 +00:00
glm-5.3-flash bb0d060135 review 001: alktls v1 implementation — correctness, security, coverage
Independent post-port review (behavior-preservation + security +
coverage focus; the alknet sources consulted only as prior art).

Findings:
- S-1 [major, security posture]: AcceptAnyCertVerifier does not verify
  the client CertificateVerify (no proof-of-possession) — executable
  probe confirms a victim-cert + attacker-key handshake completes and
  the server extracts the victim's fingerprint (both X.509 and RFC
  7250 SPKI variants). Doc/ADR remediation, not a behavior change
  (the shape is the alknet-inherited design).
- C-1..C-4 [minor]: self-signed cert validity 1975-4096 undocumented;
  acme-tls/1 duplicated if caller supplies it; empty ACME domains
  construct without validation; malformed/case-shifted fingerprint
  pins reject at handshake with no config-layer doc.
- U-1..U-3 [minor, coverage]: ACME event-loop body uncovered (23
  lines); resolvers' resolve() methods uncovered; zero
  handshake-level tests (fail-closed/pin/raw-key paths asserted only
  structurally); webpki-roots fallback loop nondeterministically
  covered.
- N-1..N-7: doc nits, two non-findings (dangerous()-downgrade suspect
  retracted; zeroize marker verified inert via ed25519-dalek default
  features), packaging noise (tasks/ + docs/architecture/ ship),
  requires_raw_public_keys interaction note (raw-only clients fail
  against request-but-don't-require), http:// custom ACME directory
  warning.
- Behavior preservation: full src/ diff vs alknet-tls + alknet-core —
  zero unrecorded behavioral divergences (Part B).

Verification: cargo test 68 default / 75 --all-features; clippy -D
warnings (both configs); fmt --check; cargo doc --no-deps;
cargo publish --dry-run --allow-dirty; cargo llvm-cov --all-features
95.32% line / 94.48% functions, uncovered-line inventory in the doc;
temporary review probes (fingerprint pins, DER adversarial battery,
empty-PEM, ACME construction edges, impersonation handshake) all run
and deleted after the run.
2026-09-10 16:14:05 +00:00
glm-5.3-flash 8a15978c41 generation 5: review-impl — spec-conformance gate passed, API frozen
Checklist (all six PASS):
1. API surface == ADR-004 — every accessor signature verified verbatim
2. TlsError == ADR-002 — six variants, #[non_exhaustive], typed sources,
   AcmeConfig holds exactly the two config-mismatch cases
3. Invariants: all five server invariants + client 0-RTT half +
   fail-closed structure, each with a passing behavioral test at unit
   and integration level
4. Deltas vs extraction: all ADR-pinned; two surfaced divergences
   recorded as ADR amendments — zero un-pinned divergences remain
5. Feature hygiene: default = [] lean, tokio subset (no full),
   doc comments on public API, no inline // comments, no panics
6. Docs sync: ADR-002 + ADR-003 amendment notes; overview/server/client
   Draft → Reviewed; README carries the API-freeze lifecycle note

5 findings, all low severity, all resolved forward (table in task Notes)

Verification: cargo test (81), cargo test --all-features (92),
clippy -D warnings, fmt --check, doc --no-deps,
publish --dry-run — all green. API FROZEN for the alknet rewrite.
2026-09-10 15:05:01 +00:00
glm-5.3-flash d74a27f764 phase 1: architecture spec — overview, server/client, ADR-001..006
- ADR-001: inherit the alknet TLS design as the baseline; deviations
  recorded as alktls ADRs
- ADR-002: TlsError ships the ADR-088 six-variant shape from day one
  (typed #[from] sources; NoqWrap; no string catch-all)
- ADR-003: the QUIC feature is noq (iroh's extracted fork), pre-
  consumer rename; default = [] per the lean-crate convention
  (corrects the extracted code's default = ["quinn"])
- ADR-004: complete accessors — for_tcp_tls() adopted, rustls_config()
  adopted; server accessors borrow (&self), client accessors consume
- ADR-005: identity + credentials + fingerprint types move into
  alktls; auth layer stays out
- ADR-006: eight-module layout; seed tests + integration invariant
  pins (exact nine-scheme list, client enable_early_data)
- specs: overview (transport picture, terminology), server.md (ACME
  lifecycle, invariants), client.md (verifier selection matrix, root-
  store fallback); open-questions.md promotes OQ-TLS-01..08 (all
  resolved at entry)
- Cargo.toml: quinn feature -> noq (per ADR-003); AGENTS.md aligned

Architecture review pass done: 0 critical, 2 major (ADR-002 AcmeConfig
doc comment contradiction; ADR-003 unrecorded default deviation) and
8 minors all addressed; cross-references verified against alknet ADRs,
rustls/noq/iroh sources.

Verified: cargo test, test --all-features, clippy -D warnings,
fmt --check, doc --no-deps
2026-09-10 05:37:55 +00:00
glm-5.3-flash e93238cb4a adopt ecosystem MSRV floor 1.88; drop the time pin
- rust-version 1.85 -> 1.88 (ecosystem-wide resolution from the audit
  sessions; matches noq 1.2's floor, sits below iroh 1.91)
- Cargo.lock: time 0.3.36 pin removed (existed only to keep the 1.85
  claim satisfiable); tree re-floated to current
- phase-0: MSRV thread marked RESOLVED; OQ-TLS-08 narrowed to the
  quinn->noq feature-rename half; lesson recorded (rust-version is
  passive metadata — claims must be compile-checked, not assumed)

Verified: cargo test, test --all-features, clippy -D warnings,
fmt --check, rustup run 1.88 cargo check
2026-09-10 03:51:31 +00:00
glm-5.3-flash 6bd19994f8 phase-0: noq/iroh investigation — quinn→noq shift recorded
- noq 1.2.0 published (iroh's extracted quinn fork); iroh 1.1.0 is
  built on noq 1.2.0 and re-exports noq as its public API
- TLS seam verified API-compatible with quinn 0.11: QuicServerConfig/
  QuicClientConfig try_from + NoInitialCipherSuite — port is mechanical
- one rustls 0.23 tree across all QUIC paths (both pin 0.23.33);
  ADR-084 posture strengthens (no ring/aws-lc provider split possible)
- iroh key surface unchanged (32-byte Ed25519 SecretKey) —
  key-not-config exception intact
- OQ-TLS-08 opened: quinn feature → noq feature rename + honest MSRV
  floor (noq 1.88, iroh 1.91); OQ-TLS-04/07 updated; survey + checklist
  extended

Verified: cargo fmt --check, cargo test, cargo doc --no-deps
2026-09-09 16:45:41 +00:00
glm-5.3-flash a570bee0fe repo scaffold + AGENTS.md + Phase 0 research
- Cargo scaffold: feature gates (quinn/tcp/acme), lean tokio subset,
  placeholder lib; Cargo.lock committed with time pinned to 0.3.36 so
  rust-version = 1.85 is actually satisfiable (rcgen's default time
  resolution requires 1.88 — alknet-tls fails the same check)
- AGENTS.md adapted from alktunnels: TLS-crate conventions (behavior-
  preservation invariants, fail-closed verifier selection, one ACME
  state machine, config-construction scope boundary, no wasm target)
- .opencode/agents: implementation-specialist conventions + coordinator
  prompt template + architect deferral examples updated for alktls
- docs/research/phase-0.md: extraction inventory with verified
  invariants (line-referenced), spec-vs-code gaps (TlsError shape,
  for_tcp_tls, config-type ownership), rewrite requirements,
  OQ-TLS-01..07, MSRV verification record

Verified: cargo test, clippy -D warnings, fmt --check, doc --no-deps,
test --all-features, rustup run 1.85 cargo check
2026-09-09 16:25:55 +00:00
glm-5.3-flash dbc77af3d3 init 2026-09-09 14:47:09 +00:00