summaryrefslogtreecommitdiff
path: root/net-analyzer/ssh-audit/files/ssh-audit-3.9.0_p20261011_add_ssh-mldsa44-ed25519.patch
blob: a383ca925da8b90a04f2d12455ac78dad402e50d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
Derived from: https://github.com/jtesta/ssh-audit/pull/379

commit ae16f4e55128d3dfaa11bcc231bf93cca9181a0f Mon Sep 17 00:00:00 2001
Author: =?UTF-8?q?Nicol=C3=B2=20Sala?= <me@niceo.org>
Date: Wed, 7 Oct 2026 11:17:41 +0200
Subject: [PATCH] Add ssh-mldsa44-ed25519 host key (OpenSSH 10.6)

OpenSSH 10.6 enables the hybrid post-quantum ssh-mldsa44-ed25519
signature algorithm without the "@openssh.com" suffix used by the
previous experimental implementation, which was removed.

- Add ssh-mldsa44-ed25519 (available since OpenSSH 10.6).
- Mark ssh-mldsa44-ed25519@openssh.com as available in OpenSSH
  10.4-10.5 only, with a note that it was removed in 10.6.
- Don't recommend adding algorithms to software newer than the last
  version that supports them, so OpenSSH 10.6+ no longer gets the old
  name suggested.
- Add a test covering the recommendations for OpenSSH 10.3 to 10.7.

Fixes #378

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--- a/README.md
+++ b/README.md
@@ -257,6 +257,7 @@
  - Added support for Python 3.15.
  - Fixed a perhaps rare crash when performing connection rate tests during standard audits.
  - Added `-V`/`--version` flag to print version and terminate; credit [Christian Krause](https://github.com/wookietreiber).
+ - Added 1 new host key: `ssh-mldsa44-ed25519` (the final name used since OpenSSH 10.6).  The experimental `ssh-mldsa44-ed25519@openssh.com` was removed in OpenSSH 10.6, so it is now marked as such and is no longer recommended for OpenSSH 10.6 and later.
 
 ### v3.9.0 (2026-07-04)
  - BIG THANKS to [realmiwi](https://github.com/realmiwi) for being the project's *very first sponsor!!*
--- a/src/ssh_audit/algorithms.py
+++ b/src/ssh_audit/algorithms.py
@@ -141,6 +141,17 @@
                             break
                         if not matches:
                             continue
+                    removed = False
+                    if (software is not None) and (len(versions) > 1):
+                        # The last version supporting this algorithm is the second entry for servers, and the last entry for clients.
+                        till_versions = versions[1] if for_server else versions[-1]
+                        for v in (till_versions or '').split(','):
+                            ssh_prefix, ssh_version, is_cli = Algorithm.get_ssh_version(v)
+                            if (not ssh_version) or (ssh_prefix != software.product) or (is_cli and for_server):
+                                continue
+                            if software.compare_version(ssh_version) > 0:
+                                removed = True
+                            break
                     adl, faults = len(alg_desc), 0
                     for i in range(1, 3):
                         if not adl > i:
@@ -153,7 +164,7 @@
                         if faults > 0 or \
                            (alg_type == 'key' and (('-cert-' in n) or (n.startswith('sk-')))) or \
                            (alg_type == 'kex' and (n.startswith('ext-info-') or n.startswith('kex-strict-'))) or \
-                           empty_version:
+                           empty_version or removed:
                             continue
                         rec[sshv][alg_type]['add'][n] = 0
                     else:
--- a/src/ssh_audit/ssh2_kexdb.py
+++ b/src/ssh_audit/ssh2_kexdb.py
@@ -77,6 +77,7 @@
     INFO_REMOVED_IN_OPENSSH61 = 'removed since OpenSSH 6.1, removed from specification'
     INFO_REMOVED_IN_OPENSSH69 = 'removed in OpenSSH 6.9: https://www.openssh.com/txt/release-6.9'
     INFO_REMOVED_IN_OPENSSH70 = 'removed in OpenSSH 7.0: https://www.openssh.com/txt/release-7.0'
+    INFO_REMOVED_IN_OPENSSH106 = 'removed in OpenSSH 10.6 (replaced by ssh-mldsa44-ed25519): https://www.openssh.com/txt/release-10.6'
     INFO_WITHDRAWN_PQ_ALG = 'the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security'
     INFO_EXTENSION_NEGOTIATION = 'pseudo-algorithm that denotes the peer supports RFC8308 extensions'
     INFO_STRICT_KEX = 'pseudo-algorithm that denotes the peer supports a stricter key exchange method as a counter-measure to the Terrapin attack (CVE-2023-48795)'
@@ -272,7 +273,8 @@
             'ssh-mldsa-65': [[], [], [], [INFO_NIST_PQC_LEVEL_3]],
             'ssh-mldsa-87': [[], [], [], [INFO_NIST_PQC_LEVEL_5]],
             'ssh-mldsa44': [[], [], [], [INFO_NIST_PQC_LEVEL_2]],
-            'ssh-mldsa44-ed25519@openssh.com': [['10.4'], [], [], [INFO_NIST_PQC_LEVEL_2]],
+            'ssh-mldsa44-ed25519': [['10.6'], [], [], [INFO_NIST_PQC_LEVEL_2]],
+            'ssh-mldsa44-ed25519@openssh.com': [['10.4', '10.5'], [], [], [INFO_NIST_PQC_LEVEL_2, INFO_REMOVED_IN_OPENSSH106]],
             'ssh-mldsa65': [[], [], [], [INFO_NIST_PQC_LEVEL_3]],
             'ssh-mldsa87': [[], [], [], [INFO_NIST_PQC_LEVEL_5]],
             'ssh-rsa1': [[], [FAIL_SHA1]],
--- a/test/test_algorithms.py
+++ b/test/test_algorithms.py
@@ -0,0 +1,41 @@
+import os
+import pytest
+
+from ssh_audit.algorithms import Algorithms
+from ssh_audit.outputbuffer import OutputBuffer
+from ssh_audit.product import Product
+from ssh_audit.software import Software
+from ssh_audit.ssh2_kex import SSH2_Kex
+from ssh_audit.ssh2_kexparty import SSH2_KexParty
+
+
+# pylint: disable=attribute-defined-outside-init
+class TestAlgorithms:
+    @pytest.fixture(autouse=True)
+    def init(self, ssh_audit):
+        cli = SSH2_KexParty([], [], ['none'], [])
+        srv = SSH2_KexParty([], [], ['none'], [])
+        kex = SSH2_Kex(OutputBuffer(), os.urandom(16), ['mlkem768x25519-sha256'], ['ssh-ed25519'], cli, srv, False)
+        self.algs = Algorithms(kex)
+
+    def _key_additions(self, openssh_version):
+        software = Software(None, Product.OpenSSH, openssh_version, None, None)
+        _, rec = self.algs.get_recommendations(software)
+        return rec[2]['key']['add']
+
+    def test_mldsa44_ed25519_recommendations(self):
+        '''Ensures that the experimental "@openssh.com" name is only recommended for OpenSSH 10.4 & 10.5, and the final name from 10.6 onwards.'''
+
+        add = self._key_additions('10.3')
+        assert 'ssh-mldsa44-ed25519@openssh.com' not in add
+        assert 'ssh-mldsa44-ed25519' not in add
+
+        for version in ['10.4', '10.5']:
+            add = self._key_additions(version)
+            assert 'ssh-mldsa44-ed25519@openssh.com' in add
+            assert 'ssh-mldsa44-ed25519' not in add
+
+        for version in ['10.6', '10.7']:
+            add = self._key_additions(version)
+            assert 'ssh-mldsa44-ed25519@openssh.com' not in add
+            assert 'ssh-mldsa44-ed25519' in add