Files
alkssh/docs/architecture/decisions/002-russh-pin.md
T
glm-5.3-flash ab6fb9de87 docs(architecture): resolve all open questions (OQ-01..13), mark specs reviewed
- OQ-08: shell convention = assembly-supplied serve config (shell argv
  for shell_request; exec wrapper argv + command string for exec; no
  crate default; unset -> clean decline)
- OQ-11: direct-streamlocal = universal compile + runtime Unix-gated
  decline (channel and listen flow)
- OQ-10: closed as contract + upstream constraint; derivation rules
  formalized in mapping.md (Exit chunk -> SSH exit reporting), incl.
  the -1/genuine-SIGHUP fidelity tradeoff and an unmapped-negative
  fallback rule
- OQ-01/04/09/13: resolved as fully-decided dispositions (ADR-001/
  ADR-004/fixed decline postures); remainders were forecasts about
  consumers, not pending alkssh decisions; upstream deps now listed
  as watch items, not OQs
- OQ-12 restored to the tracker (dropped in the rewrite)
- review-agent criticals/warnings fixed: exec-unset + wrap mechanics
  specified, streamlocal listen gate added, stale deferred/tracked
  language removed, ADR-006 title fixed, 0.64.1-vs-0.65.0 crosswalk
  added in ADR-004, ADR frontmatter aligned to 'reviewed'

All specs + ADRs 001-006 now reviewed; implementation may begin.
2026-10-28 05:08:01 +00:00

6.2 KiB

status, last_updated
status last_updated
reviewed 2026-10-28

ADR-002: The russh pin — 0.65.0, aws-lc-rs, no compression, ed25519-only

Status

Accepted — 2026-10-26. A one-way door in practice (SSH negotiation behavior crosses crate boundaries; bumps are deliberate, tested, and recorded per the repo's wire-stability convention). Amended same day after review: the earlier enabling of the rsa feature is reverted (rsa off). Amended 2026-10-27 (review pass): the key-algorithm position is ed25519-only — the family's posture is the binding constraint, not fleet compatibility (decision 4).

Context

russh.md documents the crate inventory and the pin questions; the 2026-10-26 re-verification section carries the current facts. The POCs validated against 0.64.1 (then-newest) with the ring backend; since then 0.65.0 has been published (2026-10-25) with six security fixes — three in classes an internet-facing SSH door cares about (client EXT_INFO unbounded allocation, peer zero-max-packet-size channel stall, pre-auth nested-certificate stack exhaustion) — and two breaking changes confined to handler-signature shapes (PublicKeyOffer / VerifiedPublicKey; async-trait feature removed).

The family's crypto-posture context: alktls, alkhttp, and alknet all standardize on rustls with the aws_lc_rs feature; no family crate links ring. The provider choice matters only as binary-composition hygiene — when alkforge's binary links alkssh and the family's rustls stack, one shared primitive library is the goal — and has nothing to do with TLS on the SSH wire.

Decision

  1. Pin russh = "0.65" (caret-compatible within 0.65.x, matching the family's "0.10"-style convention; russh minors have broken API before, so the caret stops at the minor). 0.65.0 over 0.64.1: current published + the three security fixes above; the breaking changes land inside the handler surface alkssh implements anyway. POC evidence transfers (wire behavior unchanged); the implementation phase re-verifies the POC-1 decline matrix against 0.65 as contract tests.
  2. Crypto backend: aws-lc-rs. Family-confirmed (alktls / alkhttp / alknet all rustls(aws_lc_rs); nothing in-family links ring) and it is russh's own default. Verified in-scratch: builds clean in ~50 s with no external provisioning (prebuilt bindings), tree aws-lc-rs 1.18.2 / aws-lc-sys 0.46.0. The POCs' ring build is recorded as the fallback if a target platform ever fails to provision aws-lc — a deliberate, recorded deviation, never drift.
  3. flate2 off — no compression. The POCs already ran compression-free and vanilla OpenSSH was untroubled; SSH compression is largely pointless at modern link layers and is the CRIME-adjacent attack surface OpenSSH itself defaults off. Bounded-resources and surface-reduction posture agree.
  4. ed25519-only — rsa off, and no other scheme is supported. Amended 2026-10-27 from the earlier "ed25519-first" wording after review: the position is ed25519-only. One key algorithm carries the family's identity: the same ed25519 keys serve alktls's self-signed TLS certificates and iroh, and the downstream alknet rewrite rides ssh + ed25519, tcp + tls, quic + tls, and iroh — the same ed25519 identity. The legacy/alternative SSH key schemes (rsa, dsa; ecdsa variants and hardware-token sk variants share the defect) are issued, stored, or derived nowhere in the family — supporting them here would be a wart backed by nothing else. Enabling rsa would additionally have pulled two RC-pinned deps and made alkssh the family's only RSA-holding crate. Concretely: the tree drops rsa =0.10.0-rc.18 and pkcs1 =0.8.0-rc.4 entirely (verified: the ["aws-lc-rs"]-only build is clean and RC-free except ssh-key =0.7.0-rc.11, which russh exact-pins on the russh::keys path). Wire behavior is honest and fail-closed: a client presenting a non-ed25519 key gets a clean USERAUTH_FAILURE — never a half-open session. Operational shape: alkssh implements no other scheme; an assembly registers ed25519 fingerprints only; and auth_publickey declines non-ed25519 keys explicitly (ADR-004's explicit-over-inherited pattern applied to the algorithm position, so the posture survives a pin bump that might otherwise accept more schemes). If a scheme ever matters, the amendment is one feature flag plus this ADR.
  5. des / dsa never. russh's own "Danger: insecure" features — no alkssh configuration may enable them.
  6. Manifest lands with the dependency: rust-version = "1.89" (russh's MSRV; supersedes the current 1.88) and, with it, the edition-2024 bump the POCs compiled under.

Consequences

  • Positive: the pin is current, carries the security fixes, and matches the family crypto posture; the tree is fully inventoried — with rsa off it is RC-free except ssh-key =0.7.0-rc.11 (unavoidable: russh exact-pins it on the russh::keys path); MSRV/licensing are explicit.
  • Negative: clients presenting non-ed25519 keys (RSA among them) decline outright (clean USERAUTH_FAILURE) — recorded as intentional; ssh-key's RC pin rides the russh keys path until russh moves off it; aws-lc-rs is the heavier build (proven acceptable here, with ring as the recorded fallback).
  • Neutral: at 0.65.0 the key arrives as VerifiedPublicKey.public_key with the client's signature .algorithm exposed; the ed25519-only posture (decision 4) acts on the key-algorithm fact at auth_publickey, and the .algorithm field remains available for further hardening if ever wanted. ADR-004 carries the matching amendment note; its other dispositions are unchanged.

References

  • docs/research/russh.md (inventory + the 2026-10-26 re-verification section with the scratch-build record)
  • docs/research/poc-1-auth-bridge.md (the 0.64.1 wire evidence; backend note), docs/research/poc-2-vault-keys.md, docs/research/poc-3-mapping-bakeoff.md (0.64.1 runtime facts)
  • ADR-001 (the pin context), ADR-003 (feature graph the russh features compose under), ADR-004 (auth dispositions on this surface)
  • Family: alktls/alkhttp/alknet manifests (the aws-lc-rs posture), family ADR-002 decision 5