(out: OutputBuffer, algs: Algorithms, is_json_output: bool)
| 286 | |
| 287 | |
| 288 | def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: bool) -> None: |
| 289 | with out: |
| 290 | fps = {} |
| 291 | if algs.ssh1kex is not None: |
| 292 | name = 'ssh-rsa1' |
| 293 | fp = Fingerprint(algs.ssh1kex.host_key_fingerprint_data) |
| 294 | # bits = algs.ssh1kex.host_key_bits |
| 295 | fps[name] = fp |
| 296 | if algs.ssh2kex is not None: |
| 297 | host_keys = algs.ssh2kex.host_keys() |
| 298 | for host_key_type in algs.ssh2kex.host_keys(): |
| 299 | if host_keys[host_key_type] is None: |
| 300 | continue |
| 301 | |
| 302 | fp = Fingerprint(cast(bytes, host_keys[host_key_type]['raw_hostkey_bytes'])) |
| 303 | |
| 304 | # Workaround for Python's order-indifference in dicts. We might get a random RSA type (ssh-rsa, rsa-sha2-256, or rsa-sha2-512), so running the tool against the same server three times may give three different host key types here. So if we have any RSA type, we will simply hard-code it to 'ssh-rsa'. |
| 305 | if host_key_type in HostKeyTest.RSA_FAMILY: |
| 306 | host_key_type = 'ssh-rsa' |
| 307 | |
| 308 | # Skip over certificate host types (or we would return invalid fingerprints), and only add one fingerprint in the RSA family. |
| 309 | if '-cert-' not in host_key_type: |
| 310 | fps[host_key_type] = fp |
| 311 | # Similarly, the host keys can be processed in random order due to Python's order-indifference in dicts. So we sort this list before printing; this makes automated testing possible. |
| 312 | fp_types = sorted(fps.keys()) |
| 313 | for fp_type in fp_types: |
| 314 | fp = fps[fp_type] |
| 315 | |
| 316 | # Don't output any ECDSA or DSS fingerprints unless verbose mode is enabled. |
| 317 | if fp_type.startswith("ecdsa-") or (fp_type == "ssh-dss"): |
| 318 | if out.verbose: |
| 319 | out.warn('(fin) {}: {} -- [info] this fingerprint type is insecure and should not be relied upon'.format(fp_type, fp.sha256)) |
| 320 | else: |
| 321 | continue # If verbose mode is not enabled, skip this type entirely. |
| 322 | else: |
| 323 | out.good('(fin) {}: {}'.format(fp_type, fp.sha256)) |
| 324 | |
| 325 | # Output the MD5 hash too if verbose mode is enabled. |
| 326 | if out.verbose: |
| 327 | out.warn('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5)) |
| 328 | |
| 329 | if not out.is_section_empty() and not is_json_output: |
| 330 | out.head('# fingerprints') |
| 331 | out.flush_section() |
| 332 | out.sep() |
| 333 | |
| 334 | |
| 335 | # Returns True if no warnings or failures encountered in configuration. |
no test coverage detected