Merge branch 'master' of github.com:jtesta/ssh-audit into strong_crypto_only

This commit is contained in:
OAM7575 2024-03-24 19:21:50 +11:00
commit 3515593ade
24 changed files with 424 additions and 89 deletions

View File

@ -190,6 +190,8 @@ For convenience, a web front-end on top of the command-line tool is available at
- 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).
- 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).
- Added 1 new key exchange algorithm: `gss-nistp384-sha384-*`. - Added 1 new key exchange algorithm: `gss-nistp384-sha384-*`.
### v3.1.0 (2023-12-20) ### v3.1.0 (2023-12-20)

View File

@ -784,6 +784,15 @@ run_custom_policy_test "config2" "test13" "${PROGRAM_RETVAL_GOOD}"
# Failing test with DH modulus test. # Failing test with DH modulus test.
run_custom_policy_test "config2" "test14" "${PROGRAM_RETVAL_FAILURE}" run_custom_policy_test "config2" "test14" "${PROGRAM_RETVAL_FAILURE}"
# Passing test with algorithm subset matching.
run_custom_policy_test "config2" "test15" "${PROGRAM_RETVAL_GOOD}"
# Failing test with algorithm subset matching.
run_custom_policy_test "config2" "test16" "${PROGRAM_RETVAL_FAILURE}"
# Passing test with larger key matching.
run_custom_policy_test "config2" "test17" "${PROGRAM_RETVAL_GOOD}"
# Failing test for built-in OpenSSH 8.0p1 server policy (RSA host key size is 3072 instead of 4096). # Failing test for built-in OpenSSH 8.0p1 server policy (RSA host key size is 3072 instead of 4096).
run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 4)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" "${PROGRAM_RETVAL_FAILURE}" run_builtin_policy_test "Hardened OpenSSH Server v8.0 (version 4)" "8.0p1" "test1" "-o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-ed25519 -o KexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 -o Ciphers=chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -o MACs=hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com" "${PROGRAM_RETVAL_FAILURE}"

View File

@ -54,6 +54,9 @@ class Policy:
self._hostkey_sizes: Optional[Dict[str, Dict[str, Union[int, str, bytes]]]] = None self._hostkey_sizes: Optional[Dict[str, Dict[str, Union[int, str, bytes]]]] = None
self._dh_modulus_sizes: Optional[Dict[str, int]] = None self._dh_modulus_sizes: Optional[Dict[str, int]] = None
self._server_policy = True self._server_policy = True
self._allow_algorithm_subset_and_reordering = False
self._allow_larger_keys = False
self._errors: List[Any] = []
self._name_and_version: str = '' self._name_and_version: str = ''
@ -112,7 +115,7 @@ class Policy:
key = key.strip() key = key.strip()
val = val.strip() val = val.strip()
if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'): if key not in ['name', 'version', 'banner', 'compressions', 'host keys', 'optional host keys', 'key exchanges', 'ciphers', 'macs', 'client policy', 'host_key_sizes', 'dh_modulus_sizes', 'allow_algorithm_subset_and_reordering', 'allow_larger_keys'] and not key.startswith('hostkey_size_') and not key.startswith('cakey_size_') and not key.startswith('dh_modulus_size_'):
raise ValueError("invalid field found in policy: %s" % line) raise ValueError("invalid field found in policy: %s" % line)
if key in ['name', 'banner']: if key in ['name', 'banner']:
@ -205,7 +208,10 @@ class Policy:
elif key.startswith('client policy') and val.lower() == 'true': elif key.startswith('client policy') and val.lower() == 'true':
self._server_policy = False self._server_policy = False
elif key == 'allow_algorithm_subset_and_reordering' and val.lower() == 'true':
self._allow_algorithm_subset_and_reordering = True
elif key == 'allow_larger_keys' and val.lower() == 'true':
self._allow_larger_keys = True
if self._name is None: if self._name is None:
raise ValueError('The policy does not have a name field.') raise ValueError('The policy does not have a name field.')
@ -215,13 +221,12 @@ class Policy:
self._name_and_version = "%s (version %s)" % (self._name, self._version) self._name_and_version = "%s (version %s)" % (self._name, self._version)
@staticmethod def _append_error(self, mismatched_field: str, expected_required: Optional[List[str]], expected_optional: Optional[List[str]], actual: List[str]) -> None:
def _append_error(errors: List[Any], mismatched_field: str, expected_required: Optional[List[str]], expected_optional: Optional[List[str]], actual: List[str]) -> None:
if expected_required is None: if expected_required is None:
expected_required = [''] expected_required = ['']
if expected_optional is None: if expected_optional is None:
expected_optional = [''] expected_optional = ['']
errors.append({'mismatched_field': mismatched_field, 'expected_required': expected_required, 'expected_optional': expected_optional, 'actual': actual}) self._errors.append({'mismatched_field': mismatched_field, 'expected_required': expected_required, 'expected_optional': expected_optional, 'actual': actual})
def _normalize_hostkey_sizes(self) -> None: def _normalize_hostkey_sizes(self) -> None:
@ -294,6 +299,12 @@ name = "Custom Policy (based on %s on %s)"
# The version of this policy (displayed in the output during scans). Not parsed, and may be any value, including strings. # The version of this policy (displayed in the output during scans). Not parsed, and may be any value, including strings.
version = 1 version = 1
# When false, host keys, kex, ciphers, and MAC lists must match exactly. When true, the target host may support a subset of the specified algorithms and/or algorithms may appear in a different order; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls.
allow_algorithm_subset_and_reordering = false
# When false, host keys, CA keys, and Diffie-Hellman key sizes must exactly match what's specified in this policy. When true, target systems are allowed to have larger keys; this feature is useful for specifying a baseline and allowing some hosts the option to implement stricter controls.
allow_larger_keys = false
# The banner that must match exactly. Commented out to ignore banners, since minor variability in the banner is sometimes normal. # The banner that must match exactly. Commented out to ignore banners, since minor variability in the banner is sometimes normal.
# banner = "%s" # banner = "%s"
@ -323,41 +334,53 @@ macs = %s
'''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.''' '''Evaluates a server configuration against this policy. Returns a tuple of a boolean (True if server adheres to policy) and an array of strings that holds error messages.'''
ret = True ret = True
errors: List[Any] = []
banner_str = str(banner) banner_str = str(banner)
if (self._banner is not None) and (banner_str != self._banner): if (self._banner is not None) and (banner_str != self._banner):
ret = False ret = False
self._append_error(errors, 'Banner', [self._banner], None, [banner_str]) self._append_error('Banner', [self._banner], None, [banner_str])
# All subsequent tests require a valid kex, so end here if we don't have one. # All subsequent tests require a valid kex, so end here if we don't have one.
if kex is None: if kex is None:
return ret, errors, self._get_error_str(errors) error_list, error_str = self._get_errors()
return ret, error_list, error_str
if (self._compressions is not None) and (kex.server.compression != self._compressions): if (self._compressions is not None) and (kex.server.compression != self._compressions):
ret = False ret = False
self._append_error(errors, 'Compression', self._compressions, None, kex.server.compression) self._append_error('Compression', self._compressions, None, kex.server.compression)
# If a list of optional host keys was given in the policy, remove any of its entries from the list retrieved from the server. This allows us to do an exact comparison with the expected list below. # If a list of optional host keys was given in the policy, remove any of its entries from the list retrieved from the server. This allows us to do an exact comparison with the expected list below.
pruned_host_keys = kex.key_algorithms pruned_host_keys = kex.key_algorithms
if self._optional_host_keys is not None: if self._optional_host_keys is not None:
pruned_host_keys = [x for x in kex.key_algorithms if x not in self._optional_host_keys] pruned_host_keys = [x for x in kex.key_algorithms if x not in self._optional_host_keys]
if (self._host_keys is not None) and (pruned_host_keys != self._host_keys): # Check host keys.
ret = False if self._host_keys is not None:
self._append_error(errors, 'Host keys', self._host_keys, self._optional_host_keys, kex.key_algorithms) # If the policy allows subsets and re-ordered algorithms...
if self._allow_algorithm_subset_and_reordering:
for hostkey_t in kex.key_algorithms:
if hostkey_t not in self._host_keys:
ret = False
self._append_error('Host keys', self._host_keys, self._optional_host_keys, kex.key_algorithms)
break
# The policy requires exact matching of algorithms.
elif pruned_host_keys != self._host_keys:
ret = False
self._append_error('Host keys', self._host_keys, self._optional_host_keys, kex.key_algorithms)
# Check host key sizes.
if self._hostkey_sizes is not None: if self._hostkey_sizes is not None:
hostkey_types = list(self._hostkey_sizes.keys()) hostkey_types = list(self._hostkey_sizes.keys())
hostkey_types.sort() # Sorted to make testing output repeatable. hostkey_types.sort() # Sorted to make testing output repeatable.
for hostkey_type in hostkey_types: for hostkey_type in hostkey_types:
expected_hostkey_size = self._hostkey_sizes[hostkey_type]['hostkey_size'] expected_hostkey_size = cast(int, self._hostkey_sizes[hostkey_type]['hostkey_size'])
server_host_keys = kex.host_keys() server_host_keys = kex.host_keys()
if hostkey_type in server_host_keys: if hostkey_type in server_host_keys:
actual_hostkey_size = server_host_keys[hostkey_type]['hostkey_size'] actual_hostkey_size = cast(int, server_host_keys[hostkey_type]['hostkey_size'])
if actual_hostkey_size != expected_hostkey_size: if (self._allow_larger_keys and actual_hostkey_size < expected_hostkey_size) or \
(not self._allow_larger_keys and actual_hostkey_size != expected_hostkey_size):
ret = False ret = False
self._append_error(errors, 'Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)]) self._append_error('Host key (%s) sizes' % hostkey_type, [str(expected_hostkey_size)], None, [str(actual_hostkey_size)])
# If we have expected CA signatures set, check them against what the server returned. # If we have expected CA signatures set, check them against what the server returned.
if self._hostkey_sizes is not None and len(cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])) > 0 and cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) > 0: if self._hostkey_sizes is not None and len(cast(str, self._hostkey_sizes[hostkey_type]['ca_key_type'])) > 0 and cast(int, self._hostkey_sizes[hostkey_type]['ca_key_size']) > 0:
@ -369,23 +392,60 @@ macs = %s
# Ensure that the CA signature type is what's expected (i.e.: the server doesn't have an RSA sig when we're expecting an ED25519 sig). # Ensure that the CA signature type is what's expected (i.e.: the server doesn't have an RSA sig when we're expecting an ED25519 sig).
if actual_ca_key_type != expected_ca_key_type: if actual_ca_key_type != expected_ca_key_type:
ret = False ret = False
self._append_error(errors, 'CA signature type', [expected_ca_key_type], None, [actual_ca_key_type]) self._append_error('CA signature type', [expected_ca_key_type], None, [actual_ca_key_type])
# Ensure that the actual and expected signature sizes match. # Ensure that the actual and expected signature sizes match.
elif actual_ca_key_size != expected_ca_key_size: elif (self._allow_larger_keys and actual_ca_key_size < expected_ca_key_size) or \
(not self._allow_larger_keys and actual_ca_key_size != expected_ca_key_size):
ret = False ret = False
self._append_error(errors, 'CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)]) self._append_error('CA signature size (%s)' % actual_ca_key_type, [str(expected_ca_key_size)], None, [str(actual_ca_key_size)])
if kex.kex_algorithms != self._kex: # Check key exchanges.
ret = False if self._kex is not None:
self._append_error(errors, 'Key exchanges', self._kex, None, kex.kex_algorithms) # If the policy allows subsets and re-ordered algorithms...
if self._allow_algorithm_subset_and_reordering:
for kex_t in kex.kex_algorithms:
if kex_t not in self._kex:
ret = False
self._append_error('Key exchanges', self._kex, None, kex.kex_algorithms)
break
# If kex-strict-?-v00@openssh.com is in the policy (i.e. the Terrapin vulnerability countermeasure), then it must appear in the server's list, regardless of the "allow_algorithm_subset_and_reordering" flag.
if ('kex-strict-s-v00@openssh.com' in self._kex and 'kex-strict-s-v00@openssh.com' not in kex.kex_algorithms) or \
('kex-strict-c-v00@openssh.com' in self._kex and 'kex-strict-c-v00@openssh.com' not in kex.kex_algorithms):
ret = False
self._append_error('Key exchanges', self._kex, None, kex.kex_algorithms)
if (self._ciphers is not None) and (kex.server.encryption != self._ciphers): # The policy requires exact matching of algorithms.
ret = False elif kex.kex_algorithms != self._kex:
self._append_error(errors, 'Ciphers', self._ciphers, None, kex.server.encryption) ret = False
self._append_error('Key exchanges', self._kex, None, kex.kex_algorithms)
if (self._macs is not None) and (kex.server.mac != self._macs): # Checking Ciphers
ret = False if self._ciphers is not None:
self._append_error(errors, 'MACs', self._macs, None, kex.server.mac) # If the policy allows subsets and re-ordered algorithms...
if self._allow_algorithm_subset_and_reordering:
for cipher_t in kex.server.encryption:
if cipher_t not in self._ciphers:
ret = False
self._append_error('Ciphers', self._ciphers, None, kex.server.encryption)
break
# The policy requires exact matching of algorithms.
elif kex.server.encryption != self._ciphers:
ret = False
self._append_error('Ciphers', self._ciphers, None, kex.server.encryption)
# Checking MACs
if self._macs is not None:
# If the policy allows subsets and re-ordered algorithms...
if self._allow_algorithm_subset_and_reordering:
for mac_t in kex.server.mac:
if mac_t not in self._macs:
ret = False
self._append_error('MACs', self._macs, None, kex.server.mac)
break
# The policy requires exact matching of algorithms.
elif kex.server.mac != self._macs:
ret = False
self._append_error('MACs', self._macs, None, kex.server.mac)
if self._dh_modulus_sizes is not None: if self._dh_modulus_sizes is not None:
dh_modulus_types = list(self._dh_modulus_sizes.keys()) dh_modulus_types = list(self._dh_modulus_sizes.keys())
@ -394,26 +454,30 @@ macs = %s
expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type] expected_dh_modulus_size = self._dh_modulus_sizes[dh_modulus_type]
if dh_modulus_type in kex.dh_modulus_sizes(): if dh_modulus_type in kex.dh_modulus_sizes():
actual_dh_modulus_size = kex.dh_modulus_sizes()[dh_modulus_type] actual_dh_modulus_size = kex.dh_modulus_sizes()[dh_modulus_type]
if expected_dh_modulus_size != actual_dh_modulus_size: if (self._allow_larger_keys and actual_dh_modulus_size < expected_dh_modulus_size) or \
(not self._allow_larger_keys and actual_dh_modulus_size != expected_dh_modulus_size):
ret = False ret = False
self._append_error(errors, 'Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)]) self._append_error('Group exchange (%s) modulus sizes' % dh_modulus_type, [str(expected_dh_modulus_size)], None, [str(actual_dh_modulus_size)])
return ret, errors, self._get_error_str(errors) error_list, error_str = self._get_errors()
return ret, error_list, error_str
@staticmethod def _get_errors(self) -> Tuple[List[Any], str]:
def _get_error_str(errors: List[Any]) -> str: '''Returns the list of errors, along with the string representation of those errors.'''
'''Transforms an error struct to a flat string of error messages.'''
subset_and_reordering_semicolon = "; subset and/or reordering allowed" if self._allow_algorithm_subset_and_reordering else "; exact match"
subset_and_reordering_parens = " (subset and/or reordering allowed)" if self._allow_algorithm_subset_and_reordering else ""
error_list = [] error_list = []
spacer = '' spacer = ''
for e in errors: for e in self._errors:
e_str = " * %s did not match.\n" % e['mismatched_field'] e_str = " * %s did not match.\n" % e['mismatched_field']
if ('expected_optional' in e) and (e['expected_optional'] != ['']): if ('expected_optional' in e) and (e['expected_optional'] != ['']):
e_str += " - Expected (required): %s\n - Expected (optional): %s\n" % (Policy._normalize_error_field(e['expected_required']), Policy._normalize_error_field(e['expected_optional'])) e_str += " - Expected (required%s): %s\n - Expected (optional): %s\n" % (subset_and_reordering_semicolon, Policy._normalize_error_field(e['expected_required']), Policy._normalize_error_field(e['expected_optional']))
spacer = ' ' spacer = ' '
else: else:
e_str += " - Expected: %s\n" % Policy._normalize_error_field(e['expected_required']) e_str += " - Expected%s: %s\n" % (subset_and_reordering_parens, Policy._normalize_error_field(e['expected_required']))
spacer = ' ' spacer = ' '
e_str += " - Actual:%s%s\n" % (spacer, Policy._normalize_error_field(e['actual'])) e_str += " - Actual:%s%s\n" % (spacer, Policy._normalize_error_field(e['actual']))
error_list.append(e_str) error_list.append(e_str)
@ -424,7 +488,7 @@ macs = %s
if len(error_list) > 0: if len(error_list) > 0:
error_str = "\n".join(error_list) error_str = "\n".join(error_list)
return error_str return self._errors, error_str
def get_name_and_version(self) -> str: def get_name_and_version(self) -> str:
@ -540,4 +604,4 @@ macs = %s
if self._dh_modulus_sizes is not None: if self._dh_modulus_sizes is not None:
dh_modulus_sizes_str = str(self._dh_modulus_sizes) dh_modulus_sizes_str = str(self._dh_modulus_sizes)
return "Name: %s\nVersion: %s\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy) return "Name: %s\nVersion: %s\nAllow Algorithm Subset and/or Reordering: %r\nBanner: %s\nCompressions: %s\nHost Keys: %s\nOptional Host Keys: %s\nKey Exchanges: %s\nCiphers: %s\nMACs: %s\nHost Key Sizes: %s\nDH Modulus Sizes: %s\nServer Policy: %r" % (name, version, self._allow_algorithm_subset_and_reordering, banner, compressions_str, host_keys_str, optional_host_keys_str, kex_str, ciphers_str, macs_str, hostkey_sizes_str, dh_modulus_sizes_str, self._server_policy)

View File

@ -62,7 +62,8 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
WARN_TAG_SIZE_96 = 'using small 96-bit tag size' WARN_TAG_SIZE_96 = 'using small 96-bit tag size'
INFO_DEFAULT_OPENSSH_CIPHER = 'default cipher since OpenSSH 6.9' INFO_DEFAULT_OPENSSH_CIPHER = 'default cipher since OpenSSH 6.9'
INFO_DEFAULT_OPENSSH_KEX_64_TO_89 = 'default key exchange from OpenSSH 6.4 to 8.9' INFO_DEFAULT_OPENSSH_KEX_65_TO_73 = 'default key exchange from OpenSSH 6.5 to 7.3'
INFO_DEFAULT_OPENSSH_KEX_74_TO_89 = 'default key exchange from OpenSSH 7.4 to 8.9'
INFO_DEFAULT_OPENSSH_KEX_90 = 'default key exchange since OpenSSH 9.0' INFO_DEFAULT_OPENSSH_KEX_90 = 'default key exchange since OpenSSH 9.0'
INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8' INFO_DEPRECATED_IN_OPENSSH88 = 'deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8'
INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67' INFO_DISABLED_IN_DBEAR67 = 'disabled in Dropbear SSH 2015.67'
@ -117,8 +118,8 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
# 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, ...], [preference_weight]]
'kex': { 'kex': {
'Curve25519SHA256': [[], [], [], [], [STRONG_CURVE]], 'Curve25519SHA256': [[], [], [], [], [STRONG_CURVE]],
'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX_64_TO_89], [STRONG_CURVE]], 'curve25519-sha256': [['7.4,d2018.76'], [], [], [INFO_DEFAULT_OPENSSH_KEX_74_TO_89], [STRONG_CURVE]],
'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX_64_TO_89], [STRONG_CURVE]], 'curve25519-sha256@libssh.org': [['6.4,d2013.62,l10.6.0'], [], [], [INFO_DEFAULT_OPENSSH_KEX_65_TO_73], [STRONG_CURVE]],
'curve448-sha512': [[], [], [], [], [GOOD_CURVE]], 'curve448-sha512': [[], [], [], [], [GOOD_CURVE]],
'curve448-sha512@libssh.org': [[], [], [], [], [GOOD_CURVE]], 'curve448-sha512@libssh.org': [[], [], [], [], [GOOD_CURVE]],
'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], [], [WEIGHT_FAIL]],
@ -258,7 +259,7 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
'null': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]], 'null': [[], [FAIL_PLAINTEXT], [], [], [WEIGHT_FAIL]],
'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'pgp-sign-dss': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]],
'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'pgp-sign-rsa': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]],
'rsa-sha2-256': [['7.2'], [], [], [], [2000]], 'rsa-sha2-256': [['7.2,d2020.79'], [], [], [], [2000]],
'rsa-sha2-256-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]], 'rsa-sha2-256-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]],
'rsa-sha2-512': [['7.2'], [], [], [], [2200]], 'rsa-sha2-512': [['7.2'], [], [], [], [2200]],
'rsa-sha2-512-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]], 'rsa-sha2-512-cert-v01@openssh.com': [['7.8'], [], [], [], [NEVER_SUGGEST_ALG]],
@ -277,7 +278,7 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha256@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]],
'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha384@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]],
'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]], 'ssh-dss-sha512@ssh.com': [[], [FAIL_1024BIT_MODULUS], [], [], [WEIGHT_FAIL]],
'ssh-ed25519': [['6.5,l10.7.0'], [], [], [], [2000]], 'ssh-ed25519': [['6.5,d2020.79,l10.7.0'], [], [], [], [2000]],
'ssh-ed25519-cert-v01@openssh.com': [['6.5'], [], [], [], [NEVER_SUGGEST_ALG]], 'ssh-ed25519-cert-v01@openssh.com': [['6.5'], [], [], [], [NEVER_SUGGEST_ALG]],
'ssh-ed448': [[], [], [], [], [1500]], 'ssh-ed448': [[], [], [], [], [1500]],
'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], [NEVER_SUGGEST_ALG]],
@ -370,7 +371,7 @@ class SSH2_KexDB: # pylint: disable=too-few-public-methods
'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-ecb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]],
'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]], 'cast128-ofb': [[], [FAIL_CAST], [WARN_CIPHER_MODE], [], [WEIGHT_FAIL]],
'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]], 'chacha20-poly1305': [[], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]],
'chacha20-poly1305@openssh.com': [['6.5'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]], 'chacha20-poly1305@openssh.com': [['6.5,d2020.79'], [], [], [INFO_DEFAULT_OPENSSH_CIPHER], [WEIGHT_CHACHA]],
'crypticore128@ssh.com': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]], 'crypticore128@ssh.com': [[], [FAIL_UNPROVEN], [], [], [WEIGHT_FAIL]],
'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cbc': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]],
'des-cfb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]], 'des-cfb': [[], [FAIL_DES], [WARN_CIPHER_MODE, WARN_BLOCK_SIZE], [], [WEIGHT_FAIL]],

View File

@ -96,7 +96,7 @@
"algorithm": "curve25519-sha256", "algorithm": "curve25519-sha256",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 7.4 to 8.9",
"available since OpenSSH 7.4, Dropbear SSH 2018.76" "available since OpenSSH 7.4, Dropbear SSH 2018.76"
] ]
} }
@ -105,7 +105,7 @@
"algorithm": "curve25519-sha256@libssh.org", "algorithm": "curve25519-sha256@libssh.org",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 6.5 to 7.3",
"available since OpenSSH 6.4, Dropbear SSH 2013.62" "available since OpenSSH 6.4, Dropbear SSH 2013.62"
] ]
} }

View File

@ -6,9 +6,9 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp521 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency

View File

@ -0,0 +1,6 @@
{
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test15 (version 1)"
}

View File

@ -0,0 +1,3 @@
Host: localhost:2222
Policy: Docker policy: test15 (version 1)
Result: ✔ Passed

View File

@ -0,0 +1,86 @@
{
"errors": [
{
"actual": [
"rsa-sha2-512",
"rsa-sha2-256",
"ssh-rsa",
"ecdsa-sha2-nistp256",
"ssh-ed25519"
],
"expected_optional": [
""
],
"expected_required": [
"rsa-sha2-512",
"extra_hostkey_alg"
],
"mismatched_field": "Host keys"
},
{
"actual": [
"curve25519-sha256",
"curve25519-sha256@libssh.org",
"ecdh-sha2-nistp256",
"ecdh-sha2-nistp384",
"ecdh-sha2-nistp521",
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group16-sha512",
"diffie-hellman-group18-sha512",
"diffie-hellman-group14-sha256",
"diffie-hellman-group14-sha1"
],
"expected_optional": [
""
],
"expected_required": [
"curve25519-sha256",
"extra_kex_alg"
],
"mismatched_field": "Key exchanges"
},
{
"actual": [
"chacha20-poly1305@openssh.com",
"aes128-ctr",
"aes192-ctr",
"aes256-ctr",
"aes128-gcm@openssh.com",
"aes256-gcm@openssh.com"
],
"expected_optional": [
""
],
"expected_required": [
"chacha20-poly1305@openssh.com",
"extra_cipher_alg"
],
"mismatched_field": "Ciphers"
},
{
"actual": [
"umac-64-etm@openssh.com",
"umac-128-etm@openssh.com",
"hmac-sha2-256-etm@openssh.com",
"hmac-sha2-512-etm@openssh.com",
"hmac-sha1-etm@openssh.com",
"umac-64@openssh.com",
"umac-128@openssh.com",
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1"
],
"expected_optional": [
""
],
"expected_required": [
"umac-64-etm@openssh.com",
"extra_mac_alg"
],
"mismatched_field": "MACs"
}
],
"host": "localhost",
"passed": false,
"policy": "Docker policy: test16 (version 1)"
}

View File

@ -0,0 +1,21 @@
Host: localhost:2222
Policy: Docker policy: test16 (version 1)
Result: ❌ Failed!

Errors:
* Ciphers did not match.
- Expected (subset and/or reordering allowed): chacha20-poly1305@openssh.com, extra_cipher_alg
- Actual: chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com
* Host keys did not match.
- Expected (subset and/or reordering allowed): rsa-sha2-512, extra_hostkey_alg
- Actual: rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519
* Key exchanges did not match.
- Expected (subset and/or reordering allowed): curve25519-sha256, extra_kex_alg
- Actual: curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
* MACs did not match.
- Expected (subset and/or reordering allowed): umac-64-etm@openssh.com, extra_mac_alg
- Actual: umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1


View File

@ -0,0 +1,6 @@
{
"errors": [],
"host": "localhost",
"passed": true,
"policy": "Docker policy: test17 (version 1)"
}

View File

@ -0,0 +1,3 @@
Host: localhost:2222
Policy: Docker policy: test17 (version 1)
Result: ✔ Passed

View File

@ -40,7 +40,7 @@
"notes": { "notes": {
"info": [ "info": [
"default cipher since OpenSSH 6.9", "default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
], ],
"warn": [ "warn": [
"vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation" "vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation"
@ -115,7 +115,7 @@
"algorithm": "curve25519-sha256", "algorithm": "curve25519-sha256",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 7.4 to 8.9",
"available since OpenSSH 7.4, Dropbear SSH 2018.76" "available since OpenSSH 7.4, Dropbear SSH 2018.76"
] ]
} }
@ -124,7 +124,7 @@
"algorithm": "curve25519-sha256@libssh.org", "algorithm": "curve25519-sha256@libssh.org",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 6.5 to 7.3",
"available since OpenSSH 6.4, Dropbear SSH 2013.62" "available since OpenSSH 6.4, Dropbear SSH 2013.62"
] ]
} }
@ -229,7 +229,7 @@
"keysize": 3072, "keysize": 3072,
"notes": { "notes": {
"info": [ "info": [
"available since OpenSSH 7.2" "available since OpenSSH 7.2, Dropbear SSH 2020.79"
] ]
} }
}, },
@ -264,7 +264,7 @@
"algorithm": "ssh-ed25519", "algorithm": "ssh-ed25519",
"notes": { "notes": {
"info": [ "info": [
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
] ]
} }
} }

View File

@ -1,7 +1,7 @@
# general # general
(gen) banner: SSH-2.0-OpenSSH_8.0 (gen) banner: SSH-2.0-OpenSSH_8.0
(gen) software: OpenSSH 8.0 (gen) software: OpenSSH 8.0
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2020.79+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
@ -12,9 +12,9 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
@ -33,18 +33,18 @@
# host-key algorithms # host-key algorithms
(key) rsa-sha2-512 (3072-bit) -- [info] available since OpenSSH 7.2 (key) rsa-sha2-512 (3072-bit) -- [info] available since OpenSSH 7.2
(key) rsa-sha2-256 (3072-bit) -- [info] available since OpenSSH 7.2 (key) rsa-sha2-256 (3072-bit) -- [info] available since OpenSSH 7.2, Dropbear SSH 2020.79
(key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm (key) ssh-rsa (3072-bit) -- [fail] using broken SHA-1 hash algorithm
`- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28 `- [info] available since OpenSSH 2.5.0, Dropbear SSH 0.28
`- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8 `- [info] deprecated in OpenSSH 8.8: https://www.openssh.com/txt/release-8.8
(key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (key) ecdsa-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
 `- [warn] using weak random number generator could reveal the key  `- [warn] using weak random number generator could reveal the key
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation (enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation
`- [info] available since OpenSSH 6.5 `- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
`- [info] default cipher since OpenSSH 6.9 `- [info] default cipher since OpenSSH 6.9
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7

View File

@ -40,7 +40,7 @@
"notes": { "notes": {
"info": [ "info": [
"default cipher since OpenSSH 6.9", "default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
], ],
"warn": [ "warn": [
"vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation" "vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation"
@ -105,7 +105,7 @@
"algorithm": "curve25519-sha256", "algorithm": "curve25519-sha256",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 7.4 to 8.9",
"available since OpenSSH 7.4, Dropbear SSH 2018.76" "available since OpenSSH 7.4, Dropbear SSH 2018.76"
] ]
} }
@ -114,7 +114,7 @@
"algorithm": "curve25519-sha256@libssh.org", "algorithm": "curve25519-sha256@libssh.org",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 6.5 to 7.3",
"available since OpenSSH 6.4, Dropbear SSH 2013.62" "available since OpenSSH 6.4, Dropbear SSH 2013.62"
] ]
} }
@ -209,7 +209,7 @@
"algorithm": "ssh-ed25519", "algorithm": "ssh-ed25519",
"notes": { "notes": {
"info": [ "info": [
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
] ]
} }
}, },

View File

@ -1,7 +1,7 @@
# general # general
(gen) banner: SSH-2.0-OpenSSH_8.0 (gen) banner: SSH-2.0-OpenSSH_8.0
(gen) software: OpenSSH 8.0 (gen) software: OpenSSH 8.0
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2020.79+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
@ -12,9 +12,9 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp256 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
`- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62 `- [info] available since OpenSSH 5.7, Dropbear SSH 2013.62
(kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency (kex) ecdh-sha2-nistp384 -- [fail] using elliptic curves that are suspected as being backdoored by the U.S. National Security Agency
@ -32,12 +32,12 @@
`- [info] available since OpenSSH 3.9, Dropbear SSH 0.53 `- [info] available since OpenSSH 3.9, Dropbear SSH 0.53
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
(key) ssh-ed25519-cert-v01@openssh.com (256-bit cert/256-bit ssh-ed25519 CA) -- [info] available since OpenSSH 6.5 (key) ssh-ed25519-cert-v01@openssh.com (256-bit cert/256-bit ssh-ed25519 CA) -- [info] available since OpenSSH 6.5
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation (enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation
`- [info] available since OpenSSH 6.5 `- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
`- [info] default cipher since OpenSSH 6.9 `- [info] default cipher since OpenSSH 6.9
(enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52 (enc) aes128-ctr -- [info] available since OpenSSH 3.7, Dropbear SSH 0.52
(enc) aes192-ctr -- [info] available since OpenSSH 3.7 (enc) aes192-ctr -- [info] available since OpenSSH 3.7

View File

@ -40,7 +40,7 @@
"notes": { "notes": {
"info": [ "info": [
"default cipher since OpenSSH 6.9", "default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
], ],
"warn": [ "warn": [
"vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation" "vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation"
@ -105,7 +105,7 @@
"algorithm": "curve25519-sha256", "algorithm": "curve25519-sha256",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 7.4 to 8.9",
"available since OpenSSH 7.4, Dropbear SSH 2018.76" "available since OpenSSH 7.4, Dropbear SSH 2018.76"
] ]
} }
@ -114,7 +114,7 @@
"algorithm": "curve25519-sha256@libssh.org", "algorithm": "curve25519-sha256@libssh.org",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 6.5 to 7.3",
"available since OpenSSH 6.4, Dropbear SSH 2013.62" "available since OpenSSH 6.4, Dropbear SSH 2013.62"
] ]
} }
@ -135,7 +135,7 @@
"algorithm": "ssh-ed25519", "algorithm": "ssh-ed25519",
"notes": { "notes": {
"info": [ "info": [
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
] ]
} }
} }

View File

@ -1,7 +1,7 @@
# general # general
(gen) banner: SSH-2.0-OpenSSH_8.0 (gen) banner: SSH-2.0-OpenSSH_8.0
(gen) software: OpenSSH 8.0 (gen) software: OpenSSH 8.0
(gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 7.4+, Dropbear SSH 2020.79+
(gen) compression: enabled (zlib@openssh.com) (gen) compression: enabled (zlib@openssh.com)
# security # security
@ -12,18 +12,18 @@
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4 (kex) diffie-hellman-group-exchange-sha256 (4096-bit) -- [info] available since OpenSSH 4.4
 `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).  `- [info] OpenSSH's GEX fallback mechanism was triggered during testing. Very old SSH clients will still be able to create connections using a 2048-bit modulus, though modern clients will use 4096. This can only be disabled by recompiling the code (see https://github.com/openssh/openssh-portable/blob/V_9_4/dh.c#L477).
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation (enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation
`- [info] available since OpenSSH 6.5 `- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
`- [info] default cipher since OpenSSH 6.9 `- [info] default cipher since OpenSSH 6.9
(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2 (enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2
(enc) aes128-gcm@openssh.com -- [info] available since OpenSSH 6.2 (enc) aes128-gcm@openssh.com -- [info] available since OpenSSH 6.2

View File

@ -18,7 +18,7 @@
"notes": { "notes": {
"info": [ "info": [
"default cipher since OpenSSH 6.9", "default cipher since OpenSSH 6.9",
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
], ],
"warn": [ "warn": [
"vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation" "vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation"
@ -43,7 +43,7 @@
"algorithm": "curve25519-sha256", "algorithm": "curve25519-sha256",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 7.4 to 8.9",
"available since OpenSSH 7.4, Dropbear SSH 2018.76" "available since OpenSSH 7.4, Dropbear SSH 2018.76"
] ]
} }
@ -52,7 +52,7 @@
"algorithm": "curve25519-sha256@libssh.org", "algorithm": "curve25519-sha256@libssh.org",
"notes": { "notes": {
"info": [ "info": [
"default key exchange from OpenSSH 6.4 to 8.9", "default key exchange from OpenSSH 6.5 to 7.3",
"available since OpenSSH 6.4, Dropbear SSH 2013.62" "available since OpenSSH 6.4, Dropbear SSH 2013.62"
] ]
} }
@ -75,7 +75,7 @@
"algorithm": "ssh-ed25519", "algorithm": "ssh-ed25519",
"notes": { "notes": {
"info": [ "info": [
"available since OpenSSH 6.5" "available since OpenSSH 6.5, Dropbear SSH 2020.79"
] ]
} }
} }

View File

@ -1,23 +1,23 @@
# general # general
(gen) software: TinySSH noversion (gen) software: TinySSH noversion
(gen) compatibility: OpenSSH 8.0-8.4, Dropbear SSH 2018.76+ (gen) compatibility: OpenSSH 8.0-8.4, Dropbear SSH 2020.79+
(gen) compression: disabled (gen) compression: disabled
# key exchange algorithms # key exchange algorithms
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76 (kex) curve25519-sha256 -- [info] available since OpenSSH 7.4, Dropbear SSH 2018.76
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 7.4 to 8.9
(kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62 (kex) curve25519-sha256@libssh.org -- [info] available since OpenSSH 6.4, Dropbear SSH 2013.62
 `- [info] default key exchange from OpenSSH 6.4 to 8.9  `- [info] default key exchange from OpenSSH 6.5 to 7.3
(kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm (kex) sntrup4591761x25519-sha512@tinyssh.org -- [warn] using experimental algorithm
`- [info] available since OpenSSH 8.0 `- [info] available since OpenSSH 8.0
`- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security `- [info] the sntrup4591761 algorithm was withdrawn, as it may not provide strong post-quantum security
# host-key algorithms # host-key algorithms
(key) ssh-ed25519 -- [info] available since OpenSSH 6.5 (key) ssh-ed25519 -- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
# encryption algorithms (ciphers) # encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation (enc) chacha20-poly1305@openssh.com -- [warn] vulnerable to the Terrapin attack (CVE-2023-48795), allowing message prefix truncation
`- [info] available since OpenSSH 6.5 `- [info] available since OpenSSH 6.5, Dropbear SSH 2020.79
`- [info] default cipher since OpenSSH 6.9 `- [info] default cipher since OpenSSH 6.9
# message authentication code algorithms # message authentication code algorithms

View File

@ -0,0 +1,13 @@
#
# Docker policy: test15
#
name = "Docker policy: test15"
version = 1
allow_algorithm_subset_and_reordering = true
banner = "SSH-2.0-OpenSSH_8.0"
compressions = none, zlib@openssh.com
host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519, extra_hostkey_alg
key exchanges = curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1, extra_kex_alg
ciphers = chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com, extra_cipher_alg
macs = umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1, extra_mac_alg

View File

@ -0,0 +1,13 @@
#
# Docker policy: test16
#
name = "Docker policy: test16"
version = 1
allow_algorithm_subset_and_reordering = true
banner = "SSH-2.0-OpenSSH_8.0"
compressions = none, zlib@openssh.com
host keys = rsa-sha2-512, extra_hostkey_alg
key exchanges = curve25519-sha256, extra_kex_alg
ciphers = chacha20-poly1305@openssh.com, extra_cipher_alg
macs = umac-64-etm@openssh.com, extra_mac_alg

View File

@ -0,0 +1,15 @@
#
# Docker policy: test17
#
name = "Docker policy: test17"
version = 1
allow_larger_keys = true
banner = "SSH-2.0-OpenSSH_8.0"
compressions = none, zlib@openssh.com
host keys = rsa-sha2-512, rsa-sha2-256, ssh-rsa, ecdsa-sha2-nistp256, ssh-ed25519
key exchanges = curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
ciphers = chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com
macs = umac-64-etm@openssh.com, umac-128-etm@openssh.com, hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, umac-128@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1
host_key_sizes = {"ssh-rsa": {"hostkey_size": 2048}, "rsa-sha2-256": {"hostkey_size": 2048}, "rsa-sha2-512": {"hostkey_size": 2048}, "ssh-ed25519": {"hostkey_size": 256}}
dh_modulus_sizes = {"diffie-hellman-group-exchange-sha256": 2048}

View File

@ -150,7 +150,7 @@ ciphers = cipher_alg1, cipher_alg2, cipher_alg3
macs = mac_alg1, mac_alg2, mac_alg3''' macs = mac_alg1, mac_alg2, mac_alg3'''
policy = self.Policy(policy_data=policy_data) policy = self.Policy(policy_data=policy_data)
assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True" assert str(policy) == "Name: [Test Policy]\nVersion: [1]\nAllow Algorithm Subset and/or Reordering: False\nBanner: {undefined}\nCompressions: comp_alg1\nHost Keys: key_alg1\nOptional Host Keys: {undefined}\nKey Exchanges: kex_alg1, kex_alg2\nCiphers: cipher_alg1, cipher_alg2, cipher_alg3\nMACs: mac_alg1, mac_alg2, mac_alg3\nHost Key Sizes: {undefined}\nDH Modulus Sizes: {undefined}\nServer Policy: True"
def test_policy_invalid_1(self): def test_policy_invalid_1(self):
@ -297,7 +297,7 @@ macs = mac_alg1, mac_alg2, mac_alg3'''
pol_data = pol_data.replace(date.today().strftime('%Y/%m/%d'), '[todays date]') pol_data = pol_data.replace(date.today().strftime('%Y/%m/%d'), '[todays date]')
# Instead of writing out the entire expected policy--line by line--just check that it has the expected hash. # Instead of writing out the entire expected policy--line by line--just check that it has the expected hash.
assert hashlib.sha256(pol_data.encode('ascii')).hexdigest() == '4af7777fb57a1dad0cf438c899a11d4f625fd9276ea3bb5ef5c9fe8806cb47dc' assert hashlib.sha256(pol_data.encode('ascii')).hexdigest() == 'fb84bce442cff2bce9bf653d6373a8a938e3bfcfbd1e876f51a08c1842df3cff'
def test_policy_evaluate_passing_1(self): def test_policy_evaluate_passing_1(self):
@ -440,3 +440,96 @@ macs = mac_alg1, mac_alg2, XXXmismatchedXXX, mac_alg3'''
assert len(errors) == 2 assert len(errors) == 2
assert error_str.find('Host keys did not match.') != -1 assert error_str.find('Host keys did not match.') != -1
assert error_str.find('MACs did not match.') != -1 assert error_str.find('MACs did not match.') != -1
def test_policy_evaluate_subset_passing_1(self):
'''Ensure that exact algorithm matches work even when subset parsing is enabled.'''
policy_data = '''name = "Test Policy"
version = 1
allow_algorithm_subset_and_reordering = true
compressions = comp_alg1, comp_alg2
host keys = key_alg1, key_alg2
key exchanges = kex_alg1, kex_alg2
ciphers = cipher_alg1, cipher_alg2, cipher_alg3
macs = mac_alg1, mac_alg2, mac_alg3'''
policy = self.Policy(policy_data=policy_data)
ret, errors, error_str = policy.evaluate('SSH Server 1.0', self._get_kex())
assert ret is True
assert len(errors) == 0
assert error_str == ""
def test_policy_evaluate_subset_passing_2(self):
'''Ensure that subset parsing works.'''
policy_data = '''name = "Test Policy"
version = 1
allow_algorithm_subset_and_reordering = true
compressions = comp_alg1, comp_alg2
host keys = key_alg2, key_alg1, key_alg0
key exchanges = kex_alg3, kex_alg1, kex_alg2
ciphers = cipher_alg0, cipher_alg3, cipher_alg2, cipher_alg1
macs = mac_alg2, mac_alg1, mac_alg3, mac_alg0'''
policy = self.Policy(policy_data=policy_data)
ret, errors, error_str = policy.evaluate('SSH Server 1.0', self._get_kex())
assert ret is True
assert len(errors) == 0
assert error_str == ""
def test_policy_evaluate_subset_failing_1(self):
'''Ensure that subset parsing returns a failure.'''
policy_data = '''name = "Test Policy"
version = 1
allow_algorithm_subset_and_reordering = true
compressions = comp_alg1, comp_alg2
host keys = key_alg7, key_alg8, key_alg9
key exchanges = kex_alg7, kex_alg8, kex_alg9
ciphers = cipher_alg7, cipher_alg8, cipher_alg9, cipher_alg10
macs = mac_alg7, mac_alg8, mac_alg9, mac_alg10'''
policy = self.Policy(policy_data=policy_data)
ret, errors, error_str = policy.evaluate('SSH Server 1.0', self._get_kex())
assert ret is False
assert len(errors) == 4
assert error_str.find("Ciphers did not match.") != -1
assert error_str.find("Host keys did not match.") != -1
assert error_str.find("MACs did not match") != -1
assert error_str.find("Key exchanges did not match.") != -1
def test_policy_evaluate_subset_failing_2(self):
'''Ensure that subset parsing returns a failure when policy includes kex-strict-s-v00@openssh.com, but target does not.'''
policy_data = '''name = "Test Policy"
version = 1
allow_algorithm_subset_and_reordering = true
compressions = comp_alg1, comp_alg2
host keys = key_alg2, key_alg1, key_alg0
key exchanges = kex_alg3, kex_alg1, kex_alg2, kex-strict-s-v00@openssh.com
ciphers = cipher_alg0, cipher_alg3, cipher_alg2, cipher_alg1
macs = mac_alg2, mac_alg1, mac_alg3, mac_alg0'''
policy = self.Policy(policy_data=policy_data)
ret, errors, error_str = policy.evaluate('SSH Server 1.0', self._get_kex())
assert ret is False
assert len(errors) == 1
assert error_str.find("Key exchanges did not match.") != -1
def test_policy_evaluate_subset_failing_3(self):
'''Ensure that subset parsing returns a failure when policy includes kex-strict-c-v00@openssh.com, but target does not.'''
policy_data = '''name = "Test Policy"
version = 1
allow_algorithm_subset_and_reordering = true
compressions = comp_alg1, comp_alg2
host keys = key_alg2, key_alg1, key_alg0
key exchanges = kex_alg3, kex_alg1, kex_alg2, kex-strict-c-v00@openssh.com
ciphers = cipher_alg0, cipher_alg3, cipher_alg2, cipher_alg1
macs = mac_alg2, mac_alg1, mac_alg3, mac_alg0'''
policy = self.Policy(policy_data=policy_data)
ret, errors, error_str = policy.evaluate('SSH Server 1.0', self._get_kex())
assert ret is False
assert len(errors) == 1
assert error_str.find("Key exchanges did not match.") != -1