- src/fingerprint.rs: alkssh::fingerprint wraps the ssh-key re-export (HashAlg::Sha256) — the crate's only fingerprint computation and formatting site (ADR-004 decision 1's contract invariant) - tests/fingerprint_parity.rs: 4 committed ed25519 fixtures with ssh-keygen -lf-recorded fingerprints (OpenSSH 9.6p1, independent issuer); blobs cross-checked against the vectors manifest - verified: cargo test, clippy (default + all-features, -D warnings), fmt; taskgraph validate clean
4.6 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| w1-fingerprint | Wave 1 — fingerprint computation (the contract invariant) | completed |
|
narrow | low | project | implementation |
Description
Land the fingerprint computation the auth bridge (server) and the host-key policy path (client) both consume — ADR-004 decision 1's contract invariant in code:
- Compute a key's fingerprint via the
ssh-keyre-export (HashAlg::Sha256): theSHA256:+ unpadded url-safe base64 OpenSSH format. The string format is a contract invariant — registration strings from any standard issuer (ssh-keygen -lf, alkcall-side computation) must compare equal to what this crate computes; parity is proven, not assumed (POC-1 §1). - The function takes the russh/ssh-key public-key type and returns the string; it is the single fingerprint path in the crate (no second formatting anywhere — a drift here breaks every identity resolution silently).
- Parity tests against independent-issuer vectors: static ed25519
test keys with their
ssh-keygen -lf-recorded expected fingerprints (the POC-1 §1 checkpoint shape). The vectors are committed test fixtures (throwaway test keys — no secret material).
Acceptance Criteria
- Single fingerprint function via
HashAlg::Sha256;SHA256:+ unpadded url-safe base64 output - Parity tests against
ssh-keygen -lf-recorded vectors pass (independent-issuer format parity proven) - No second fingerprint-formatting path exists in
src/ cargo test,cargo clippy --all-targets -- -D warnings,cargo fmt --checkpass
References
- docs/architecture/decisions/004-auth-dispositions.md (decision 1 — the format invariant)
- docs/architecture/auth.md §The bridge (step 2)
- docs/research/poc-1-auth-bridge.md §1 (the parity checkpoint)
- docs/research/auth-bridge.md §The mapping (step 2)
Notes
Design:
src/fingerprint.rsexposesfingerprint(&public_key) -> String— the thin wrapper over thessh-keyre-export (key.fingerprint(HashAlg::Sha256).to_string(); russh 0.65 re-exportsssh_key::{PublicKey, HashAlg}viarussh::keys), so the computation and formatting stay ssh-key's own code and parity is structural, not re-implemented.lib.rsre-exportsalkssh::fingerprint; a grep oversrc/confirms no second formatting path (doc mentions only). The russh 0.65 handler shape feeds exactly this type:VerifiedPublicKey.public_key: & ssh_key::PublicKey— the auth bridge (wave 2, w1-host-key-policy) passes that field straight through.Fact-check finding (doc correction landed): the ADR-004 / auth.md / task wording "unpadded url-safe base64" is a misnomer. The ssh-key crate's
FingerprintDisplay emitsSHA256:+ unpadded standard base64 (base64ctBase64Unpadded= the standard+/alphabet), and OpenSSH does the same — the committedssh-keygen -lfvectors contain+and/. The binding invariant was never "url-safe"; it is byte-parity with standard issuers, which POC-1 proved and the committed vectors now pin. Corrected the wording in ADR-004 andauth.md(the two places that spell the format); the parity contract itself is unchanged on both sides.Vectors: 4 throwaway ed25519 keys generated with local ssh-keygen (OpenSSH 9.6p1), blobs committed under
tests/vectors/*.pub, expected fingerprints byte-verbatim fromssh-keygen -lfrecorded intests/vectors/fingerprints.txt(provenance header included) and inlined intests/fingerprint_parity.rs. Tests cross-check the inlined vectors against the committed files and manifest so a stale fixture edit cannot silently pass. No secret material committed (private halves never left the tmpdir and were discarded).
Summary
Landed
src/fingerprint.rs— the crate's single fingerprint path (alkssh::fingerprint), delegating computation/formatting to the ssh-key re-export behind russh 0.65's keys module withHashAlg::Sha256. Parity proven, not assumed: 4 committed ed25519 fixtures withssh-keygen -lf(OpenSSH 9.6p1) recorded fingerprints reproduce byte-identically (tests/ fingerprint_parity.rs, incl. shape/format-of-registered-string assertions). Found and corrected a misnomer in the docs: the format is unpadded standard base64, not url-safe (OpenSSH fingerprints contain+/; byte-parity withssh-keygenis and always was the contract). Verified:cargo test(10/10 incl. all-features),cargo clippy --all-targets -- -D warnings(default + all-features),cargo fmt --check,cargo doc --no-depsclean;taskgraph validateclean.