#!/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 &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 \ 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 "$@"