11 Commits

28 changed files with 1750 additions and 525 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -U codecov coveralls flake8 mypy pylint pytest tox vulture pip install -U codecov coveralls flake8 mypy pylint pytest tox
- name: Run Tox - name: Run Tox
run: | run: |
tox tox
+39 -4
View File
@@ -48,7 +48,22 @@ usage: ssh-audit.py [options] <host>
-c, --client-audit starts a server on port 2222 to audit client -c, --client-audit starts a server on port 2222 to audit client
software config (use -p to change port; software config (use -p to change port;
use -t to change timeout) use -t to change timeout)
--conn-rate-test=N[:max_rate] perform a connection rate test (useful
for collecting metrics related to
susceptibility of the DHEat vuln).
Testing is conducted with N concurrent
sockets with an optional maximum rate
of connections per second.
-d, --debug Enable debug output. -d, --debug Enable debug output.
--dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack
(CVE-2002-20001) against the target using N
concurrent sockets. Optionally, a specific
key exchange algorithm can be specified
instead of allowing it to be automatically
chosen. Additionally, a small length of
the fake e value sent to the server can
be chosen for a more efficient attack (such
as 4).
-g, --gex-test=<x[,y,...]> dh gex modulus size test -g, --gex-test=<x[,y,...]> dh gex modulus size test
<min1:pref1:max1[,min2:pref2:max2,...]> <min1:pref1:max1[,min2:pref2:max2,...]>
<x-y[:step]> <x-y[:step]>
@@ -68,6 +83,9 @@ usage: ssh-audit.py [options] <host>
-p, --port=<port> port to connect -p, --port=<port> port to connect
-P, --policy=<"policy name" | policy.txt> run a policy test using the -P, --policy=<"policy name" | policy.txt> run a policy test using the
specified policy specified policy
--skip-rate-test skip the connection rate test during standard audits
(used to safely infer whether the DHEat attack
is viable)
-t, --timeout=<secs> timeout (in seconds) for connection and reading -t, --timeout=<secs> timeout (in seconds) for connection and reading
(default: 5) (default: 5)
-T, --targets=<hosts.txt> a file containing a list of target hosts (one -T, --targets=<hosts.txt> a file containing a list of target hosts (one
@@ -132,6 +150,21 @@ To create a policy based on a target server (which can be manually edited):
ssh-audit -M new_policy.txt targetserver ssh-audit -M new_policy.txt targetserver
``` ```
To run the DHEat CPU exhaustion DoS attack ([CVE-2002-20001](https://nvd.nist.gov/vuln/detail/CVE-2002-20001)) against a target using 10 concurrent sockets:
```
ssh-audit --dheat=10 targetserver
```
To run the DHEat attack using the `diffie-hellman-group-exchange-sha256` key exchange algorithm:
```
ssh-audit --dheat=10:diffie-hellman-group-exchange-sha256 targetserver
```
To run the DHEat attack using the `diffie-hellman-group-exchange-sha256` key exchange algorithm along with very small but non-standard packet lengths (this may result in the same CPU exhaustion, but with many less bytes per second being sent):
```
ssh-audit --dheat=10:diffie-hellman-group-exchange-sha256:4 targetserver
```
## Screenshots ## Screenshots
### Server Standard Audit Example ### Server Standard Audit Example
@@ -180,19 +213,21 @@ For convenience, a web front-end on top of the command-line tool is available at
## ChangeLog ## ChangeLog
### v3.2.0-dev (???) ### v3.2.0 (2024-04-22)
- Added implementation of the DHEat denial-of-service attack (see `--dheat` option; [CVE-2002-20001](https://nvd.nist.gov/vuln/detail/CVE-2002-20001)).
- Expanded filter of CBC ciphers to flag for the Terrapin vulnerability. It now includes more rarely found ciphers. - Expanded filter of CBC ciphers to flag for the Terrapin vulnerability. It now includes more rarely found ciphers.
- Color output is disabled if the `NO_COLOR` environment variable is set (see https://no-color.org/).
- Fixed parsing of `ecdsa-sha2-nistp*` CA signatures on host keys. Additionally, they are now flagged as potentially back-doored, just as standard host keys are. - Fixed parsing of `ecdsa-sha2-nistp*` CA signatures on host keys. Additionally, they are now flagged as potentially back-doored, just as standard host keys are.
- Gracefully handle rare exceptions (i.e.: crashes) while performing GEX tests. - Gracefully handle rare exceptions (i.e.: crashes) while performing GEX tests.
- Built-in policies now include a change log (use `-L -v` to view them).
- Added built-in policies for Amazon Linux 2023, Debian 12, OpenSSH 9.7, and Rocky Linux 9.
- The built-in man page (`-m`, `--manual`) is now available on Docker, PyPI, and Snap builds, in addition to the Windows build. - The built-in man page (`-m`, `--manual`) is now available on Docker, PyPI, and Snap builds, in addition to the Windows build.
- Snap builds are now architecture-independent. - Snap builds are now architecture-independent.
- Changed Docker base image from `python:3-slim` to `python:3-alpine`, resulting in a 59% reduction in image size; credit [Daniel Thamdrup](https://github.com/dallemon). - Changed Docker base image from `python:3-slim` to `python:3-alpine`, resulting in a 59% reduction in image size; credit [Daniel Thamdrup](https://github.com/dallemon).
- Added built-in policies for Amazon Linux 2023, Debian 12, OpenSSH 9.7, and Rocky Linux 9.
- Built-in policies now include a change log (use `-L -v` to view them).
- Custom policies now support the `allow_algorithm_subset_and_reordering` directive to allow targets to pass with a subset and/or re-ordered list of host keys, kex, ciphers, and MACs. This allows for the creation of a baseline policy where targets can optionally implement stricter controls; partial credit [yannik1015](https://github.com/yannik1015). - Custom policies now support the `allow_algorithm_subset_and_reordering` directive to allow targets to pass with a subset and/or re-ordered list of host keys, kex, ciphers, and MACs. This allows for the creation of a baseline policy where targets can optionally implement stricter controls; partial credit [yannik1015](https://github.com/yannik1015).
- Custom policies now support the `allow_larger_keys` directive to allow targets to pass with larger host keys, CA keys, and Diffie-Hellman keys. This allows for the creation of a baseline policy where targets can optionally implement stricter controls; partial credit [Damian Szuberski](https://github.com/szubersk). - Custom policies now support the `allow_larger_keys` directive to allow targets to pass with larger host keys, CA keys, and Diffie-Hellman keys. This allows for the creation of a baseline policy where targets can optionally implement stricter controls; partial credit [Damian Szuberski](https://github.com/szubersk).
- Color output is disabled if the `NO_COLOR` environment variable is set (see https://no-color.org/).
- Added 1 new key exchange algorithm: `gss-nistp384-sha384-*`. - Added 1 new key exchange algorithm: `gss-nistp384-sha384-*`.
- Added 1 new cipher: `aes128-ocb@libassh.org`.
### v3.1.0 (2023-12-20) ### v3.1.0 (2023-12-20)
- Added test for the Terrapin message prefix truncation vulnerability ([CVE-2023-48795](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795)). - Added test for the Terrapin message prefix truncation vulnerability ([CVE-2023-48795](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795)).
+2 -2
View File
@@ -464,7 +464,7 @@ run_test() {
exit 1 exit 1
fi fi
./ssh-audit.py localhost:2222 > "$test_result_stdout" ./ssh-audit.py --skip-rate-test localhost:2222 > "$test_result_stdout"
actual_retval=$? actual_retval=$?
if [[ $actual_retval != "$expected_retval" ]]; then if [[ $actual_retval != "$expected_retval" ]]; then
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}" echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
@@ -478,7 +478,7 @@ run_test() {
exit 1 exit 1
fi fi
./ssh-audit.py -jj localhost:2222 > "$test_result_json" ./ssh-audit.py --skip-rate-test -jj localhost:2222 > "$test_result_json"
actual_retval=$? actual_retval=$?
if [[ $actual_retval != "$expected_retval" ]]; then if [[ $actual_retval != "$expected_retval" ]]; then
echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}" echo -e "${REDB}Unexpected return value. Expected: ${expected_retval}; Actual: ${actual_retval}${CLR}"
+7 -51
View File
@@ -137,45 +137,13 @@ class Algorithms:
for alg_pair in self.values: for alg_pair in self.values:
sshv, alg_db = alg_pair.sshv, alg_pair.db sshv, alg_db = alg_pair.sshv, alg_pair.db
rec[sshv] = {} rec[sshv] = {}
for alg_type, alg_list in alg_pair.items(): for alg_type, alg_list in alg_pair.items():
list_of_weights = []
if alg_type == 'aut': if alg_type == 'aut':
continue continue
# For each alg that is already enabled. Look up its assigned weighting.
# If it has a higher preference than current max or something more than current min
# add it to the list.
# Sort the list as we go to ensure largest numbers are furst
for alg_name_lst in alg_list:
for alg_name_look, alg_desc_look in alg_db[alg_type].items():
if str.lower(alg_name_look) == str.lower(alg_name_lst):
lst_weight = alg_desc_look[4]
lst_weight = int(lst_weight[0])
if not list_of_weights:
list_of_weights.insert(1, int(lst_weight))
elif lst_weight > max(list_of_weights):
list_of_weights.insert(1, int(lst_weight))
list_of_weights.sort(key=int, reverse=True)
elif lst_weight < max(list_of_weights) and lst_weight > min(list_of_weights):
list_of_weights.insert(2, int(lst_weight))
list_of_weights.sort(key=int, reverse=True)
# Keep the two largest weights per ALG TYPE
# Discard all others.
# Used below.
while len(list_of_weights) > 2:
del list_of_weights[-1]
rec[sshv][alg_type] = {'add': {}, 'del': {}, 'chg': {}} rec[sshv][alg_type] = {'add': {}, 'del': {}, 'chg': {}}
for n, alg_desc in alg_db[alg_type].items():
for alg_name, alg_desc in alg_db[alg_type].items():
versions = alg_desc[0] versions = alg_desc[0]
empty_version = False empty_version = False
sugg_weight = alg_desc[4]
sugg_weight = int(sugg_weight[0])
if len(versions) == 0 or versions[0] is None: if len(versions) == 0 or versions[0] is None:
empty_version = True empty_version = True
else: else:
@@ -193,11 +161,9 @@ class Algorithms:
if (software is not None) and (software.compare_version(ssh_version) < 0): if (software is not None) and (software.compare_version(ssh_version) < 0):
continue continue
matches = True matches = True
break break
if not matches: if not matches:
continue continue
adl, faults = len(alg_desc), 0 adl, faults = len(alg_desc), 0
for i in range(1, 3): for i in range(1, 3):
if not adl > i: if not adl > i:
@@ -205,28 +171,18 @@ class Algorithms:
fc = len(alg_desc[i]) fc = len(alg_desc[i])
if fc > 0: if fc > 0:
faults += pow(10, 2 - i) * fc faults += pow(10, 2 - i) * fc
if n not in alg_list:
if alg_name not in alg_list:
# Don't recommend certificate or token types; these will only appear in the server's list if they are fully configured & functional on the server. # Don't recommend certificate or token types; these will only appear in the server's list if they are fully configured & functional on the server.
# Never suggest an algorithm with a weight of less than 200 if faults > 0 or (alg_type == 'key' and (('-cert-' in n) or (n.startswith('sk-')))) or empty_version:
MIN_SUGGEST_WEIGHT = 200
if faults > 0 or (alg_type == 'key' and (('-cert-' in alg_name) or (alg_name.startswith('sk-')))) or empty_version or sugg_weight < MIN_SUGGEST_WEIGHT:
continue continue
rec[sshv][alg_type]['add'][n] = 0
# Always suggest a new algorithm if it has more weight than the strongest already enabled
# or more weight than the second strongest alread enabled.
# This can be changed to "if sugg_weight > max(list_of_weights):" - to only suggest stronger weights
# However this will preclude the possabilty of suggesting a new "second best" for those that have more than 1 algorithm enabled.
if sugg_weight > max(list_of_weights) or (sugg_weight < max(list_of_weights) and sugg_weight > min(list_of_weights)):
rec[sshv][alg_type]['add'][alg_name] = 0
else: else:
if faults == 0: if faults == 0:
continue continue
if alg_name in ['diffie-hellman-group-exchange-sha256', 'rsa-sha2-256', 'rsa-sha2-512', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com']: if n in ['diffie-hellman-group-exchange-sha256', 'rsa-sha2-256', 'rsa-sha2-512', 'rsa-sha2-256-cert-v01@openssh.com', 'rsa-sha2-512-cert-v01@openssh.com']:
rec[sshv][alg_type]['chg'][alg_name] = faults rec[sshv][alg_type]['chg'][n] = faults
else: else:
rec[sshv][alg_type]['del'][alg_name] = faults rec[sshv][alg_type]['del'][n] = faults
list_of_weights = []
# If we are working with unknown software, drop all add recommendations, because we don't know if they're valid. # If we are working with unknown software, drop all add recommendations, because we don't know if they're valid.
if unknown_software: if unknown_software:
rec[sshv][alg_type]['add'] = {} rec[sshv][alg_type]['add'] = {}
+95 -2
View File
@@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2021 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -60,10 +60,20 @@ class AuditConf:
self.manual = False self.manual = False
self.debug = False self.debug = False
self.gex_test = '' self.gex_test = ''
self.dheat: Optional[str] = None
self.dheat_concurrent_connections: int = 0
self.dheat_e_length: int = 0
self.dheat_target_alg: str = ""
self.skip_rate_test = False
self.conn_rate_test: str = "1:1"
self.conn_rate_test_enabled = False
self.conn_rate_test_threads = 0
self.conn_rate_test_target_rate = 0
def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None: def __setattr__(self, name: str, value: Union[str, int, float, bool, Sequence[int]]) -> None:
valid = False valid = False
if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose', 'debug']: if name in ['batch', 'client_audit', 'colors', 'json', 'json_print_indent', 'list_policies', 'manual', 'make_policy', 'ssh1', 'ssh2', 'timeout_set', 'verbose', 'debug', 'skip_rate_test']:
valid, value = True, bool(value) valid, value = True, bool(value)
elif name in ['ipv4', 'ipv6']: elif name in ['ipv4', 'ipv6']:
valid, value = True, bool(value) valid, value = True, bool(value)
@@ -94,6 +104,89 @@ class AuditConf:
if num_threads < 1: if num_threads < 1:
raise ValueError('invalid number of threads: {}'.format(value)) raise ValueError('invalid number of threads: {}'.format(value))
value = num_threads value = num_threads
elif name == "dheat":
# Valid values:
# * None
# * "10" (concurrent-connections)
# * "10:diffie-hellman-group18-sha512" (concurrent-connections:target-alg)
# * "10:diffie-hellman-group18-sha512:100" (concurrent-connections:target-alg:e-length)
valid = True
if value is not None:
def _parse_concurrent_connections(s: str) -> int:
if Utils.parse_int(s) < 1:
raise ValueError("number of concurrent connections must be 1 or greater: {}".format(s))
return int(s)
def _parse_e_length(s: str) -> int:
s_int = Utils.parse_int(s)
if s_int < 2:
raise ValueError("length of e must not be less than 2: {}".format(s))
return s_int
def _parse_target_alg(s: str) -> str:
if len(s) == 0:
raise ValueError("target algorithm must not be the empty string.")
return s
value = str(value)
fields = value.split(':')
self.dheat_concurrent_connections = _parse_concurrent_connections(fields[0])
# Parse the target algorithm if present.
if len(fields) >= 2:
self.dheat_target_alg = _parse_target_alg(fields[1])
# Parse the length of e, if present.
if len(fields) == 3:
self.dheat_e_length = _parse_e_length(fields[2])
if len(fields) > 3:
raise ValueError("only three fields are expected instead of {}: {}".format(len(fields), value))
elif name in ["dheat_concurrent_connections", "dheat_e_length"]:
valid = True
if not isinstance(value, int):
valid = False
elif name == "dheat_target_alg":
valid = True
if not isinstance(value, str):
valid = False
elif name == "conn_rate_test":
# Valid values:
# * "4" (run rate test with 4 threads)
# * "4:100" (run rate test with 4 threads, targeting 100 connections/second)
error_msg = "valid format for {:s} is \"N\" or \"N:N\", where N is an integer.".format(name)
self.conn_rate_test_enabled = True
fields = str(value).split(":")
if len(fields) > 2 or len(fields) == 0:
raise ValueError(error_msg)
else:
self.conn_rate_test_threads = int(fields[0])
if self.conn_rate_test_threads < 1:
raise ValueError("number of threads must be 1 or greater.")
self.conn_rate_test_target_rate = 0
if len(fields) == 2:
self.conn_rate_test_target_rate = int(fields[1])
if self.conn_rate_test_target_rate < 1:
raise ValueError("rate target must be 1 or greater.")
elif name == "conn_rate_test_enabled":
valid = True
if not isinstance(value, bool):
valid = False
elif name in ["conn_rate_test_threads", "conn_rate_test_target_rate"]:
valid = True
if not isinstance(value, int):
valid = False
if valid: if valid:
object.__setattr__(self, name, value) object.__setattr__(self, name, value)
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
THE SOFTWARE. THE SOFTWARE.
""" """
# The version to display. # The version to display.
VERSION = 'v3.2.0-dev' VERSION = 'v3.2.0'
# SSH software to impersonate # SSH software to impersonate
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2' SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
+357 -391
View File
@@ -1,7 +1,7 @@
""" """
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com) Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu) Copyright (C) 2017 Andris Raugulis (moo@arthepsy.eu)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -76,411 +76,377 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
INFO_EXTENSION_NEGOTIATION = 'pseudo-algorithm that denotes the peer supports RFC8308 extensions' 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)' 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)'
WEIGHT_FAIL = 1
WEIGHT_EAM = 100
WEIGHT_NEVER_OSSH = 200
WEIGHT_128 = 1000
WEIGHT_192 = 1500
WEIGHT_384 = 1500
WEIGHT_CURVE_256 = 5000
WEIGHT_DH_G14_256 = 2000
WEIGHT_DH_G15_256 = 2500
WEIGHT_DH_G15_384 = 2550
WEIGHT_DH_G15_512 = 2575
WEIGHT_DH_G16_256 = 2600
WEIGHT_DH_G16_384 = 2650
WEIGHT_DH_G16_512 = 2675
WEIGHT_DH_G16_256 = 2700
WEIGHT_DH_G16_384 = 2750
WEIGHT_DH_G16_512 = 2775
WEIGHT_DH_G17_512 = 2875
WEIGHT_DH_G18_512 = 2975
WEIGHT_DH_256 = 2000
WEIGHT_DH_384 = 2200
WEIGHT_DH_512 = 2300
WEIGHT_DISABLED = 1300
WEIGHT_SSH_NOT_IMP_OR_DISABLED = 250
DESIRED_WEIGHT = 9000
WEIGHT_CHACHA = 1200 # until patch
STRONG_CURVE = 9000
GOOD_CURVE = 8500
NEVER_SUGGEST_ALG = 1
WEIGHT_STRICT_KEX = 5000
# Maintains a dictionary per calling thread that yields its own copy of MASTER_DB. This prevents results from one thread polluting the results of another thread. # Maintains a dictionary per calling thread that yields its own copy of MASTER_DB. This prevents results from one thread polluting the results of another thread.
DB_PER_THREAD: Dict[int, Dict[str, Dict[str, List[List[Optional[str]]]]]] = {} DB_PER_THREAD: Dict[int, Dict[str, Dict[str, List[List[Optional[str]]]]]] = {}
MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = { MASTER_DB: Dict[str, Dict[str, List[List[Optional[str]]]]] = {
# Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...], [preference_weight]] # Format: 'algorithm_name': [['version_first_appeared_in'], [reason_for_failure1, reason_for_failure2, ...], [warning1, warning2, ...], [info1, info2, ...]]
'kex': { 'kex': {
'Curve25519SHA256': [[], [], [], [], [STRONG_CURVE]], 'Curve25519SHA256': [[]],
'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX_74_TO_89], [STRONG_CURVE]], 'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX_74_TO_89]],
'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX_65_TO_73], [STRONG_CURVE]], 'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX_65_TO_73]],
'curve448-sha512': [[], [], [], [], [GOOD_CURVE]], 'curve448-sha512': [[]],
'curve448-sha512@libssh.org': [[], [], [], [], [GOOD_CURVE]], 'curve448-sha512@libssh.org': [[]],
'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS], [], [WEIGHT_FAIL]], 'diffie-hellman-group14-sha1': [['3.9,d0.53,l10.6.0'], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'diffie-hellman-group14-sha224@ssh.com': [[], [], [], [], [WEIGHT_DH_G14_256]], 'diffie-hellman-group14-sha224@ssh.com': [[]],
'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS], [], [WEIGHT_DH_G14_256]], 'diffie-hellman-group14-sha256': [['7.3,d2016.73'], [], [WARN_2048BIT_MODULUS]],
'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS], [], [WEIGHT_DH_G14_256]], 'diffie-hellman-group14-sha256@ssh.com': [[], [], [WARN_2048BIT_MODULUS]],
'diffie-hellman-group15-sha256': [[], [], [], [], [WEIGHT_DH_G15_256]], 'diffie-hellman-group15-sha256': [[]],
'diffie-hellman-group15-sha256@ssh.com': [[], [], [], [], [WEIGHT_DH_G15_256]], 'diffie-hellman-group15-sha256@ssh.com': [[]],
'diffie-hellman-group15-sha384@ssh.com': [[], [], [], [], [WEIGHT_DH_G15_384]], 'diffie-hellman-group15-sha384@ssh.com': [[]],
'diffie-hellman-group15-sha512': [[], [], [], [], [WEIGHT_DH_G15_512]], 'diffie-hellman-group15-sha512': [[]],
'diffie-hellman-group16-sha256': [[], [], [], [], [WEIGHT_DH_G16_256]], 'diffie-hellman-group16-sha256': [[]],
'diffie-hellman-group16-sha384@ssh.com': [[], [], [], [], [WEIGHT_DH_G16_384]], 'diffie-hellman-group16-sha384@ssh.com': [[]],
'diffie-hellman-group16-sha512': [['7.3,d2016.73'], [], [], [], [WEIGHT_DH_G16_512]], 'diffie-hellman-group16-sha512': [['7.3,d2016.73']],
'diffie-hellman-group16-sha512@ssh.com': [[], [], [], [], [WEIGHT_DH_G16_512]], 'diffie-hellman-group16-sha512@ssh.com': [[]],
'diffie-hellman-group17-sha512': [[], [], [], [], [WEIGHT_DH_G17_512]], 'diffie-hellman-group17-sha512': [[]],
'diffie-hellman_group17-sha512': [[], [], [], [], [WEIGHT_DH_G17_512]], 'diffie-hellman_group17-sha512': [[]],
'diffie-hellman-group18-sha512': [['7.3'], [], [], [], [WEIGHT_DH_G18_512]], 'diffie-hellman-group18-sha512': [['7.3']],
'diffie-hellman-group18-sha512@ssh.com': [[], [], [], [], [WEIGHT_DH_G18_512]], 'diffie-hellman-group18-sha512@ssh.com': [[]],
'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH69], [WEIGHT_FAIL]], 'diffie-hellman-group1-sha1': [['2.3.0,d0.28,l10.2', '6.6', '6.9'], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH69]],
'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'diffie-hellman-group1-sha256': [[], [FAIL_1024BIT_MODULUS]],
'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'diffie-hellman-group-exchange-sha1': [['2.3.0', '6.6', None], [FAIL_SHA1]],
'diffie-hellman-group-exchange-sha224@ssh.com': [[], [], [], [], [WEIGHT_FAIL]], 'diffie-hellman-group-exchange-sha224@ssh.com': [[]],
'diffie-hellman-group-exchange-sha256': [['4.4'], [], [], [], [WEIGHT_DH_256]], 'diffie-hellman-group-exchange-sha256': [['4.4']],
'diffie-hellman-group-exchange-sha256@ssh.com': [[], [], [], [], [WEIGHT_DH_256]], 'diffie-hellman-group-exchange-sha256@ssh.com': [[]],
'diffie-hellman-group-exchange-sha384@ssh.com': [[], [], [], [], [WEIGHT_DH_384]], 'diffie-hellman-group-exchange-sha384@ssh.com': [[]],
'diffie-hellman-group-exchange-sha512@ssh.com': [[], [], [], [], [WEIGHT_DH_512]], 'diffie-hellman-group-exchange-sha512@ssh.com': [[]],
'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-1.2.840.10045.3.1.1': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-192 / secp192r1 'ecdh-sha2-1.2.840.10045.3.1.1': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
'ecdh-sha2-1.2.840.10045.3.1.7': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-256 / secp256r1 'ecdh-sha2-1.2.840.10045.3.1.7': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
'ecdh-sha2-1.3.132.0.10': [[], [], [], [], [WEIGHT_FAIL]], # ECDH over secp256k1 (i.e.: the Bitcoin curve) 'ecdh-sha2-1.3.132.0.10': [[]], # ECDH over secp256k1 (i.e.: the Bitcoin curve)
'ecdh-sha2-1.3.132.0.16': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect283k1 'ecdh-sha2-1.3.132.0.16': [[], [FAIL_UNPROVEN]], # sect283k1
'ecdh-sha2-1.3.132.0.1': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], # sect163k1 'ecdh-sha2-1.3.132.0.1': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
'ecdh-sha2-1.3.132.0.26': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], # sect233k1 'ecdh-sha2-1.3.132.0.26': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # sect233r1 'ecdh-sha2-1.3.132.0.27': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
'ecdh-sha2-1.3.132.0.33': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-224 / secp224r1 'ecdh-sha2-1.3.132.0.33': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-224 / secp224r1
'ecdh-sha2-1.3.132.0.34': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-384 / secp384r1 'ecdh-sha2-1.3.132.0.34': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
'ecdh-sha2-1.3.132.0.35': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-521 / secp521r1 'ecdh-sha2-1.3.132.0.35': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
'ecdh-sha2-1.3.132.0.36': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect409k1 'ecdh-sha2-1.3.132.0.36': [[], [FAIL_UNPROVEN]], # sect409k1
'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # sect409r1 'ecdh-sha2-1.3.132.0.37': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
'ecdh-sha2-1.3.132.0.38': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect571k1 'ecdh-sha2-1.3.132.0.38': [[], [FAIL_UNPROVEN]], # sect571k1
# Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2 # Note: the base64 strings, according to draft 6 of RFC5656, is Base64(MD5(DER(OID))). The final RFC5656 dropped the base64 strings in favor of plain OID concatenation, but apparently some SSH servers implement them anyway. See: https://datatracker.ietf.org/doc/html/draft-green-secsh-ecc-06#section-9.2
'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], # sect163k1 'ecdh-sha2-4MHB+NBt3AlaSRQ7MnB4cg==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect163k1
'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-192 / secp192r1 'ecdh-sha2-5pPrSUQtIaTjUSt5VZNBjg==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # NIST P-192 / secp192r1
'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-256 / secp256r1 'ecdh-sha2-9UzNcgwTlEnSCECZa7V1mw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-256 / secp256r1
'ecdh-sha2-brainpoolp256r1@genua.de': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-brainpoolp256r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-brainpoolp384r1@genua.de': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-brainpoolp384r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-brainpoolp521r1@genua.de': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-brainpoolp521r1@genua.de': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-curve25519': [[], [], [], [], [2200]], 'ecdh-sha2-curve25519': [[], []],
'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # sect409r1 'ecdh-sha2-D3FefCjYoJ/kfXgAyLddYA==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # sect409r1
'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-521 / secp521r1 'ecdh-sha2-h/SsxnLCtRBh7I9ATyeB3A==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-521 / secp521r1
'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect409k1 'ecdh-sha2-m/FtSAmrV4j/Wy6RVUaK7A==': [[], [FAIL_UNPROVEN]], # sect409k1
'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect571k1 'ecdh-sha2-mNVwCXAoS1HGmHpLvBC94w==': [[], [FAIL_UNPROVEN]], # sect571k1
'ecdh-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistb409': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistb409': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]],
'ecdh-sha2-nistk283': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistk283': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistk409': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistk409': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistp256': [['5.7,d2013.62,l10.6.0'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistp384': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistp521': [['5.7,d2013.62'], [FAIL_NSA_BACKDOORED_CURVE]],
'ecdh-sha2-nistt571': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecdh-sha2-nistt571': [[], [FAIL_UNPROVEN]],
'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[], [FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # sect233r1 'ecdh-sha2-qCbG5Cn/jjsZ7nBeR7EnOA==': [[FAIL_SMALL_ECC_MODULUS, FAIL_NSA_BACKDOORED_CURVE]], # sect233r1
'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], # NIST P-384 / secp384r1 'ecdh-sha2-qcFQaMAMGhTziMT0z+Tuzw==': [[], [FAIL_NSA_BACKDOORED_CURVE]], # NIST P-384 / secp384r1
'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], # NIST P-224 / secp224r1 'ecdh-sha2-VqBg4QRPjxx1EXZdV0GdWQ==': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS]], # NIST P-224 / secp224r1
'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], # sect283k1 'ecdh-sha2-wiRIU8TKjMZ418sMqlqtvQ==': [[], [FAIL_UNPROVEN]], # sect283k1
'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [], [], [WEIGHT_FAIL]], # sect233k1 'ecdh-sha2-zD/b3hu/71952ArpUG4OjQ==': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS]], # sect233k1
'ecmqv-sha2': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'ecmqv-sha2': [[], [FAIL_UNPROVEN]],
'ext-info-c': [[], [], [], [INFO_EXTENSION_NEGOTIATION], [100]], # Extension negotiation (RFC 8308) 'ext-info-c': [[], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
'ext-info-s': [[], [], [], [INFO_EXTENSION_NEGOTIATION], [100]], # Extension negotiation (RFC 8308) 'ext-info-s': [[], [], [], [INFO_EXTENSION_NEGOTIATION]], # Extension negotiation (RFC 8308)
'kex-strict-c-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX], [WEIGHT_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795). 'kex-strict-c-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
'kex-strict-s-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX], [WEIGHT_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795). 'kex-strict-s-v00@openssh.com': [[], [], [], [INFO_STRICT_KEX]], # Strict KEX marker (countermeasure for CVE-2023-48795).
# The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes. # The GSS kex algorithms get special wildcard handling, since they include variable base64 data after their standard prefixes.
'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN], [], [] ,[WEIGHT_FAIL]], 'gss-13.3.132.0.10-sha256-*': [[], [FAIL_UNKNOWN]],
'gss-curve25519-sha256-*': [[], [], [], [], [2000]], 'gss-curve25519-sha256-*': [[]],
'gss-curve448-sha512-*': [[], [], [], [], [2000]], 'gss-curve448-sha512-*': [[]],
'gss-gex-sha1-*': [[], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'gss-gex-sha1-*': [[], [FAIL_SHA1]],
'gss-gex-sha256-*': [[], [], [], [], [2000]], 'gss-gex-sha256-*': [[]],
'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS], [], [WEIGHT_FAIL]], 'gss-group14-sha1-*': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS], [], [100]], 'gss-group14-sha256-*': [[], [], [WARN_2048BIT_MODULUS]],
'gss-group15-sha512-*': [[], [], [], [], [2000]], 'gss-group15-sha512-*': [[]],
'gss-group16-sha512-*': [[], [], [], [], [2200]], 'gss-group16-sha512-*': [[]],
'gss-group17-sha512-*': [[], [], [], [], [2200]], 'gss-group17-sha512-*': [[]],
'gss-group18-sha512-*': [[], [], [], [], [2300]], 'gss-group18-sha512-*': [[]],
'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'gss-group1-sha1-*': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'gss-nistp256-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'gss-nistp384-sha256-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'gss-nistp384-sha384-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'gss-nistp384-sha384-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'gss-nistp521-sha512-*': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoCurve25519SHA256': [[], [], [], [], [2000]], 'kexAlgoCurve25519SHA256': [[]],
'kexAlgoDH14SHA1': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS], [], [WEIGHT_FAIL]], 'kexAlgoDH14SHA1': [[], [FAIL_SHA1], [WARN_2048BIT_MODULUS]],
'kexAlgoDH1SHA1': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'kexAlgoDH1SHA1': [[], [FAIL_1024BIT_MODULUS, FAIL_LOGJAM_ATTACK, FAIL_SHA1]],
'kexAlgoECDH256': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'kexAlgoECDH256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoECDH384': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'kexAlgoECDH384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexAlgoECDH521': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'kexAlgoECDH521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'kexguess2@matt.ucc.asn.au': [['d2013.57'], [], [], [], [200]], 'kexguess2@matt.ucc.asn.au': [['d2013.57']],
'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'm383-sha384@libassh.org': [[], [FAIL_UNPROVEN]],
'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'm511-sha512@libassh.org': [[], [FAIL_UNPROVEN]],
'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'rsa1024-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS], [], [100]], 'rsa2048-sha256': [[], [], [WARN_2048BIT_MODULUS]],
'sm2kep-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_UNTRUSTED], [], [], [WEIGHT_FAIL]], 'sm2kep-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_UNTRUSTED]],
'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG], [1]], 'sntrup4591761x25519-sha512@tinyssh.org': [['8.0', '8.4'], [], [WARN_EXPERIMENTAL], [INFO_WITHDRAWN_PQ_ALG]],
'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [], [INFO_DEFAULT_OPENSSH_KEX_90], [1]], 'sntrup761x25519-sha512@openssh.com': [['8.5'], [], [], [INFO_DEFAULT_OPENSSH_KEX_90]],
'x25519-kyber-512r3-sha256-d00@amazon.com': [[], [], [], [], [2000]], 'x25519-kyber-512r3-sha256-d00@amazon.com': [[]],
'x25519-kyber512-sha512@aws.amazon.com': [[], [], [], [], [2000]], 'x25519-kyber512-sha512@aws.amazon.com': [[]],
}, },
'key': { 'key': {
'dsa2048-sha224@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS], [], [WEIGHT_FAIL]], 'dsa2048-sha224@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
'dsa2048-sha256@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS], [], [WEIGHT_FAIL]], 'dsa2048-sha256@libassh.org': [[], [FAIL_UNPROVEN], [WARN_2048BIT_MODULUS]],
'dsa3072-sha256@libassh.org': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'dsa3072-sha256@libassh.org': [[], [FAIL_UNPROVEN]],
'ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com': [[], [FAIL_UNKNOWN], [], [], [WEIGHT_FAIL]], 'ecdsa-sha2-1.3.132.0.10-cert-v01@openssh.com': [[], [FAIL_UNKNOWN]],
'ecdsa-sha2-1.3.132.0.10': [[], [], [WARN_RNDSIG_KEY], [], [900]], # ECDSA over secp256k1 (i.e.: the Bitcoin curve) 'ecdsa-sha2-1.3.132.0.10': [[], [], [WARN_RNDSIG_KEY]], # ECDSA over secp256k1 (i.e.: the Bitcoin curve)
'ecdsa-sha2-curve25519': [[], [], [WARN_RNDSIG_KEY], [], [900]], # ECDSA with Curve25519? Bizarre... 'ecdsa-sha2-curve25519': [[], [], [WARN_RNDSIG_KEY]], # ECDSA with Curve25519? Bizarre...
'ecdsa-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistb233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistb409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistb409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistk163': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistk233': [[], [FAIL_UNPROVEN, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistk283': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistk283': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistk409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistk409': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp224': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp192': [[], [FAIL_NSA_BACKDOORED_CURVE, FAIL_SMALL_ECC_MODULUS], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp256': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp256-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp384': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp384-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp521': [['5.7,d2013.62,l10.6.4'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistp521-cert-v01@openssh.com': [['5.7'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'ecdsa-sha2-nistt571': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ecdsa-sha2-nistt571': [[], [FAIL_UNPROVEN], [WARN_RNDSIG_KEY]],
'eddsa-e382-shake256@libassh.org': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'eddsa-e382-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
'eddsa-e521-shake256@libassh.org': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'eddsa-e521-shake256@libassh.org': [[], [FAIL_UNPROVEN]],
'null': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'null': [[], [FAIL_PLAINTEXT]],
'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
'rsa-sha2-256': [['7.2,d2020.79'], [], [], [], [2000]], 'rsa-sha2-256': [['7.2,d2020.79']],
'rsa-sha2-256-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]], 'rsa-sha2-256-cert-v01@openssh.com': [['7.8']],
'rsa-sha2-512': [['7.2'], [], [], [], [2200]], 'rsa-sha2-512': [['7.2']],
'rsa-sha2-512-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]], 'rsa-sha2-512-cert-v01@openssh.com': [['7.8']],
'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'sk-ecdsa-sha2-nistp256-cert-v01@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'sk-ecdsa-sha2-nistp256@openssh.com': [['8.2'], [FAIL_NSA_BACKDOORED_CURVE], [WARN_RNDSIG_KEY]],
'sk-ssh-ed25519-cert-v01@openssh.com': [['8.2'], [], [], [], [NEVER_SUGGEST_ALG]], 'sk-ssh-ed25519-cert-v01@openssh.com': [['8.2']],
'sk-ssh-ed25519@openssh.com': [['8.2'], [], [], [], [NEVER_SUGGEST_ALG]], 'sk-ssh-ed25519@openssh.com': [['8.2']],
'spi-sign-rsa': [[], [], [], [], [200]], 'spi-sign-rsa': [[]],
'spki-sign-dss': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'spki-sign-dss': [[], [FAIL_1024BIT_MODULUS]],
'spki-sign-rsa': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'spki-sign-rsa': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dsa': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ssh-dsa': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'ssh-dss': [['2.1.0,d0.28,l10.2', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'ssh-dss-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [INFO_DISABLED_IN_OPENSSH70]],
'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'ssh-dss-cert-v01@openssh.com': [['5.6', '6.9'], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'ssh-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'ssh-ed25519': [['6.5,d2020.79,l10.7.0'], [], [], [], [2000]], 'ssh-ed25519': [['6.5,d2020.79,l10.7.0']],
'ssh-ed25519-cert-v01@openssh.com': [['6.5'], [], [], [], [NEVER_SUGGEST_ALG]], 'ssh-ed25519-cert-v01@openssh.com': [['6.5']],
'ssh-ed448': [[], [], [], [], [1500]], 'ssh-ed448': [[]],
'ssh-ed448-cert-v01@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [NEVER_SUGGEST_ALG]], 'ssh-ed448-cert-v01@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'ssh-gost2001': [[], [FAIL_UNTRUSTED], [], [], [WEIGHT_FAIL]], 'ssh-gost2001': [[], [FAIL_UNTRUSTED]],
'ssh-gost2012-256': [[], [FAIL_UNTRUSTED], [], [], [WEIGHT_FAIL]], 'ssh-gost2012-256': [[], [FAIL_UNTRUSTED]],
'ssh-gost2012-512': [[], [FAIL_UNTRUSTED], [], [], [WEIGHT_FAIL]], 'ssh-gost2012-512': [[], [FAIL_UNTRUSTED]],
'ssh-rsa1': [[], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'ssh-rsa1': [[], [FAIL_SHA1]],
'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88], [WEIGHT_SSH_NOT_IMP_OR_DISABLED]], 'ssh-rsa': [['2.5.0,d0.28,l10.2'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH70], [NEVER_SUGGEST_ALG]], 'ssh-rsa-cert-v00@openssh.com': [['5.4', '6.9'], [FAIL_SHA1], [], [INFO_REMOVED_IN_OPENSSH70]],
'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88], [NEVER_SUGGEST_ALG]], 'ssh-rsa-cert-v01@openssh.com': [['5.6'], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
'ssh-rsa-sha224@ssh.com': [[], [], [], [], [200]], 'ssh-rsa-sha224@ssh.com': [[]],
'ssh-rsa-sha2-256': [[], [], [], [], [1000]], 'ssh-rsa-sha2-256': [[]],
'ssh-rsa-sha2-512': [[], [], [], [], [1010]], 'ssh-rsa-sha2-512': [[]],
'ssh-rsa-sha256@ssh.com': [[], [], [], [], [1020]], 'ssh-rsa-sha256@ssh.com': [[]],
'ssh-rsa-sha384@ssh.com': [[], [], [], [], [1030]], 'ssh-rsa-sha384@ssh.com': [[]],
'ssh-rsa-sha512@ssh.com': [[], [], [], [], [1040]], 'ssh-rsa-sha512@ssh.com': [[]],
'ssh-xmss-cert-v01@openssh.com': [['7.7'], [], [WARN_EXPERIMENTAL], [], [NEVER_SUGGEST_ALG]], 'ssh-xmss-cert-v01@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
'ssh-xmss@openssh.com': [['7.7'], [], [WARN_EXPERIMENTAL], [], [WEIGHT_FAIL]], 'ssh-xmss@openssh.com': [['7.7'], [WARN_EXPERIMENTAL]],
'webauthn-sk-ecdsa-sha2-nistp256@openssh.com': [['8.3'], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'webauthn-sk-ecdsa-sha2-nistp256@openssh.com': [['8.3'], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-1.3.132.0.10': [[], [FAIL_UNKNOWN], [], [], [WEIGHT_FAIL]], 'x509v3-ecdsa-sha2-1.3.132.0.10': [[], [FAIL_UNKNOWN]],
'x509v3-ecdsa-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'x509v3-ecdsa-sha2-nistp256': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-nistp384': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'x509v3-ecdsa-sha2-nistp384': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-ecdsa-sha2-nistp521': [[], [FAIL_NSA_BACKDOORED_CURVE], [], [], [WEIGHT_FAIL]], 'x509v3-ecdsa-sha2-nistp521': [[], [FAIL_NSA_BACKDOORED_CURVE]],
'x509v3-rsa2048-sha256': [[], [], [], [], [1050]], 'x509v3-rsa2048-sha256': [[]],
'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'x509v3-sign-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-sign-dss-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'x509v3-sign-dss-sha1': [[], [FAIL_1024BIT_MODULUS, FAIL_SHA1]],
'x509v3-sign-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'x509v3-sign-dss-sha224@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'x509v3-sign-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'x509v3-sign-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'x509v3-sign-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS]],
'x509v3-sign-rsa': [[], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'x509v3-sign-rsa': [[], [FAIL_SHA1]],
'x509v3-sign-rsa-sha1': [[], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'x509v3-sign-rsa-sha1': [[], [FAIL_SHA1]],
'x509v3-sign-rsa-sha224@ssh.com': [[], [], [], [], [1060]], 'x509v3-sign-rsa-sha224@ssh.com': [[]],
'x509v3-sign-rsa-sha256': [[], [], [], [], [1070]], 'x509v3-sign-rsa-sha256': [[]],
'x509v3-sign-rsa-sha256@ssh.com': [[], [], [], [], [1080]], 'x509v3-sign-rsa-sha256@ssh.com': [[]],
'x509v3-sign-rsa-sha384@ssh.com': [[], [], [], [], [1090]], 'x509v3-sign-rsa-sha384@ssh.com': [[]],
'x509v3-sign-rsa-sha512@ssh.com': [[], [], [], [], [2000]], 'x509v3-sign-rsa-sha512@ssh.com': [[]],
'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY], [], [WEIGHT_FAIL]], 'x509v3-ssh-dss': [[], [FAIL_1024BIT_MODULUS], [WARN_RNDSIG_KEY]],
'x509v3-ssh-rsa': [[], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88], [WEIGHT_FAIL]], 'x509v3-ssh-rsa': [[], [FAIL_SHA1], [], [INFO_DEPRECATED_IN_OPENSSH88]],
}, },
'enc': { 'enc': {
'3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], '3des-cbc': [['1.2.2,d0.28,l10.2', '6.6', None], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'3des-cfb': [[], [FAIL_3DES], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], '3des-cfb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'3des-ctr': [['d0.52'], [FAIL_3DES], [], [], [WEIGHT_FAIL]], '3des-ctr': [['d0.52'], [FAIL_3DES]],
'3des-ecb': [[], [FAIL_3DES], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], '3des-ecb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'3des': [[], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], '3des': [[], [FAIL_3DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], '3des-ofb': [[], [FAIL_3DES], [WARN_CIPHER_MODE]],
'AEAD_AES_128_GCM': [[], [], [], [], [2010]], 'AEAD_AES_128_GCM': [[]],
'AEAD_AES_256_GCM': [[], [], [], [], [2020]], 'AEAD_AES_256_GCM': [[]],
'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE], [], [1000]], 'aes128-cbc': [['2.3.0,d0.28,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes128-ctr': [['3.7,d0.52,l10.4.1'], [], [], [], [1100]], 'aes128-ctr': [['3.7,d0.52,l10.4.1']],
'aes128-gcm': [[], [], [], [], [500]], 'aes128-gcm': [[]],
'aes128-gcm@openssh.com': [['6.2'], [], [], [], [1600]], 'aes128-gcm@openssh.com': [['6.2']],
'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [], [WARN_CIPHER_MODE], [], [1900]], 'aes128-ocb@libassh.org': [[], [], [WARN_CIPHER_MODE]],
'aes192-ctr': [['3.7,l10.4.1'], [], [], [], [2100]], 'aes192-cbc': [['2.3.0,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes192-gcm@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_SSH_NOT_IMP_OR_DISABLED]], 'aes192-ctr': [['3.7,l10.4.1']],
'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [], [WARN_CIPHER_MODE], [], [2800]], 'aes192-gcm@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'aes256-ctr': [['3.7,d0.52,l10.4.1'], [], [], [], [2900]], 'aes256-cbc': [['2.3.0,d0.47,l10.2', '6.6', None], [], [WARN_CIPHER_MODE]],
'aes256-gcm': [[], [], [], [], [3300]], 'aes256-ctr': [['3.7,d0.52,l10.4.1']],
'aes256-gcm@openssh.com': [['6.2'], [], [], [], [3500]], 'aes256-gcm': [[]],
'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_RC4], [], [], [WEIGHT_FAIL]], 'aes256-gcm@openssh.com': [['6.2']],
'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_RC4], [], [], [WEIGHT_FAIL]], 'arcfour128': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_RC4], [], [], [WEIGHT_FAIL]], 'arcfour': [['2.1.0', '6.6', '7.1'], [FAIL_RC4]],
'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'arcfour256': [['4.2', '6.6', '7.1'], [FAIL_RC4]],
'blowfish-cfb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'blowfish-cbc': [['1.2.2,d0.28,l10.2', '6.6,d0.52', '7.1,d0.52'], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'blowfish-ctr': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'blowfish-cfb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'blowfish-ecb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'blowfish-ctr': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'blowfish': [[], [FAIL_BLOWFISH], [WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'blowfish-ecb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'blowfish-ofb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'blowfish': [[], [FAIL_BLOWFISH], [WARN_BLOCK_SIZE]],
'camellia128-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'blowfish-ofb': [[], [FAIL_BLOWFISH], [WARN_CIPHER_MODE]],
'camellia128-cbc': [[], [], [WARN_CIPHER_MODE], [], [1900]], 'camellia128-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia128-ctr': [[], [], [], [], [1925]], 'camellia128-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia128-ctr@openssh.org': [[], [], [], [], [1950]], 'camellia128-ctr': [[]],
'camellia192-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE], [], [1975]], 'camellia128-ctr@openssh.org': [[]],
'camellia192-cbc': [[], [], [WARN_CIPHER_MODE], [], [2000]], 'camellia192-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia192-ctr': [[], [], [], [], [2025]], 'camellia192-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia192-ctr@openssh.org': [[], [], [], [], [2050]], 'camellia192-ctr': [[]],
'camellia256-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE], [], [2100]], 'camellia192-ctr@openssh.org': [[]],
'camellia256-cbc': [[], [], [WARN_CIPHER_MODE], [], [2125]], 'camellia256-cbc@openssh.org': [[], [], [WARN_CIPHER_MODE]],
'camellia256-ctr': [[], [], [], [], [2200]], 'camellia256-cbc': [[], [], [WARN_CIPHER_MODE]],
'camellia256-ctr@openssh.org': [[], [], [], [], [2250]], 'camellia256-ctr': [[]],
'cast128-12-cbc@ssh.com': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'camellia256-ctr@openssh.org': [[]],
'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_CAST], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'cast128-12-cbc@ssh.com': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-cbc': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-cbc': [['2.1.0', '6.6', '7.1'], [FAIL_CAST], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'cast128-12-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-12-cbc': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-12-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-12-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-12-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-12-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-ctr': [[], [FAIL_CAST],[] ,[], [WEIGHT_FAIL]], 'cast128-cfb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-ctr': [[], [FAIL_CAST]],
'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]], 'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE]],
'chacha20-poly1305@openssh.com': [['6.5,d2020.79'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]], 'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
'crypticore128@ssh.com': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'chacha20-poly1305@openssh.com': [['6.5,d2020.79'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER]],
'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'crypticore128@ssh.com': [[], [FAIL_UNPROVEN]],
'des-cfb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-ecb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cfb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-ofb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-ecb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-cbc-ssh1': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-ofb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des-cbc@ssh.com': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cbc-ssh1': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'des': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cbc@ssh.com': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'idea-cbc': [[], [FAIL_IDEA], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'des': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE]],
'idea-cfb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'idea-cbc': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'idea-ctr': [[], [FAIL_IDEA], [], [], [WEIGHT_FAIL]], 'idea-cfb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'idea-ecb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'idea-ctr': [[], [FAIL_IDEA]],
'idea-ofb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'idea-ecb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'idea-ofb': [[], [FAIL_IDEA], [WARN_CIPHER_MODE]],
'rijndael128-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'none': [['1.2.2,d2013.56,l10.2'], [FAIL_PLAINTEXT]],
'rijndael192-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'rijndael128-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael256-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'rijndael192-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70], [WEIGHT_FAIL]], 'rijndael256-cbc': [['2.3.0', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'rijndael-cbc@ssh.com': [[], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'rijndael-cbc@lysator.liu.se': [['2.3.0', '6.6', '7.0'], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_OPENSSH70]],
'seed-cbc@ssh.com': [[], [FAIL_SEED], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'rijndael-cbc@ssh.com': [[], [FAIL_RIJNDAEL], [WARN_CIPHER_MODE]],
'seed-ctr@ssh.com': [[], [FAIL_SEED], [], [], [WEIGHT_FAIL]], 'seed-cbc@ssh.com': [[], [FAIL_SEED], [WARN_CIPHER_MODE]],
'serpent128-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'seed-ctr@ssh.com': [[], [FAIL_SEED]],
'serpent128-ctr': [[], [FAIL_SERPENT], [], [], [WEIGHT_FAIL]], 'serpent128-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent128-gcm@libassh.org': [[], [FAIL_SERPENT], [], [], [WEIGHT_FAIL]], 'serpent128-ctr': [[], [FAIL_SERPENT]],
'serpent192-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'serpent128-gcm@libassh.org': [[], [FAIL_SERPENT]],
'serpent192-ctr': [[], [FAIL_SERPENT], [], [], [WEIGHT_FAIL]], 'serpent192-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent256-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'serpent192-ctr': [[], [FAIL_SERPENT]],
'serpent256-ctr': [[], [FAIL_SERPENT], [], [], [WEIGHT_FAIL]], 'serpent256-cbc': [[], [FAIL_SERPENT], [WARN_CIPHER_MODE]],
'serpent256-gcm@libassh.org': [[], [FAIL_SERPENT], [], [], [WEIGHT_FAIL]], 'serpent256-ctr': [[], [FAIL_SERPENT]],
'twofish128-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67], [WEIGHT_DISABLED]], 'serpent256-gcm@libassh.org': [[], [FAIL_SERPENT]],
'twofish128-ctr': [['d2015.68'], [], [], [], [1500]], 'twofish128-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish128-gcm@libassh.org': [[], [], [], [], [1550]], 'twofish128-ctr': [['d2015.68']],
'twofish192-cbc': [[], [], [WARN_CIPHER_MODE], [], [1600]], 'twofish128-gcm@libassh.org': [[]],
'twofish192-ctr': [[], [], [], [], [1650]], 'twofish192-cbc': [[], [], [WARN_CIPHER_MODE]],
'twofish256-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67], [WEIGHT_DISABLED]], 'twofish192-ctr': [[]],
'twofish256-ctr': [['d2015.68'], [], [], [], [1700]], 'twofish256-cbc': [['d0.47', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish256-gcm@libassh.org': [[], [], [], [], [1800]], 'twofish256-ctr': [['d2015.68']],
'twofish-cbc': [['d0.28', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67], [WEIGHT_DISABLED]], 'twofish256-gcm@libassh.org': [[]],
'twofish-cfb': [[], [], [WARN_CIPHER_MODE], [], [1500]], 'twofish-cbc': [['d0.28', 'd2014.66'], [], [WARN_CIPHER_MODE], [INFO_DISABLED_IN_DBEAR67]],
'twofish-ctr': [[], [], [], [], [1500]], 'twofish-cfb': [[], [], [WARN_CIPHER_MODE]],
'twofish-ecb': [[], [], [WARN_CIPHER_MODE], [], [1500]], 'twofish-ctr': [[]],
'twofish-ofb': [[], [], [WARN_CIPHER_MODE], [], [1500]], 'twofish-ecb': [[], [], [WARN_CIPHER_MODE]],
'twofish-ofb': [[], [], [WARN_CIPHER_MODE]],
}, },
'mac': { 'mac': {
'AEAD_AES_128_GCM': [[], [], [], [], [4000]], 'AEAD_AES_128_GCM': [[]],
'AEAD_AES_256_GCM': [[], [], [], [], [5100]], 'AEAD_AES_256_GCM': [[]],
'aes128-gcm': [[], [], [], [], [4000]], 'aes128-gcm': [[]],
'aes256-gcm': [[], [], [], [], [5200]], 'aes256-gcm': [[]],
'cbcmac-3des': [[], [FAIL_UNPROVEN, FAIL_3DES], [], [], [WEIGHT_FAIL]], 'cbcmac-3des': [[], [FAIL_UNPROVEN, FAIL_3DES]],
'cbcmac-aes': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'cbcmac-aes': [[], [FAIL_UNPROVEN]],
'cbcmac-blowfish': [[], [FAIL_UNPROVEN, FAIL_BLOWFISH], [], [], [WEIGHT_FAIL]], 'cbcmac-blowfish': [[], [FAIL_UNPROVEN, FAIL_BLOWFISH]],
'cbcmac-des': [[], [FAIL_UNPROVEN, FAIL_DES], [], [], [WEIGHT_FAIL]], 'cbcmac-des': [[], [FAIL_UNPROVEN, FAIL_DES]],
'cbcmac-rijndael': [[], [FAIL_UNPROVEN, FAIL_RIJNDAEL], [], [], [WEIGHT_FAIL]], 'cbcmac-rijndael': [[], [FAIL_UNPROVEN, FAIL_RIJNDAEL]],
'cbcmac-twofish': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'cbcmac-twofish': [[], [FAIL_UNPROVEN]],
'chacha20-poly1305@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_SSH_NOT_IMP_OR_DISABLED]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify. 'chacha20-poly1305@openssh.com': [[], [], [], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Despite the @openssh.com tag, this was never shipped as a MAC in OpenSSH (only as a cipher); it is only implemented as a MAC in Syncplify.
'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'crypticore-mac@ssh.com': [[], [FAIL_UNPROVEN]],
'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-md5': [['2.1.0,d0.28', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-md5-96': [['2.5.0', '6.6', '7.1'], [FAIL_MD5], [WARN_ENCRYPT_AND_MAC]],
'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5], [], [], [WEIGHT_FAIL]], 'hmac-md5-96-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5], [], [], [WEIGHT_FAIL]], 'hmac-md5-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_MD5]],
'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-ripemd160': [['2.5.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-ripemd160-96': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [], [WEIGHT_FAIL]], 'hmac-ripemd160-96': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_RIPEMD], [], [], [WEIGHT_FAIL]], 'hmac-ripemd160-etm@openssh.com': [['6.2', '6.6', '7.1'], [FAIL_RIPEMD]],
'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-ripemd160@openssh.com': [['2.1.0', '6.6', '7.1'], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-ripemd': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-ripemd': [[], [FAIL_RIPEMD], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1': [['2.1.0,d0.28,l10.2'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-sha1': [['2.1.0,d0.28,l10.2'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_FAIL]], 'hmac-sha1-96': [['2.5.0,d0.47', '6.6', '7.1'], [FAIL_SHA1], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'hmac-sha1-96-etm@openssh.com': [['6.2', '6.6', None], [FAIL_SHA1]],
'hmac-sha1-96@openssh.com': [[], [FAIL_SHA1], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_FAIL]], 'hmac-sha1-96@openssh.com': [[], [FAIL_SHA1], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'hmac-sha1-etm@openssh.com': [['6.2'], [FAIL_SHA1], [], [], [WEIGHT_FAIL]], 'hmac-sha1-etm@openssh.com': [['6.2'], [FAIL_SHA1]],
'hmac-sha2-224': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha2-224': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
'hmac-sha224@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha224@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-256': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha2-256': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-256-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61], [WEIGHT_EAM]], 'hmac-sha2-256-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_EAM]], # Only ever implemented in AsyncSSH (?). 'hmac-sha2-256-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
'hmac-sha2-256-etm@openssh.com': [['6.2'], [], [], [], [WEIGHT_FAIL]], 'hmac-sha2-256-etm@openssh.com': [['6.2']],
'hmac-sha2-384': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha2-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-512': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha2-512': [['5.9,d2013.56,l10.7.0'], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-512-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61], [WEIGHT_EAM]], 'hmac-sha2-512-96': [['5.9', '6.0'], [], [WARN_ENCRYPT_AND_MAC], [INFO_REMOVED_IN_OPENSSH61]],
'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_EAM]], # Only ever implemented in AsyncSSH (?). 'hmac-sha2-512-96-etm@openssh.com': [[], [], [WARN_TAG_SIZE_96], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]], # Only ever implemented in AsyncSSH (?).
'hmac-sha2-512-etm@openssh.com': [['6.2'], [], [], [], [150]], 'hmac-sha2-512-etm@openssh.com': [['6.2']],
'hmac-sha256-2@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha256-2@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [], [WEIGHT_EAM]], 'hmac-sha256-96@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-sha256-96': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [], [WEIGHT_EAM]], 'hmac-sha256-96': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha256@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha256': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha2-56': [[], [], [WARN_TAG_SIZE, WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-224': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha3-224': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-256': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha3-256': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-384': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha3-384': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha3-512': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha3-512': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha384@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha384@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha512@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha512@ssh.com': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-sha512': [[], [], [WARN_ENCRYPT_AND_MAC]],
'hmac-whirlpool': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'hmac-whirlpool': [[], [], [WARN_ENCRYPT_AND_MAC]],
'md5': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'md5': [[], [FAIL_PLAINTEXT]],
'md5-8': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'md5-8': [[], [FAIL_PLAINTEXT]],
'none': [['d2013.56'], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'none': [['d2013.56'], [FAIL_PLAINTEXT]],
'ripemd160': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'ripemd160': [[], [FAIL_PLAINTEXT]],
'ripemd160-8': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'ripemd160-8': [[], [FAIL_PLAINTEXT]],
'sha1': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'sha1': [[], [FAIL_PLAINTEXT]],
'sha1-8': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'sha1-8': [[], [FAIL_PLAINTEXT]],
'umac-128': [[], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'umac-128': [[], [], [WARN_ENCRYPT_AND_MAC]],
'umac-128-etm@openssh.com': [['6.2'], [], [], [], [1500]], 'umac-128-etm@openssh.com': [['6.2']],
'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC], [], [WEIGHT_EAM]], 'umac-128@openssh.com': [['6.2'], [], [WARN_ENCRYPT_AND_MAC]],
'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH], [WEIGHT_EAM]], 'umac-32@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE],[] ,[WEIGHT_EAM]], 'umac-64-etm@openssh.com': [['6.2'], [], [WARN_TAG_SIZE]],
'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE], [], [WEIGHT_EAM]], 'umac-64@openssh.com': [['4.7'], [], [WARN_ENCRYPT_AND_MAC, WARN_TAG_SIZE]],
'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH],[WEIGHT_EAM]], 'umac-96@openssh.com': [[], [], [WARN_ENCRYPT_AND_MAC], [INFO_NEVER_IMPLEMENTED_IN_OPENSSH]],
} }
} }
+61 -16
View File
@@ -27,6 +27,7 @@ import concurrent.futures
import copy import copy
import getopt import getopt
import json import json
import multiprocessing
import os import os
import re import re
import sys import sys
@@ -44,6 +45,7 @@ from ssh_audit.algorithm import Algorithm
from ssh_audit.algorithms import Algorithms from ssh_audit.algorithms import Algorithms
from ssh_audit.auditconf import AuditConf from ssh_audit.auditconf import AuditConf
from ssh_audit.banner import Banner from ssh_audit.banner import Banner
from ssh_audit.dheat import DHEat
from ssh_audit import exitcodes from ssh_audit import exitcodes
from ssh_audit.fingerprint import Fingerprint from ssh_audit.fingerprint import Fingerprint
from ssh_audit.gextest import GEXTest from ssh_audit.gextest import GEXTest
@@ -96,7 +98,22 @@ def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
uout.info(' -6, --ipv6 enable IPv6 (order of precedence)') uout.info(' -6, --ipv6 enable IPv6 (order of precedence)')
uout.info(' -b, --batch batch output') uout.info(' -b, --batch batch output')
uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)') uout.info(' -c, --client-audit starts a server on port 2222 to audit client\n software config (use -p to change port;\n use -t to change timeout)')
uout.info(' --conn-rate-test=N[:max_rate] perform a connection rate test (useful')
uout.info(' for collecting metrics related to')
uout.info(' susceptibility of the DHEat vuln).')
uout.info(' Testing is conducted with N concurrent')
uout.info(' sockets with an optional maximum rate')
uout.info(' of connections per second.')
uout.info(' -d, --debug debug output') uout.info(' -d, --debug debug output')
uout.info(' --dheat=N[:kex[:e_len]] continuously perform the DHEat DoS attack')
uout.info(' (CVE-2002-20001) against the target using N')
uout.info(' concurrent sockets. Optionally, a specific')
uout.info(' key exchange algorithm can be specified')
uout.info(' instead of allowing it to be automatically')
uout.info(' chosen. Additionally, a small length of')
uout.info(' the fake e value sent to the server can')
uout.info(' be chosen for a more efficient attack (such')
uout.info(' as 4).')
uout.info(' -g, --gex-test=<x[,y,...]> dh gex modulus size test') uout.info(' -g, --gex-test=<x[,y,...]> dh gex modulus size test')
uout.info(' <min1:pref1:max1[,min2:pref2:max2,...]>') uout.info(' <min1:pref1:max1[,min2:pref2:max2,...]>')
uout.info(' <x-y[:step]>') uout.info(' <x-y[:step]>')
@@ -111,6 +128,7 @@ def usage(uout: OutputBuffer, err: Optional[str] = None) -> None:
uout.info(' environment variable is set)') uout.info(' environment variable is set)')
uout.info(' -p, --port=<port> port to connect') uout.info(' -p, --port=<port> port to connect')
uout.info(' -P, --policy=<policy.txt> run a policy test using the specified policy') uout.info(' -P, --policy=<policy.txt> run a policy test using the specified policy')
uout.info(' --skip-rate-test skip the connection rate test during standard audits\n (used to safely infer whether the DHEat attack\n is viable)')
uout.info(' -t, --timeout=<secs> timeout (in seconds) for connection and reading\n (default: 5)') uout.info(' -t, --timeout=<secs> timeout (in seconds) for connection and reading\n (default: 5)')
uout.info(' -T, --targets=<hosts.txt> a file containing a list of target hosts (one\n per line, format HOST[:PORT]). Use --threads\n to control concurrent scans.') uout.info(' -T, --targets=<hosts.txt> a file containing a list of target hosts (one\n per line, format HOST[:PORT]). Use --threads\n to control concurrent scans.')
uout.info(' --threads=<threads> number of threads to use when scanning multiple\n targets (-T/--targets) (default: 32)') uout.info(' --threads=<threads> number of threads to use when scanning multiple\n targets (-T/--targets) (default: 32)')
@@ -430,7 +448,7 @@ def output_recommendations(out: OutputBuffer, algs: Algorithms, algorithm_recomm
# Output additional information & notes. # Output additional information & notes.
def output_info(out: OutputBuffer, software: Optional['Software'], client_audit: bool, any_problems: bool, is_json_output: bool, additional_notes: str) -> None: def output_info(out: OutputBuffer, software: Optional['Software'], client_audit: bool, any_problems: bool, is_json_output: bool, additional_notes: List[str]) -> None:
with out: with out:
# Tell user that PuTTY cannot be hardened at the protocol-level. # Tell user that PuTTY cannot be hardened at the protocol-level.
if client_audit and (software is not None) and (software.product == Product.PuTTY): if client_audit and (software is not None) and (software.product == Product.PuTTY):
@@ -441,8 +459,9 @@ def output_info(out: OutputBuffer, software: Optional['Software'], client_audit:
out.warn('(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>') out.warn('(nfo) For hardening guides on common OSes, please see: <https://www.ssh-audit.com/hardening_guides.html>')
# Add any additional notes. # Add any additional notes.
if len(additional_notes) > 0: for additional_note in additional_notes:
out.warn("(nfo) %s" % additional_notes) if len(additional_note) > 0:
out.warn("(nfo) %s" % additional_note)
if not out.is_section_empty() and not is_json_output: if not out.is_section_empty() and not is_json_output:
out.head('# additional info') out.head('# additional info')
@@ -450,8 +469,8 @@ def output_info(out: OutputBuffer, software: Optional['Software'], client_audit:
out.sep() out.sep()
def post_process_findings(banner: Optional[Banner], algs: Algorithms, client_audit: bool) -> Tuple[List[str], str]: def post_process_findings(banner: Optional[Banner], algs: Algorithms, client_audit: bool, dh_rate_test_notes: str) -> Tuple[List[str], List[str]]:
'''Perform post-processing on scan results before reporting them to the user. Returns a list of algorithms that should not be recommended''' '''Perform post-processing on scan results before reporting them to the user. Returns a list of algorithms that should not be recommended and a list of notes.'''
def _add_terrapin_warning(db: Dict[str, Dict[str, List[List[Optional[str]]]]], category: str, algorithm_name: str) -> None: def _add_terrapin_warning(db: Dict[str, Dict[str, List[List[Optional[str]]]]], category: str, algorithm_name: str) -> None:
'''Adds a warning regarding the Terrapin vulnerability for the specified algorithm.''' '''Adds a warning regarding the Terrapin vulnerability for the specified algorithm.'''
@@ -590,20 +609,24 @@ def post_process_findings(banner: Optional[Banner], algs: Algorithms, client_aud
_add_terrapin_warning(db, "mac", mac) _add_terrapin_warning(db, "mac", mac)
# Return a note telling the user that, while this target is properly configured, if connected to a vulnerable peer, then a vulnerable connection is still possible. # Return a note telling the user that, while this target is properly configured, if connected to a vulnerable peer, then a vulnerable connection is still possible.
notes = "" additional_notes = []
if len(algs_to_note) > 0: if len(algs_to_note) > 0:
notes = "Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present. The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: %s. If any CBC ciphers are in this list, you may remove them while leaving the *-etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types." % ", ".join(algs_to_note) additional_notes.append("Be aware that, while this target properly supports the strict key exchange method (via the kex-strict-?-v00@openssh.com marker) needed to protect against the Terrapin vulnerability (CVE-2023-48795), all peers must also support this feature as well, otherwise the vulnerability will still be present. The following algorithms would allow an unpatched peer to create vulnerable SSH channels with this target: %s. If any CBC ciphers are in this list, you may remove them while leaving the *-etm@openssh.com MACs in place; these MACs are fine while paired with non-CBC cipher types." % ", ".join(algs_to_note))
# Add the chacha ciphers, CBC ciphers, and ETM MACs to the recommendation suppression list if they are not enabled on the server. That way they are not recommended to the user to enable if they were explicitly disabled to handle the Terrapin vulnerability. However, they can still be recommended for disabling. # Add the chacha ciphers, CBC ciphers, and ETM MACs to the recommendation suppression list if they are not enabled on the server. That way they are not recommended to the user to enable if they were explicitly disabled to handle the Terrapin vulnerability. However, they can still be recommended for disabling.
algorithm_recommendation_suppress_list += _get_chacha_ciphers_not_enabled(db, algs) algorithm_recommendation_suppress_list += _get_chacha_ciphers_not_enabled(db, algs)
algorithm_recommendation_suppress_list += _get_cbc_ciphers_not_enabled(db, algs) algorithm_recommendation_suppress_list += _get_cbc_ciphers_not_enabled(db, algs)
algorithm_recommendation_suppress_list += _get_etm_macs_not_enabled(db, algs) algorithm_recommendation_suppress_list += _get_etm_macs_not_enabled(db, algs)
return algorithm_recommendation_suppress_list, notes # Append any notes related to the DH rate test.
if len(dh_rate_test_notes) > 0:
additional_notes.append(dh_rate_test_notes)
return algorithm_recommendation_suppress_list, additional_notes
# Returns a exitcodes.* flag to denote if any failures or warnings were encountered. # Returns a exitcodes.* flag to denote if any failures or warnings were encountered.
def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False) -> int: def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header: List[str], client_host: Optional[str] = None, kex: Optional[SSH2_Kex] = None, pkm: Optional[SSH1_PublicKeyMessage] = None, print_target: bool = False, dh_rate_test_notes: str = "") -> int:
program_retval = exitcodes.GOOD program_retval = exitcodes.GOOD
client_audit = client_host is not None # If set, this is a client audit. client_audit = client_host is not None # If set, this is a client audit.
@@ -611,7 +634,7 @@ def output(out: OutputBuffer, aconf: AuditConf, banner: Optional[Banner], header
algs = Algorithms(pkm, kex) algs = Algorithms(pkm, kex)
# Perform post-processing on the findings to make final adjustments before outputting the results. # Perform post-processing on the findings to make final adjustments before outputting the results.
algorithm_recommendation_suppress_list, additional_notes = post_process_findings(banner, algs, client_audit) algorithm_recommendation_suppress_list, additional_notes = post_process_findings(banner, algs, client_audit, dh_rate_test_notes)
with out: with out:
if print_target: if print_target:
@@ -868,7 +891,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
try: try:
sopts = 'h1246M:p:P:jbcnvl:t:T:Lmdg:' sopts = 'h1246M:p:P:jbcnvl:t:T:Lmdg:'
lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug', 'gex-test='] lopts = ['help', 'ssh1', 'ssh2', 'ipv4', 'ipv6', 'make-policy=', 'port=', 'policy=', 'json', 'batch', 'client-audit', 'no-colors', 'verbose', 'level=', 'timeout=', 'targets=', 'list-policies', 'lookup=', 'threads=', 'manual', 'debug', 'gex-test=', 'dheat=', 'skip-rate-test', 'conn-rate-test=']
opts, args = getopt.gnu_getopt(args, sopts, lopts) opts, args = getopt.gnu_getopt(args, sopts, lopts)
except getopt.GetoptError as err: except getopt.GetoptError as err:
usage_cb(out, str(err)) usage_cb(out, str(err))
@@ -956,6 +979,12 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound)) usage_cb(out, '{} {} {} is not valid'.format(o, bits_left_bound, bits_right_bound))
aconf.gex_test = a aconf.gex_test = a
elif o == '--dheat':
aconf.dheat = a
elif o == '--skip-rate-test':
aconf.skip_rate_test = True
elif o == '--conn-rate-test':
aconf.conn_rate_test = a
if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False: if len(args) == 0 and aconf.client_audit is False and aconf.target_file is None and aconf.list_policies is False and aconf.lookup == '' and aconf.manual is False:
@@ -1039,7 +1068,7 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
return aconf return aconf
def build_struct(target_host: str, banner: Optional['Banner'], cves: List[Dict[str, Union[str, float]]], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None, additional_notes: str = "") -> Any: # pylint: disable=too-many-arguments def build_struct(target_host: str, banner: Optional['Banner'], cves: List[Dict[str, Union[str, float]]], kex: Optional['SSH2_Kex'] = None, pkm: Optional['SSH1_PublicKeyMessage'] = None, client_host: Optional[str] = None, software: Optional[Software] = None, algorithms: Optional[Algorithms] = None, algorithm_recommendation_suppress_list: Optional[List[str]] = None, additional_notes: List[str] = []) -> Any: # pylint: disable=dangerous-default-value
def fetch_notes(algorithm: str, alg_type: str) -> Dict[str, List[Optional[str]]]: def fetch_notes(algorithm: str, alg_type: str) -> Dict[str, List[Optional[str]]]:
'''Returns a dictionary containing the messages in the "fail", "warn", and "info" levels for this algorithm.''' '''Returns a dictionary containing the messages in the "fail", "warn", and "info" levels for this algorithm.'''
@@ -1207,8 +1236,8 @@ def build_struct(target_host: str, banner: Optional['Banner'], cves: List[Dict[s
# Add in the recommendations. # Add in the recommendations.
res['recommendations'] = get_algorithm_recommendations(algorithms, algorithm_recommendation_suppress_list, software, for_server=True) res['recommendations'] = get_algorithm_recommendations(algorithms, algorithm_recommendation_suppress_list, software, for_server=True)
# Add in the additional notes. Currently just one string, but in the future this may grow to multiple strings. Hence, an array is needed to prevent future schema breakage. # Add in the additional notes.
res['additional_notes'] = [additional_notes] res['additional_notes'] = additional_notes
return res return res
@@ -1290,6 +1319,14 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc())) out.fail("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()))
return exitcodes.CONNECTION_ERROR return exitcodes.CONNECTION_ERROR
if aconf.dheat is not None:
DHEat(out, aconf, banner, kex).run()
return exitcodes.GOOD
elif aconf.conn_rate_test_enabled:
DHEat.dh_rate_test(out, aconf, kex, 0, 0, 0)
return exitcodes.GOOD
dh_rate_test_notes = ""
if aconf.client_audit is False: if aconf.client_audit is False:
HostKeyTest.run(out, s, kex) HostKeyTest.run(out, s, kex)
if aconf.gex_test != '': if aconf.gex_test != '':
@@ -1297,9 +1334,16 @@ def audit(out: OutputBuffer, aconf: AuditConf, sshv: Optional[int] = None, print
else: else:
GEXTest.run(out, s, banner, kex) GEXTest.run(out, s, banner, kex)
# Skip the rate test if the user specified "--skip-rate-test".
if aconf.skip_rate_test:
out.d("Skipping rate test due to --skip-rate-test option.")
else:
# Try to open many TCP connections against the server if any Diffie-Hellman key exchanges are present; this tests potential vulnerability to the DHEat DOS attack. Use 3 concurrent sockets over at most 1.5 seconds to open at most 38 connections (stops if 1.5 seconds elapse, or 38 connections are opened--whichever comes first). If more than 25 connections per second were observed, flag the DH algorithms with a warning about the DHEat DOS vuln.
dh_rate_test_notes = DHEat.dh_rate_test(out, aconf, kex, 1.5, 38, 3)
# This is a standard audit scan. # This is a standard audit scan.
if (aconf.policy is None) and (aconf.make_policy is False): if (aconf.policy is None) and (aconf.make_policy is False):
program_retval = output(out, aconf, banner, header, client_host=s.client_host, kex=kex, print_target=print_target) program_retval = output(out, aconf, banner, header, client_host=s.client_host, kex=kex, print_target=print_target, dh_rate_test_notes=dh_rate_test_notes)
# This is a policy test. # This is a policy test.
elif (aconf.policy is not None) and (aconf.make_policy is False): elif (aconf.policy is not None) and (aconf.make_policy is False):
@@ -1588,8 +1632,9 @@ def main() -> int:
if __name__ == '__main__': # pragma: nocover if __name__ == '__main__': # pragma: nocover
exit_code = exitcodes.GOOD multiprocessing.freeze_support() # Needed for PyInstaller (Windows) builds.
exit_code = exitcodes.GOOD
try: try:
exit_code = main() exit_code = main()
except Exception: except Exception:
+56 -1
View File
@@ -1,4 +1,4 @@
.TH SSH-AUDIT 1 "March 14, 2024" .TH SSH-AUDIT 1 "April 18, 2024"
.SH NAME .SH NAME
\fBssh-audit\fP \- SSH server & client configuration auditor \fBssh-audit\fP \- SSH server & client configuration auditor
.SH SYNOPSIS .SH SYNOPSIS
@@ -46,11 +46,21 @@ Enables grepable output.
.br .br
Starts a server on port 2222 to audit client software configuration. Use -p/--port=<port> to change port and -t/--timeout=<secs> to change listen timeout. Starts a server on port 2222 to audit client software configuration. Use -p/--port=<port> to change port and -t/--timeout=<secs> to change listen timeout.
.TP
.B \-\-conn\-rate\-test=N[:max_rate]
.br
Performs a connection rate test (useful for collecting metrics related to susceptibility of the DHEat vulnerability [CVE-2002-20001]). A successful connection is counted when the server returns a valid SSH banner. Testing is conducted with N concurrent sockets with an optional maximum rate of connections per second.
.TP .TP
.B -d, \-\-debug .B -d, \-\-debug
.br .br
Enable debug output. Enable debug output.
.TP
.B \-\-dheat=N[:kex[:e_len]]
.br
Run the DHEat DoS attack (CVE-2002-20001) against the target server (which will consume all available CPU resources). The number of concurrent sockets, N, needed to achieve this effect will be highly dependent on the CPU resources available on the target, as well as the latency between the source and target machines. The key exchange is automatically chosen based on which would cause maximum effect, unless explicitly chosen in the second field. Lastly, an (experimental) option allows the length in bytes of the fake e value sent to the server to be specified in the third field. Normally, the length of e is roughly the length of the modulus of the Diffie-Hellman exchange (hence, an 8192-bit / 1024-byte value of e is sent in each connection when targeting the diffie-hellman-group18-sha512 algorithm). Instead, it was observed that many SSH implementations accept small values, such as 4 bytes; this results in a much more network-efficient attack.
.TP .TP
.B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]> .B -g, \-\-gex-test=<x[,y,...] | min1:pref1:max1[,min2:pref2:max2,...] | x-y[:step]>
.br .br
@@ -126,6 +136,11 @@ The TCP port to connect to when auditing a server, or the port to listen on when
.br .br
Runs a policy audit against a target using the specified policy (see \fBPOLICY AUDIT\fP section for detailed description of this mode of operation). Combine with -c/--client-audit to audit a client configuration instead of a server. Use -L/--list-policies to list all official, built-in policies for common systems. Runs a policy audit against a target using the specified policy (see \fBPOLICY AUDIT\fP section for detailed description of this mode of operation). Combine with -c/--client-audit to audit a client configuration instead of a server. Use -L/--list-policies to list all official, built-in policies for common systems.
.TP
.B \-\-skip\-rate\-test
.br
Skips the connection rate test during standard audits. By default, a few dozen TCP connections are created with the target host to see if connection throttling is implemented (this can safely infer whether the target is vulnerable to the DHEat attack; see CVE-2002-20001).
.TP .TP
.B -t, \-\-timeout=<secs> .B -t, \-\-timeout=<secs>
.br .br
@@ -273,6 +288,46 @@ ssh-audit targetserver --gex-test=0-5120:1024
.fi .fi
.RE .RE
.LP
To run the DHEat DoS attack (monitor the target server's CPU usage to determine the optimal number of concurrent sockets):
.RS
.nf
ssh-audit targetserver --dheat=10
.fi
.RE
.LP
To run the DHEat attack and manually target the diffie-hellman-group-exchange-sha256 algorithm:
.RS
.nf
ssh-audit targetserver --dheat=10:diffie-hellman-group-exchange-sha256
.fi
.RE
.LP
To run the DHEat attack and manually target the diffie-hellman-group-exchange-sha256 algorithm with a very small length of e (resulting in the same effect but without having to send large packets):
.RS
.nf
ssh-audit targetserver --dheat=10:diffie-hellman-group-exchange-sha256:4
.fi
.RE
.LP
To test the number of successful connections per second that can be created with the target using 8 parallel threads (useful for detecting whether connection throttling is implemented by the target):
.RS
.nf
ssh-audit targetserver --conn-rate-test=8
.fi
.RE
.LP
To use 8 parallel threads to create up to 100 connections per second with the target (useful for understanding how much CPU load is caused on the target simply from handling new connections vs excess modular exponentiation when performing the DHEat attack):
.RS
.nf
ssh-audit targetserver --conn-rate-test=8:100
.fi
.RE
.SH RETURN VALUES .SH RETURN VALUES
When a successful connection is made and all algorithms are rated as "good", \fBssh-audit\fP returns 0. Other possible return values are: When a successful connection is made and all algorithms are rated as "good", \fBssh-audit\fP returns 0. Other possible return values are:
+10 -7
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""src/ssh_audit/ssh_audit.py wrapper for backwards compatibility""" """src/ssh_audit/ssh_audit.py wrapper for backwards compatibility"""
import multiprocessing
import sys import sys
import traceback import traceback
from pathlib import Path from pathlib import Path
@@ -10,12 +11,14 @@ sys.path.insert(0, str(Path(__file__).resolve().parent / "src"))
from ssh_audit.ssh_audit import main # noqa: E402 from ssh_audit.ssh_audit import main # noqa: E402
from ssh_audit import exitcodes # noqa: E402 from ssh_audit import exitcodes # noqa: E402
exit_code = exitcodes.GOOD if __name__ == "__main__":
multiprocessing.freeze_support() # Needed for PyInstaller (Windows) builds.
try: exit_code = exitcodes.GOOD
exit_code = main() try:
except Exception: exit_code = main()
exit_code = exitcodes.UNKNOWN_ERROR except Exception:
print(traceback.format_exc()) exit_code = exitcodes.UNKNOWN_ERROR
print(traceback.format_exc())
sys.exit(exit_code) sys.exit(exit_code)
+7
View File
@@ -73,6 +73,7 @@ class _VirtualSocket:
self.rdata = [] self.rdata = []
self.sdata = [] self.sdata = []
self.errors = {} self.errors = {}
self.blocking = False
self.gsock = _VirtualGlobalSocket(self) self.gsock = _VirtualGlobalSocket(self)
def _check_err(self, method): def _check_err(self, method):
@@ -83,12 +84,18 @@ class _VirtualSocket:
def connect(self, address): def connect(self, address):
return self._connect(address, False) return self._connect(address, False)
def connect_ex(self, address):
return self.connect(address)
def _connect(self, address, ret=True): def _connect(self, address, ret=True):
self.peer_address = address self.peer_address = address
self._connected = True self._connected = True
self._check_err('connect') self._check_err('connect')
return self if ret else None return self if ret else None
def setblocking(self, r: bool):
self.blocking = r
def settimeout(self, timeout): def settimeout(self, timeout):
self.timeout = timeout self.timeout = timeout
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "1.99", "protocol": "1.99",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": null, "comments": null,
"protocol": "2.0", "protocol": "2.0",
@@ -1,7 +1,5 @@
{ {
"additional_notes": [ "additional_notes": [],
""
],
"banner": { "banner": {
"comments": "", "comments": "",
"protocol": "2.0", "protocol": "2.0",
+29
View File
@@ -0,0 +1,29 @@
import pytest
from ssh_audit.ssh2_kexdb import SSH2_KexDB
from ssh_audit.dheat import DHEat
class TestDHEat:
@pytest.fixture(autouse=True)
def init(self):
self.SSH2_KexDB = SSH2_KexDB
self.DHEat = DHEat
def test_kex_definition_completeness(self):
alg_db = self.SSH2_KexDB.get_db()
kex_db = alg_db['kex']
# Get all Diffie-Hellman algorithms defined in our database.
dh_algs = []
for kex in kex_db:
if kex.startswith('diffie-hellman-'):
dh_algs.append(kex)
# Ensure that each DH algorithm in our database is in either DHEat's alg_priority or gex_algs list. Also ensure that all non-group exchange algorithms are accounted for in the alg_modulus_sizes dictionary.
for dh_alg in dh_algs:
assert (dh_alg in self.DHEat.alg_priority) or (dh_alg in self.DHEat.gex_algs)
if dh_alg.find("group-exchange") == -1:
assert dh_alg in self.DHEat.alg_modulus_sizes
+1
View File
@@ -17,6 +17,7 @@ class TestErrors:
conf = self.AuditConf('localhost', 22) conf = self.AuditConf('localhost', 22)
conf.colors = False conf.colors = False
conf.batch = True conf.batch = True
conf.skip_rate_test = True
return conf return conf
def _audit(self, spy, conf=None, exit_expected=False): def _audit(self, spy, conf=None, exit_expected=False):
+1
View File
@@ -33,6 +33,7 @@ class TestSSH1:
conf.verbose = True conf.verbose = True
conf.ssh1 = True conf.ssh1 = True
conf.ssh2 = False conf.ssh2 = False
conf.skip_rate_test = True
return conf return conf
def _create_ssh1_packet(self, payload, valid_crc=True): def _create_ssh1_packet(self, payload, valid_crc=True):
+1
View File
@@ -32,6 +32,7 @@ class TestSSH2:
conf.verbose = True conf.verbose = True
conf.ssh1 = False conf.ssh1 = False
conf.ssh2 = True conf.ssh2 = True
conf.skip_rate_test = True
return conf return conf
@classmethod @classmethod
+6 -15
View File
@@ -1,7 +1,7 @@
[tox] [tox]
envlist = envlist =
py{py3}-{test,pylint,flake8,vulture} py{py3}-{test,pylint,flake8}
py{38,39,310,311,312}-{test,mypy,pylint,flake8,vulture} py{38,39,310,311,312}-{test,mypy,pylint,flake8}
cov cov
skip_missing_interpreters = true skip_missing_interpreters = true
@@ -13,7 +13,6 @@ deps =
py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]deps} py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]deps}
py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]deps} py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]deps}
py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]deps} py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]deps}
py{py3,38,39,310,311,312}-{lint,vulture},lint: {[testenv:vulture]deps}
setenv = setenv =
SSHAUDIT = {toxinidir}/src SSHAUDIT = {toxinidir}/src
test: COVERAGE_FILE = {toxinidir}/.coverage.{envname} test: COVERAGE_FILE = {toxinidir}/.coverage.{envname}
@@ -28,7 +27,7 @@ commands =
py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]commands} py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]commands}
py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]commands} py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]commands}
py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]commands} py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]commands}
py{py3,38,39,310,311,312}-{lint,vulture},lint: {[testenv:vulture]commands}
#ignore_outcome = #ignore_outcome =
# type: true # type: true
# lint: true # lint: true
@@ -75,17 +74,6 @@ deps =
commands = commands =
flake8 {posargs:{env:SSHAUDIT} {toxinidir}/setup.py {toxinidir}/test {toxinidir}/ssh-audit.py} --statistics flake8 {posargs:{env:SSHAUDIT} {toxinidir}/setup.py {toxinidir}/test {toxinidir}/ssh-audit.py} --statistics
[testenv:vulture]
deps =
vulture
commands =
python -c "import sys; from subprocess import Popen, PIPE; \
a = ['vulture', '--min-confidence', '100'] + r'{posargs:{env:SSHAUDIT}}'.split(' '); \
o = Popen(a, shell=False, stdout=PIPE).communicate()[0]; \
l = [x for x in o.split(b'\n') if x and b'Unused import' not in x]; \
print(b'\n'.join(l).decode('utf-8')); \
sys.exit(1 if len(l) > 0 else 0)"
[pylint] [pylint]
reports = no reports = no
#output-format = colorized #output-format = colorized
@@ -101,11 +89,14 @@ disable =
no-else-return, no-else-return,
super-with-arguments, # Can be re-factored, at some point. super-with-arguments, # Can be re-factored, at some point.
too-complex, too-complex,
too-many-arguments,
too-many-boolean-expressions, too-many-boolean-expressions,
too-many-branches, too-many-branches,
too-many-instance-attributes, too-many-instance-attributes,
too-many-lines, too-many-lines,
too-many-locals, too-many-locals,
too-many-nested-blocks,
too-many-return-statements,
too-many-statements, too-many-statements,
consider-using-f-string consider-using-f-string
max-complexity = 15 max-complexity = 15