generation 2: port identity types, fingerprint, pem + signing

port-identity-types (src/identity.rs):
- TlsIdentity (four variants), Ed25519SecretKey, AcmeDirectory ported
  verbatim from alknet-core config.rs; OQ-TLS-02 + server-only docs
  on the variants; 9 in-module tests incl. Debug-no-leak
- dep decision: rand_core 0.6 (+getrandom) with ed25519-dalek
  rand_core feature, NOT rand (lockfile rand 0.10/rand_core 0.10
  traits are incompatible with ed25519-dalek 2.2's CryptoRngCore);
  rand stays out of the tree entirely

port-fingerprint (src/fingerprint.rs):
- fingerprint_from_cert_der, extract_ed25519_raw_key_from_spki,
  DerParser ported verbatim; production code sha2 + manual DER
  (+hex for the normalized formats)
- 16 tests: 7 ported + 9 new malformed-DER edges (the extraction
  had none despite the invariant naming them)
- empty-input behavior: matches extraction's actual code (always
  Some via the SHA-256 fallback); doc records the deviation from
  the stale None claim

port-pem-signing (src/pem.rs, src/signing.rs):
- load_cert_chain/load_private_key remapped to TlsError::CertLoad
  per ADR-002; InvalidData no-key path kept
- Ed25519SigningKey rewired to crate::identity::Ed25519SecretKey
  (the one intentional change); rcgen PEM round-trip test added

lib.rs re-export block: fingerprint + pem + signing + identity lines
landed; server/client/credentials pending their port tasks

Verification: cargo test (36), cargo test --all-features (37),
clippy -D warnings (default+all-features), fmt --check, feature
checks (noq/tcp/acme) — all green
This commit is contained in:
2026-09-10 13:48:32 +00:00
parent f68234133f
commit 4bdc12e84f
10 changed files with 1058 additions and 36 deletions
+88 -10
View File
@@ -1,7 +1,7 @@
---
id: port-identity-types
name: Port identity types — TlsIdentity, Ed25519SecretKey, AcmeDirectory (src/identity.rs)
status: pending
status: completed
depends_on: [crate-init]
scope: narrow
risk: low
@@ -51,19 +51,19 @@ new surface beyond ADR-005's list without noting it).
## Verification
- [ ] `cargo test -p alktls identity` passes (ported tests green)
- [ ] `as_bytes`/`from_bytes` round-trip asserted
- [ ] `AcmeDirectory` URLs asserted (production + staging + custom)
- [ ] `Debug` output contains no key bytes (test: format then assert
- [x] `cargo test -p alktls identity` passes (ported tests green)
- [x] `as_bytes`/`from_bytes` round-trip asserted
- [x] `AcmeDirectory` URLs asserted (production + staging + custom)
- [x] `Debug` output contains no key bytes (test: format then assert
hex key absent)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
- [x] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] `src/identity.rs` holds exactly the ADR-005 type set; no auth
- [x] `src/identity.rs` holds exactly the ADR-005 type set; no auth
layer types present
- [ ] The byte surface matches the load-bearing list above verbatim
- [ ] `lib.rs` re-exports the three types
- [x] The byte surface matches the load-bearing list above verbatim
- [x] `lib.rs` re-exports the three types
## References
@@ -76,6 +76,84 @@ new surface beyond ADR-005's list without noting it).
> Agent fills this during implementation.
### Decisions / deviations
1. **rand decision: `rand_core = "0.6"` + ed25519-dalek's `rand_core`
feature — NOT `rand`.** The alktls lockfile's transitive `rand` is
0.10.2 (`rand_core 0.10.1`); ed25519-dalek 2.2.0's
`SigningKey::generate` needs `rand_core 0.6.4`'s `CryptoRngCore`
(its Cargo.toml pins `rand_core = "0.6.4"`, optional). rand 0.10's
`OsRng` only implements rand_core 0.10 traits → incompatible, so
`rand::rngs::OsRng` would not compile against ed25519-dalek 2.2.0.
Additionally, `generate` is gated
`#[cfg(any(test, feature = "rand_core"))]` inside ed25519-dalek —
the non-default `rand_core` feature must be enabled (alknet-core
does the same: `rand = "0.8"` + `ed25519-dalek = { features =
["rand_core"] }`). Fix: `ed25519-dalek = { version = "2", features
= ["rand_core"] }` + `rand_core = { version = "0.6", features =
["getrandom"] }` in `[dependencies]`, using `rand_core::OsRng`.
`rand_core 0.6.4` + `getrandom 0.2.17` were already in the lockfile
transitively — no version churn; `rand` stays out of the dep tree
(leaner than the extraction, which depended on `rand 0.8`).
2. **`zeroize::ZeroizeOnDrop` not ported (deliberate omission).** The
extracted `Ed25519SecretKey` had `impl zeroize::ZeroizeOnDrop`, but
ADR-005's type list doesn't mention it and the task says not to add
surface beyond the ADR's list. Note: ed25519-dalek 2.2.0's default
features include `zeroize`, and its `SigningKey` itself implements
`ZeroizeOnDrop` internally — the wrapped key material is still
zeroized on drop through the inner type. Adding the crate-level
impl would require a `zeroize` dep for zero behavioral gain; can be
added later if the vault (rewrite's config side) wants the explicit
marker impl.
3. **serde derives: none ported.** The extracted three types carry no
serde derives (checked `config.rs` lines 3298) — nothing to add,
consistent with "no new surface beyond ADR-005's list".
4. **`TlsIdentity::Acme`'s doc comment added** (task instruction):
server-only, config error (`TlsError::AcmeConfig`) on the client
path — per ADR-001's identity model and the client spec's
presentation table.
5. **Sibling-task fix (tree-state deviation, not this port).** The
working tree contained port-pem-signing's uncommitted work
(`pem.rs`, `signing.rs`, `lib.rs` re-exports). Its `signing.rs`
test module was missing `use crate::{load_cert_chain,
load_private_key};` and `pem.rs` lacked a trailing newline, which
broke `cargo test` / `cargo fmt --check` for the whole crate. Two
mechanical fixes applied (test-only `use` line; trailing newline)
so whole-crate verification could run; no production code touched.
## Summary
> Agent fills this on completion.
> Agent fills this on completion. Brief description of what was
> implemented, files changed, and any follow-up needed.
### What landed
- `src/identity.rs`: the three ADR-005 types ported verbatim from
alknet-core `config.rs` lines 3298 — `Ed25519SecretKey`
(exact byte surface: `generate` / `from_bytes` / `as_bytes` /
`public` / `sign` via in-method `Signer` import; custom `Debug`
with `finish_non_exhaustive`), `AcmeDirectory` (pinned
production/staging URLs), `TlsIdentity` (four variants; doc
comments carry the OQ-TLS-02 resolution on `SelfSigned` and the
server-only note on `Acme`).
- Tests: all five extracted `Ed25519SecretKey` tests ported
(round-trip, sign-verifies, tampered-reject, Debug-no-leak with hex
assertion, public-length) + the two extracted `TlsIdentity`
construct tests + a new `AcmeDirectory` URL-pinning test +
an `Acme` construct test.
- `Cargo.toml`: `ed25519-dalek` gains the `rand_core` feature;
`rand_core 0.6` (feature `getrandom`) added as a dependency.
- `src/lib.rs`: `pub use identity::{AcmeDirectory, Ed25519SecretKey,
TlsIdentity};` added to the incremental re-export block.
### Verification
- `cargo test` ✓ (20 passed); `cargo test -p alktls identity` ✓
(9 passed); `cargo clippy --all-targets -- -D warnings` ✓;
`cargo fmt --check` ✓; `cargo check --all-features` ✓;
`cargo test --all-features` ✓ (21 passed); `cargo clippy
--all-targets --all-features -- -D warnings` ✓.
### Follow-up
- None for this module. port-client completes the re-export block.