-
Notifications
You must be signed in to change notification settings - Fork 8
/
ssh_fprint
executable file
·129 lines (113 loc) · 3.88 KB
/
ssh_fprint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#! /bin/bash
# ssh_fprint (Bourne shell script) -- Show all host key fingerprints & ASCII art
#
# Based on server_ssh_fingerprints v0.2 by Kepi <[email protected]>
#
# MIT License
#
# Print fingerprint matrix for all allowed Host Keys
# with all allowed ciphers and MD5 and SHA-256 algos
#
# Changelog:
#
# 2018-03-11 (0.2):
# - Support for newer versions of OpenSSH
# - Added visual keys for all algos too - only in recent OpenSSH versions
# 2018-04-29 (0.3):
# - Strips DSA key
# - Ensures output format is the same regardless of OpenSSH version
# - Also produces ASCII art for older OpenSSH versions
# - Uses openssl instead of sha256sum and xxd
# - Logic and indenting cleanups
# - Works with gawk (sub() wasn't stripping HostKey prefix from line)
# - Uses default when HostKey not set in sshd_config
# standard sshd config path
SSHD_CONFIG=/etc/ssh/sshd_config
# helper functions
function tablize {
awk '{printf(" | %-7s | %-7s | %-51s |\n", $1, $2, $3)}'
}
LINE=" +---------+---------+-----------------------------------------------------+"
# Warning: don't use in a pipe, because a pipe runs in a
# subshell and thus would throw away changes to global variables
function parse_fp {
local algo=$1 n=0 filter line
if [ "$2" = old ] ; then
# Older OpenSSH versions don't include the hash algorithm prefix
filter="s/^\\([^ =]*\\).*/\\1/"
else
# Newer OpenSSH versions do include the hash algorithm prefix; remove
filter="s/^${algo^^}:\\([^ =]*\\).*/\\1/"
fi
while read line
do
n=$((n + 1))
if [[ $n -eq 1 ]] ; then
ALGOS[$algo]=$(echo "$line" | sed "$filter")
else
# Alter old versions' ASCII art box to include algorithm
if [ "$line" = "+-----------------+" ] ; then
case $algo in
md5) line="+------[MD5]------+" ;;
sha256) line="+----[SHA256]-----+" ;;
esac
fi
ASCII[$n]="${ASCII[$n]} ${line}"
fi
done
}
# *** MAINLINE ***
# header
echo "$LINE"
echo "Cipher" "Algo" "Fingerprint" | tablize
echo "$LINE"
declare -A ALGOS
declare -a ASCII
# fingerprints
hostkey_files=$(awk '/^HostKey/ { print $2 ".pub" }' $SSHD_CONFIG)
if [ -z "$hostkey_files" ] ; then
# If HostKey not set in $SSHD_CONFIG, use the default
hostkey_files='/etc/ssh/ssh_host_rsa_key.pub
/etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key.pub'
fi
# (Fake piping into while loop by using a redirect, because a pipe runs in a
# subshell and thus would throw away changes to global variables)
while read -r host_key
do
cipher=$(echo "$host_key" |
sed -r 's/^.*ssh_host_([^_]+)_key\.pub$/\1/' |
tr 'a-z' 'A-Z')
if [ "$cipher" = DSA ] ; then
continue
fi
if [[ -f "$host_key" ]] ; then
if ssh-keygen -E md5 -l -f "$host_key" &>/dev/null
then
for algo in md5 sha256 ; do
parse_fp $algo < <(ssh-keygen -E $algo -lv -f "$host_key" |
sed '/^[0-9]/ s/^[^ ]* \([^ ]*\).*/\1/')
done
else
parse_fp md5 old < <(ssh-keygen -lv -f "$host_key" |
sed '/^[0-9]/ s/^[^ ]* \([^ ]*\).*/\1/')
# Note: no ASCII art
# TO-DO: Use https://github.com/atoponce/keyart Python script
parse_fp sha256 old < <(cut -f2 -d' ' "$host_key" |
base64 -d |
openssl dgst -sha256 -binary |
base64)
fi
echo "$cipher" MD5 "${ALGOS[md5]}" | tablize
echo "$cipher" SHA-256 "${ALGOS[sha256]}" | tablize
echo "$LINE"
fi
done < <(echo "$hostkey_files")
echo
for line in "${ASCII[@]}"; do
echo "$line"
done
# vim: set tabstop=4 shiftwidth=4 :
# Local Variables:
# tab-width: 4
# end: