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
+46 -10
View File
@@ -1,7 +1,7 @@
---
id: port-fingerprint
name: Port fingerprint helpers + DER parser (src/fingerprint.rs)
status: pending
status: completed
depends_on: [crate-init]
scope: narrow
risk: low
@@ -44,20 +44,20 @@ the private manual DER parser (`DerParser`).
## Verification
- [ ] Ported tests green (`cargo test fingerprint`)
- [ ] Round-trip: an Ed25519 SPKI built by `signing.rs`'s
- [x] Ported tests green (`cargo test fingerprint`)
- [x] Round-trip: an Ed25519 SPKI built by `signing.rs`'s
`spki_public_key()` yields `ed25519:<hex>` matching the source
key (integration assert — this pins the normalization across
the raw-key paths)
- [ ] Malformed-DER inputs yield `None` / SHA fallback (ported edge
- [x] Malformed-DER inputs yield `None` / SHA fallback (ported edge
tests)
- [ ] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
- [x] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`
## Acceptance Criteria
- [ ] The module compiles without `rustls` in production code
- [ ] Both normalized fingerprint formats are test-pinned
- [ ] `lib.rs` re-exports the two public functions
- [x] The module compiles without `rustls` in production code
- [x] Both normalized fingerprint formats are test-pinned
- [x] `lib.rs` re-exports the two public functions
## References
@@ -68,8 +68,44 @@ the private manual DER parser (`DerParser`).
## Notes
> Agent fills this during implementation.
- **Empty-input discrepancy (resolved against the code):** the task
description said `fingerprint_from_cert_der` "returns `None` only for
empty input"; the extraction's *doc comment* claims the same, but its
*code* has no empty-input check — empty input falls through to the
SHA-256 fallback and returns `Some("SHA256:e3b0c442…")` (the hash of
the empty slice). The port matches the extraction's actual behavior
(always `Some`); the doc comment on the ported function records the
deviation so the stale `None` claim is not propagated.
- The extraction's test list (7 tests) contained no malformed-DER edge
tests despite the task invariant naming them — the malformed-DER
suite was written fresh for this port: truncated headers, wrong
outer tag, long-form length edges (0x80 indefinite, overlong,
>4 bytes, truncated header), a well-formed long-form length
acceptance case, wrong-OID-in-valid-SPKI, bad BIT STRING lengths
(32/34 bytes, non-zero unused-bits), and malformed-DER SHA fallback.
- Tests construct the raw key bytes directly (fixed test-key arrays)
and build SPKIs via `rustls::sign::public_key_to_spki` — no
dependency on `identity.rs` (concurrent-port constraint held).
- Production code uses `hex::encode` (ported verbatim), so `hex` was
added to `[dependencies]` (it was dev-only; alknet-core does the
same).
- Ported test `fingerprint_from_ed25519_spki_matches_iroh_format`
compares against `format!("ed25519:{}", hex::encode(raw_key))` per
the task (the extraction compared a separately generated key; same
shape, key sourced directly instead).
## Summary
> Agent fills this on completion.
Ported `src/fingerprint.rs` wholesale from
`/workspace/@alkdev/alknet/crates/alknet-core/src/fingerprint.rs`:
`fingerprint_from_cert_der`, `extract_ed25519_raw_key_from_spki`,
private `DerParser` (`read_tlv`, `decode_header`, `expect_sequence`,
`expect_oid`, `expect_bit_string`). Production code stays `sha2` +
manual DER + `hex`; the only `rustls::` use is the test-only SPKI
builder. 16 tests green (7 ported from the extraction with the
`crate::config::Ed25519SecretKey::generate()` dependency replaced by
fixed key arrays, 9 new/extended edges). `lib.rs` re-exports both
public functions (concurrent port lines preserved). Verification:
`cargo test` (36 pass), `cargo test --all-features` (37 pass),
`cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`,
`cargo check --all-features` — all clean.