Files
alkssh/tasks/implementation/w1-fingerprint.md
T
glm-5.3-flash 635e82b54b feat(fingerprint): land the single fingerprint path + ssh-keygen parity vectors
- 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
2026-10-28 06:27:49 +00:00

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
w1-manifest
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-key re-export (HashAlg::Sha256): the SHA256: + 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 --check pass

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.rs exposes fingerprint(&public_key) -> String — the thin wrapper over the ssh-key re-export (key.fingerprint(HashAlg::Sha256).to_string(); russh 0.65 re-exports ssh_key::{PublicKey, HashAlg} via russh::keys), so the computation and formatting stay ssh-key's own code and parity is structural, not re-implemented. lib.rs re-exports alkssh::fingerprint; a grep over src/ 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 Fingerprint Display emits SHA256: + unpadded standard base64 (base64ct Base64Unpadded = the standard +/ alphabet), and OpenSSH does the same — the committed ssh-keygen -lf vectors 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 and auth.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 from ssh-keygen -lf recorded in tests/vectors/fingerprints.txt (provenance header included) and inlined in tests/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 with HashAlg::Sha256. Parity proven, not assumed: 4 committed ed25519 fixtures with ssh-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 with ssh-keygen is 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-deps clean; taskgraph validate clean.