Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ the CBOM/report/eval schema versions, the database) can change in a minor releas
each part ends with the issues found in it. HSTS shows the header as sent.
- **Inventory:** algorithms *By class* and *By classical strength* (`?strength=`: broken, below-112, 112, 128,
192, 256, not-rated), each bar opening its list; the list is weakest first, with a bits bar.
- **SSH reports:** the algorithm tables use the bits bar and a post-quantum column.
- **SSH reports** ([PRD-014](docs/product/PRD-014-ssh-instruments.md),
[UX-DESIGN-012](docs/product/UX-DESIGN-012-ssh-instruments.md)) get the same one-stop Configuration: version and
software (what a current client gets, as a banner), key exchange (readiness, then each method as a row with its
bits bar, post-quantum glyph and baseline mark), host keys (a card per key), ciphers, MACs and compression, and
the baseline (a tile per requirement linking to its source, the changes as chips in their parts, the
`sshd_config` lines). The Summary has the same four-figure strip, and the baseline is line 1 of *Fix first*.
Checked by [CRYPTO-REVIEW-002](docs/product/CRYPTO-REVIEW-002-ssh-instruments.md).
- **Scanner:** a TLS scan records whether the server negotiates the heartbeat extension (RFC 6520).
- Every number and claim on these screens was checked against its source
([CRYPTO-REVIEW-001](docs/product/CRYPTO-REVIEW-001-visual-rebuild.md)).
Expand Down Expand Up @@ -93,6 +99,11 @@ the CBOM/report/eval schema versions, the database) can change in a minor releas

### Fixed

- **SSH evaluation (eval/11; stored scans are re-evaluated on start):**
- a truncated MAC is as strong as its tag: hmac-sha1-96 is 96 bits, not 128 (NIST SP 800-107 Rev. 1);
- the next steps name OpenSSH releases only to a server that identifies as OpenSSH;
- a baseline rule with nothing to judge (the RSA size rule on a server with no RSA key) says it does not apply
instead of *Met*.
- **Single-DES suites (56-bit key) are Insecure, not Weak** (#18).
- **The TLS hygiene figure on a report's Summary opened *About this report*.** It now opens how the score was worked
out, on Weaknesses.
Expand Down
2 changes: 1 addition & 1 deletion docs/methodology.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The code is `internal/algo/strength.go` and `strength_of.go`.
| RSA modulus, finite-field DH prime | General Number Field Sieve: E(L) = (1.923·∛(L·ln 2)·∛((ln(L·ln 2))²) − 4.69)/ln 2, rounded to the nearest multiple of eight, at most 256. 1024 → 80, 2048 → 112, 3072 → 128, 4096 → 152, 8192 → 200 | FIPS 140-3 IG D.B; SP 800-56B Rev. 2 Appendix D, Table 4; SP 800-56A Rev. 3, Table 26 |
| Elliptic curves | Half the bit length of the base point's order, taken to the nearest strength SP 800-186 assigns (80, 112, 128, 192, 224, 256): P-256 and Curve25519 → 128, P-384 → 192, Curve448 → 224, P-521 → 256 | SP 800-186 §3 and Table 1 |
| Symmetric ciphers | AES-k → k; 3DES (3TDEA) → 112, disallowed for encryption after 2023; DES, RC4, RC2 → broken. Ciphers NIST does not rate (ChaCha20, Camellia, ARIA, SEED, …) get the bound an exhaustive key search sets, labelled as such | SP 800-57 Part 1 Rev. 5 Table 2; SP 800-131A Rev. 2; RFC 7465 |
| Hashes and MACs | Signatures, where collision resistance is needed: SHA-256 → 128, SHA-384 → 192, SHA-512 → 256; SHA-1 and MD5 → broken. HMAC, a KDF or a PRF (the TLS PRF, HKDF): SHA-1 → 128, SHA-256 and longer → 256 | SP 800-57 Part 1 Table 3 |
| Hashes and MACs | Signatures, where collision resistance is needed: SHA-256 → 128, SHA-384 → 192, SHA-512 → 256; SHA-1 and MD5 → broken. HMAC, a KDF or a PRF (the TLS PRF, HKDF): SHA-1 → 128, SHA-256 and longer → 256. A truncated MAC (hmac-sha1-96, umac-64) is bounded by its tag: the smaller of the two (eval/11) | SP 800-57 Part 1 Table 3; SP 800-107 Rev. 1 §5.3.5 |
| Signature algorithms | The weaker of the hash (collision strength) and the signer's key, in every spelling (ECDSA-SHA256, SHA256-RSA, sha256WithRSAEncryption, SHA256withRSA). Without the key's size, the hash, and the basis says the key was not given | SP 800-57 Part 1 Tables 2 and 3 |
| Post-quantum algorithms | The classical equivalent of their NIST category: ML-KEM-512/768/1024 → 128/192/256, ML-DSA-44/65/87 → 128/192/256, SLH-DSA by its level | FIPS 203, 204, 205 |
| Hybrids | Secure while either part is, so their stronger part: X25519MLKEM768 → 192 | RFC 10024, RFC 10042 |
Expand Down
101 changes: 101 additions & 0 deletions docs/product/CRYPTO-REVIEW-002-ssh-instruments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# CRYPTO-REVIEW-002 · Every number and claim on the rebuilt SSH report (PRD-014)

Date: 2026-10-21. Reviewer role: cryptographer (PRD-014 REQ-SSV-9). Build: branch `feat/ssh-instruments`, stacked
on `feat/classes-and-x509` (PRD-013). Scope: what the SSH Summary and Configuration *show*: each number, word,
glyph, tooltip and sentence, checked against the report and evaluation it is drawn from and against the source
cited. The SSH rules and strengths themselves were reviewed for PRD-008 and PRD-010 (CRYPTO-REVIEW-001 covers the
shared scale); they are re-read here only where a screen states them.

Data: the CI journey's SSH demo servers: 9460 (hybrid key exchange, OpenSSH-style MACs), 9461 (classical), 9462
(legacy: SHA-1 groups, a 1024-bit RSA host key, CBC, 3DES, truncated MACs), 9463 (ML-DSA-65 host key), 9465
(SSH-1 only), 9467 (hardened to meet the baseline). Agreement between screen and API is checked by the journey
(E2E-H.2, E2E-VIS-6, E2E-VIS-8, E2E-VIS-9, E2E-VIS-10); this review checks that what is said is right.

## Verdict

**Signed off**, with the five defects below fixed in this branch (3 to 5 from a second evaluation the owner asked for) and two notes left as they are, each with its
reason. No number on the SSH screens disagrees with its cited source.

## Numbers checked

| Shown | Value | Source | Holds |
|---|---|---|---|
| Hybrid key exchange | mlkem768x25519-sha256 → 192 | the stronger part (RFC 10042; ML-KEM-768 is category 3, FIPS 203) | yes |
| Elliptic-curve key exchange and host keys | curve25519-sha256, ssh-ed25519, ecdsa-sha2-nistp256 → 128 | SP 800-186 Table 1 (half the base-point order) | yes |
| Finite-field groups | group14 (2048-bit MODP) → 112; group1 (1024-bit, Oakley 2) → 80 | SP 800-57 Part 1 Rev. 5, Table 2 | yes |
| RSA host-key algorithms | rsa-sha2-256 on a 1024-bit key → 80; ssh-rsa (SHA-1) → broken | SP 800-57 Table 2; SP 800-131A Rev. 2 (SHA-1 disallowed for signature generation) | yes |
| ML-DSA host key | ssh-mldsa-65 → 192 | FIPS 204, category 3 | yes |
| Ciphers | AES-128/192/256 (CTR, GCM, CBC) by key; 3DES → 112, disallowed; chacha20-poly1305 → 256 by its key | SP 800-57 Table 2; SP 800-131A; RFC 8439 | yes |
| MACs | HMAC-SHA-1 → 128; HMAC-SHA-256 and -512 → 256 | SP 800-57 Table 3, HMAC column | yes (see note 1) |
| Host-key card | the strongest signature the key answers to: RSA 1024 → 80 (rsa-sha2-256, not ssh-rsa); Ed25519 → 128; ML-DSA-65 → 192 | as above | yes |
| Weakest classical strength (Summary) | the weakest rated algorithm offered: on 9462 ssh-rsa, broken; on 9460 128 bits | the evaluation's strengths | yes (E2E-VIS-10) |
| Readiness L0 to L4 | stepper filled to the evaluation's level: 9460 L3, 9461 L1, 9463 L4, 9465 L0 | PRD-008 SSH readiness | yes (E2E-H.1b, E2E-VIS-9) |
| Fingerprints | `SHA256:` base64 of the host-key blob, as `ssh-keygen -l` prints it | RFC 4253 §6.6 blob; OpenSSH fingerprint format | yes |

## Claims checked

- **"Every list here is in the server's order; in each, the client's order decides (RFC 4253 §7.1)."** RFC 4253
§7.1: the chosen algorithm is the first on the client's name-list that is also on the server's, for key exchange,
host keys, ciphers, MACs and compression alike. So the rows carry no rank numbers, unlike TLS's suites (where the
server may pick). Correct after fix 2.
- **"A current client gets" + four chips, "signature verified".** The scan's own negotiation with OpenSSH 10.6's
default lists, carried out to the host-key signature over the exchange hash, which verified. The banner names
the client in its tooltip. Correct.
- **"no MAC" with an AEAD cipher.** With [email protected] or [email protected] the negotiated MAC is
ignored (OpenSSH PROTOCOL §1.6 for [email protected]; PROTOCOL.chacha20poly1305). Correct.
- **Post-quantum glyphs.** Shield with a check on mlkem768x25519-sha256 and ssh-mldsa-65; shield with a cross on
curve25519, ECDH, finite-field DH, Ed25519, ECDSA and RSA; a dot on ciphers and MACs ("no post-quantum verdict").
See note 3.
- **Strict key exchange: "On: the countermeasure to Terrapin".** [email protected], OpenSSH 9.6
(CVE-2023-48795). *Not offered* is the problem tone only when the scan infers Terrapin is possible
(chacha20-poly1305, or CBC with encrypt-then-MAC, without strict key exchange); otherwise it needs attention.
Correct.
- **Compression: "[email protected], after login" and "zlib, before login".** [email protected] starts after user
authentication; plain zlib starts with the first NEWKEYS, before authentication. Correct.
- **Protocol tile.** "SSH-2 only" for 2.0; "SSH-2, and SSH-1 accepted" for 1.99 (RFC 4253 §5.1); "SSH-1 only" for
1.x. The identification string is shown as sent. Correct.
- **"Lines before the identification".** RFC 4253 §4.2 allows them; shown as a count, in no tone. Correct.
- **Software.** "As the server announces it. Its version is not matched against vendor advisories." True: the
scanner reads the banner only; *Server software flaws* stays *Not tested* under Weaknesses.
- **Baseline requirements.** Each tile links to its cited source (RFC 10042; OpenSSH 9.6 release notes;
SP 800-57 Table 2 for 3072-bit RSA, i.e. 128-bit strength). The *Met / Not met* states equal the evaluation's.
- **The changes.** − remove, + add, ↑ upgrade, ⟲ replace a key; each chip's tooltip is the evaluation's own reason
and source. The `sshd_config` hint ("sshd keeps the first value of each keyword") is sshd_config(5)'s rule.
Correct.

## Defects found and fixed in this branch

1. **The Summary's Host key tile drew a 1024-bit RSA key in the good tone.** It was toned by post-quantum status
alone (classical → green). It now follows the key's strength: weak or broken in the problem tone, acceptable in
the attention tone, strong green, post-quantum the L4 colour.
2. **"Listed in the server's order; the client's order decides" stood on Key exchange alone**, which could read as
if the other lists were preferences. RFC 4253 §7.1 applies the rule to every list; the aside now says so.

3. **Truncated MACs were rated by their HMAC** (the first review's note 1, now fixed). hmac-sha1-96 showed 128 bits,
but a 96-bit tag lets a forger guess right with probability 2⁻⁹⁶ per attempt: SP 800-107 Rev. 1 §5.3.5 bounds a
truncated MAC by its tag. The strength is now the smaller of the HMAC's and the tag's (hmac-sha1-96 → 96,
umac-64 → 64), with the reason in its basis. `TestTruncatedMACIsBoundedByItsTag`. eval/11.
4. **The next steps told every server to "Upgrade to OpenSSH 9.9"**, including the demo servers that identify as Go.
OpenSSH releases are now named only to a server that identifies as OpenSSH; any other is told what to offer
(mlkem768x25519-sha256 first; strict key exchange), with OpenSSH as the reference point.
`TestSSHNextStepsNameOpenSSHOnlyForOpenSSH`.
5. **"RSA host keys are at least 3072 bits: Met" on servers with no RSA key.** Nothing was judged, so *Met* claimed a
check that never ran. The requirement now carries `notApplicable` and the tile says *Does not apply: the server has
no RSA host key*; the verdict is unchanged. `TestRSASizeRuleWithoutAnRSAKeyDoesNotApply`.

## Notes left as they are

1. **SHA-1 key exchanges are rated by their group.** diffie-hellman-group14-sha1 shows 112 bits (the 2048-bit
group); its SHA-1 exchange hash is what puts it on *should be off* (SSH.KEX-SHA1, RFC 9142), and the row now says so
beside the mark (*a SHA-1 key exchange*). The bar stays the group's strength and the mark carries the SHA-1 risk;
kept.
2. **Ciphers and MACs carry a dot, not a shield.** The TLS class map and the Inventory mark AES as quantum-safe
(NIST IR 8547; Grover gives no practical break), while the SSH rows give ciphers and MACs no post-quantum
verdict, as PRD-013 drew them. Both are true statements; the dot's tooltip says *no post-quantum verdict*, not
*safe* or *vulnerable*. Kept, so the SSH page does not imply that its ciphers were classified by a source they
were not.

## Sign-off

The numbers and claims on the SSH Summary and Configuration are correct against their sources, with fixes 1 to 5
in this branch. Signed off for PRD-014 REQ-SSV-9, cryptography.
32 changes: 32 additions & 0 deletions docs/product/PRD-014-ssh-instruments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# PRD-014 · The SSH report, as instruments

Status: draft 2026-10-21, from the owner's PRD-013 verdict ("instruments, not paragraphs"), applied to the SSH
server report. Design: [UX-DESIGN-012](UX-DESIGN-012-ssh-instruments.md), an addendum to UX-DESIGN-011. The data,
the API and the evaluation stay as they are; this is a front-end change. Sign-offs: the cryptographer
(CRYPTO-REVIEW-002) and the PM's walk (QA-REPORT-013).

## Why

PRD-013 rebuilt the TLS report on shared instruments. The SSH report kept its PRD-008 layout: a baseline card of
prose, fact cards that say each thing as a sentence and again as a bullet, and bullet lists of citations. Only its
algorithm tables used `bitsBar` and `pqGlyph` (REQ-VIS-10). The owner rejected that kind of screen for TLS; an SSH
reviewer should get the same one-stop page.

## Requirements

| ID | Requirement | Acceptance | Test | Pri |
|---|---|---|---|---|
| **REQ-SSV-1** | **One Configuration page in a reviewer's order** (UX-DESIGN-012 §3): version and software, key exchange, host keys, ciphers, MACs and compression, baseline changes; a sticky jump row with each part's state; About this report last. | The parts are in that order and the jump row leads to each | `script:testing/e2e/visual-phase.mjs#E2E-VIS-8` | P0 |
| **REQ-SSV-2** | **The algorithm rows** (§3.1): every algorithm the evaluation lists, in the server's order, with the bits bar, the post-quantum glyph for key exchange and host keys, and the baseline mark; the row a current client uses is marked. | The rows equal `sshAlgorithms` kind by kind, and each bar, glyph and mark agrees with it | `script:testing/e2e/visual-phase.mjs#E2E-VIS-6` | P0 |
| **REQ-SSV-3** | **Version, key exchange and host keys as instruments**: the negotiated banner, status tiles (protocol, software, strict key exchange, compression), the readiness row with the stepper, a card per host key with its verification, and a dashed card for a key not fetched. | The banner equals the report's negotiated algorithms; the tiles agree with the report | `script:testing/e2e/visual-phase.mjs#E2E-VIS-9` | P0 |
| **REQ-SSV-4** | **Baseline as tiles and chips**: verdict tile, a tile per requirement (met or not), the changes as chips, the `sshd_config` lines with Copy. A server that meets it shows no lines. | Tiles equal the evaluation's requirements; chips equal its changes | `script:testing/e2e/ssh-phase.mjs#E2E-H.2`, `script:testing/e2e/ssh-phase.mjs#E2E-H.2c` | P0 |
| **REQ-SSV-5** | **Each part ends with its issues**: the findings of that part, each linking to its evidence, and the baseline changes that fall in it. | Every finding of the evaluation (bar the published attacks) is named under exactly one part | `script:testing/e2e/visual-phase.mjs#E2E-VIS-8` | P0 |
| **REQ-SSV-6** | **Citations in tooltips**: no bullet list of sources on the SSH Configuration; each source is a tooltip (and a link where it is a requirement). | No `ul.cites` on the page; every requirement tile names its source | `script:testing/e2e/visual-phase.mjs#E2E-VIS-8` | P1 |
| **REQ-SSV-7** | **The SSH Summary** (§2): readiness with the stepper, the baseline, the weakest classical strength with a bits bar, the host key; the baseline as the first Fix first line in the shared row shape, no "Why it matters" block. | Four tiles; the weakest strength equals the evaluation's weakest rated algorithm | `script:testing/e2e/visual-phase.mjs#E2E-VIS-10` | P1 |
| **REQ-SSV-8** | **Fit and access**: the SSH Summary and Configuration fit 1440, 1100, 860 and 375 px with no sideways scroll, every control reachable by Tab, instrument text at 4.5:1 in light and dark; an SSH-1-only server's report still renders every part. | | `script:testing/e2e/visual-phase.mjs#E2E-VIS-7`, `script:testing/e2e/ssh-phase.mjs#E2E-H.2b` | P0 |
| **REQ-SSV-9** | **Sign-off**: a cryptographer checks every number and claim the SSH screens show (CRYPTO-REVIEW-002); the PM walks every SSH screen (QA-REPORT-013). | | `report:docs/product/CRYPTO-REVIEW-002-ssh-instruments.md` | P0 |

## Out of scope

- No change to the SSH evaluation, the baseline, the API or the PDF.
- The SSH servers list, Overview, Findings and Help keep their PRD-008 layout.
3 changes: 2 additions & 1 deletion docs/product/UX-DESIGN-011-instruments-not-paragraphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ Top to bottom:

### 3.5 SSH report

The algorithm tables use `bitsBar` and `pqGlyph` in place of the words column. No other change.
The algorithm tables use `bitsBar` and `pqGlyph` in place of the words column. Superseded by
[UX-DESIGN-012](UX-DESIGN-012-ssh-instruments.md) (PRD-014), which rebuilds the whole SSH report.

## 4. Responsive and accessible

Expand Down
Loading
Loading