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
7.1 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| port-identity-types | Port identity types — TlsIdentity, Ed25519SecretKey, AcmeDirectory (src/identity.rs) | completed |
|
narrow | low | component | implementation |
|
Description
Port the identity types from alknet-core config.rs into
src/identity.rs per ADR-005: TlsIdentity (four variants: X509 { cert, key }, RawKey(Ed25519SecretKey), SelfSigned, Acme { domains, cache_dir, directory, contact }), Ed25519SecretKey, and
AcmeDirectory (Production / Staging / Custom(String) with
url()).
The load-bearing surface (do not change)
Ed25519SecretKey:generate(),from_bytes(&[u8; 32]),as_bytes() -> [u8; 32],public() -> ed25519_dalek::VerifyingKey,sign(&self, message) -> ed25519_dalek::Signature. The byte surface is what iroh'siroh_base::SecretKeyconsumes (ADR-005; verified against iroh 1.1 in Phase 0). Backed byed25519_dalek::SigningKey.Debugmust NOT leak key material (the extracted type formats asEd25519SecretKey(..)— keep it).AcmeDirectory::Production/StagingURLs are pinned strings (Let's Encrypt production + staging) — assert them in tests.- Doc comments carry the OQ-TLS-02 resolution:
SelfSignedon the client path presents nothing (documented on the variant).
What moves vs stays
TlsIdentity/Ed25519SecretKey/AcmeDirectory move here wholesale.
PeerEntry, AuthPolicy, Identity, fingerprint → peer-id
resolution stay OUT (auth layer — ADR-005's carve-out). No
serde derives unless the extracted code has them (check; do not add
new surface beyond ADR-005's list without noting it).
Work
- Port the three types + their inherent methods from
crates/alknet-core/src/config.rs. - Port the associated in-module tests (
generate/from_bytesround-trip,AcmeDirectoryURL assertions). - Add the Debug-no-leak test if not present in the extracted tests.
Verification
cargo test -p alktls identitypasses (ported tests green)as_bytes/from_bytesround-trip assertedAcmeDirectoryURLs asserted (production + staging + custom)Debugoutput contains no key bytes (test: format then assert hex key absent)cargo clippy --all-targets -- -D warnings,cargo fmt --check
Acceptance Criteria
src/identity.rsholds exactly the ADR-005 type set; no auth layer types present- The byte surface matches the load-bearing list above verbatim
lib.rsre-exports the three types
References
- docs/architecture/decisions/005-config-types-move-into-alktls.md
- docs/architecture/decisions/006-module-layout-and-tests.md (module map)
- Prior art:
/workspace/@alkdev/alknet/crates/alknet-core/src/config.rs(lines 33–80:Ed25519SecretKey,TlsIdentity,AcmeDirectory)
Notes
Agent fills this during implementation.
Decisions / deviations
- rand decision:
rand_core = "0.6"+ ed25519-dalek'srand_corefeature — NOTrand. The alktls lockfile's transitiverandis 0.10.2 (rand_core 0.10.1); ed25519-dalek 2.2.0'sSigningKey::generateneedsrand_core 0.6.4'sCryptoRngCore(its Cargo.toml pinsrand_core = "0.6.4", optional). rand 0.10'sOsRngonly implements rand_core 0.10 traits → incompatible, sorand::rngs::OsRngwould not compile against ed25519-dalek 2.2.0. Additionally,generateis gated#[cfg(any(test, feature = "rand_core"))]inside ed25519-dalek — the non-defaultrand_corefeature 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], usingrand_core::OsRng.rand_core 0.6.4+getrandom 0.2.17were already in the lockfile transitively — no version churn;randstays out of the dep tree (leaner than the extraction, which depended onrand 0.8). zeroize::ZeroizeOnDropnot ported (deliberate omission). The extractedEd25519SecretKeyhadimpl 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 includezeroize, and itsSigningKeyitself implementsZeroizeOnDropinternally — the wrapped key material is still zeroized on drop through the inner type. Adding the crate-level impl would require azeroizedep for zero behavioral gain; can be added later if the vault (rewrite's config side) wants the explicit marker impl.- serde derives: none ported. The extracted three types carry no
serde derives (checked
config.rslines 32–98) — nothing to add, consistent with "no new surface beyond ADR-005's list". 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.- Sibling-task fix (tree-state deviation, not this port). The
working tree contained port-pem-signing's uncommitted work
(
pem.rs,signing.rs,lib.rsre-exports). Itssigning.rstest module was missinguse crate::{load_cert_chain, load_private_key};andpem.rslacked a trailing newline, which brokecargo test/cargo fmt --checkfor the whole crate. Two mechanical fixes applied (test-onlyuseline; trailing newline) so whole-crate verification could run; no production code touched.
Summary
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-coreconfig.rslines 32–98 —Ed25519SecretKey(exact byte surface:generate/from_bytes/as_bytes/public/signvia in-methodSignerimport; customDebugwithfinish_non_exhaustive),AcmeDirectory(pinned production/staging URLs),TlsIdentity(four variants; doc comments carry the OQ-TLS-02 resolution onSelfSignedand the server-only note onAcme).- Tests: all five extracted
Ed25519SecretKeytests ported (round-trip, sign-verifies, tampered-reject, Debug-no-leak with hex assertion, public-length) + the two extractedTlsIdentityconstruct tests + a newAcmeDirectoryURL-pinning test + anAcmeconstruct test. Cargo.toml:ed25519-dalekgains therand_corefeature;rand_core 0.6(featuregetrandom) 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.