blob: e6e38fe259a05b136531931c6ca161fe5716689a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
#!/bin/bash
# see also Docs/ssl-infos/tools/
# i= &&tail -n+$((i*5000)) /tmp/top-1m.csv | head -5000 |~/scripts/cert-info csv $i
# killall -v cert-info -s 0
usage() {
[ -z "$1" ] || echo "$1" >&2
echo "Usage: $0 [options] hostname[:port] [hostname[:port]].." >&2
echo " $0 csv out-dir <file [options]" >&2
echo "options (may be interleaved between hosts):"
awk '/^parse_arg\(/{p=1}
/}/{if(p)exit}
/#/{if(p){sub(/\).*# */,"\t");print}}' "$0"
echo "csv file from http://s3.amazonaws.com/alexa-static/top-1m.csv.zip"
exit 1
}
auto_less() {
[ ! -t 1 ] || { "$0" "$@" | less; exit $?; }
}
# Compatibility for macOS
type timeout 2>/dev/null >&2 ||
timeout() { perl -e 'alarm shift; exec @ARGV' "$@"; }
main() {
if [ "$1" = "csv" ]; then
[ $# -ge 2 ] || usage "Missing outdir"
outdir="${2:-.}/"
mkdir -p "$outdir"
tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT
shift 2
for arg; do parse_arg "$arg" || usage "Unrecognized option $arg"; done
i=0
while IFS=,; read -r no host; do
# strip path if any
host="${host%%/*}"
[ -n "$host" ] || continue
outfile="$outdir$host.txt"
if [ -e "$outfile" ]; then
echo "Skipping existing $outfile"
else
printf "%5d %s %6d %s\n" $((++i)) "$(date -R)" "$no" "$host"
get_cert "$host" 443 | parse_cert > "$tmp" 2>&1
mv "$tmp" "$outfile"
#[ -s "$outfile" ] || echo "# no cert for $host"
fi
done
elif [ ! -t 0 ]; then
auto_less "$@"
for arg; do
parse_arg "$arg" || :
done
parse_cert
elif [ $# -gt 0 ]; then
auto_less "$@"
for arg; do
! parse_arg "$arg" || continue
host="${arg%%:*}"
port="${arg##*:}"
[ "$port" != "$arg" ] && [ -n "$port" ] || port=443
echo "# === $host:$port ==="
get_cert "$host" "$port" | parse_cert
done
else
usage
fi
}
get_cert() {
local host="$1" port="$2"
if ! nc -z -w 2 "$host" "$port" 2>/dev/null; then
echo "# conn timeout for $host:$port!" >&2
return 1
fi
</dev/null 2>/dev/null \
timeout 5 openssl s_client \
-connect "$host:$port" -servername "$host" -showcerts
}
parse_arg() {
case "$1" in
-) depth_1=1 ;; # less certificates [def]
+) depth_1=0 ;; # more certificates
-=) cert_only=1 ;; # less output (just raw cert)
+=) cert_only=0 ;; # more output (verbose details) [def]
-cert) include_cert=0 ;; # hide raw cert (-noout)
+cert) include_cert=1 ;; # include raw cert [def]
*) return 1 ;;
esac
}
parse_arg -
parse_arg +=
parse_arg +cert
parse_cert() {
infocmd="openssl x509 -text -nameopt sep_comma_plus_space"
[ $include_cert -eq 1 ] || infocmd="$infocmd -noout"
awk -v OneOnly="$depth_1" -v CertOnly="$cert_only" \
-v infocmd="$infocmd" '
BEGIN {
sep="# ";
for (i=0; i<77; i++) {
sep=sep"-";
}
}
/^-----BEGIN (TRUSTED )?CERTIFICATE-----$/ {
in_cert=1;
}
{
if (in_cert) {
cert = cert $0 "\n";
}
}
/^-----END (TRUSTED )?CERTIFICATE-----$/ {
in_cert = 0;
}
{
if (!in_cert && cert) {
if (CertOnly) {
print cert;
} else {
print cert | infocmd;
close(infocmd);
print sep;
}
cert="";
if (OneOnly) exit;
}
}
'
}
main "$@"
|