#!/bin/sh -
PATH="/app/bin:/app/utilities/openssl/bin:$PATH"
PATH="/usr/local/homebrew:/app/linuxbrew/bin:$PATH"
PATH="/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:$PATH"
PATH="$PATH:/app/env/bin:/home/kinzler/share/appenv/bin"; export PATH
LD_LIBRARY_PATH="/app/utilities/openssl/lib:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH
perlopts='-I/app/env/lib/perl'
umask 077

timeout=5

# certinfo - output various SSL certificate information, not comprehensive
# Steve Kinzler, steve@kinzler.com, Sep 16/May 20
# https://kinzler.com/me/home.html#webadm

# See also certtool(1) from gnutls-bin

case "`openssl version`" in
OpenSSL\ 0*)	echo "$0: warning, older openssl may not recognize all certs" \
			1>&2; exit;;
esac
case "`openssl x509 -help 2>&1`" in
*' -ext '*)	ext=' -ext subjectAltName';;	# 1.1.1b and later
esac

prog="`basename $0`"
line='=========='
none='Modulus:
key not found
Exponent:'

all=
case "$1" in
-@)	all=-showcerts; shift;;
esac

mode=
case "$1" in
-h)		cat <<EOF 1>&2; exit 1;;
usage: $prog [ -@ ] [ -s | -t | -k | -K ] [ host[:port] | file | - ] ...
	-@	include the whole CA chain from hosts
	-s	output one-line text of the certificates (default brief)
	-t	output full text of the certificates (default brief)
	-k	ouput the key modulus of the given files
	-K	ouput the first line of the key modulus of the given files
The CERTINFO_OPENSSL_ARGS environment variable can be set to additional
arguments to the openssl commands.
EOF
-[stkK])	mode="$1"; shift;;

-[fF]oreach)	case "$1" in -F*) F=1;; *) F=0;; esac
		shift; arg="$1"; shift; exec perl -e '
	$_ = join "", <>; /^--* *BEGIN ([\w ]*?) *--*\s*$/mi;
	$n = 1;		  ($b, $t) = ($&, $1);
	@_ = map "$b$_", grep /^--* *END $t *--*\s*$/mi,
			      split /^--* *BEGIN $t *--*\s*$/mi; $N = $#_ + 1;
	foreach (@_) { open (C, "| color on_blue"),
		       print(C "'"$line $arg"' $n/$N '$line'\n"), $n++
				if '$F';
		       open  C, "| '"$*"'"; print C } close C';;
	# NOTE: "close C" prevents premature exit in some circumstances

-oneline)	openssl x509 -noout -subject -dates | perl $perlopts -e '
	$_ = join "", <>; use Time::ParseDate; use Time::CTime;
	($s = $_) =~ s/.*^subject\s*=\s*//ims; $s =~ s/\n.*//s;
	$s = join "/", reverse grep /./, split /\//, $s;
	s/.*^notAfter\s*=\s*//ims ? s/\n.*//s : ($_ = "?");
	print strftime("%Y-%m-%d", localtime parsedate $_), " $s; "'; exit;;
esac

tmp="${TMPDIR:-/tmp}/ci$$"
trap "rm -f '$tmp'; exit" 0 1 2 13 15

opts="-noout -text $CERTINFO_OPENSSL_ARGS"

for arg
do	oarg="$arg"

	case "$arg" in
	-)	cat > "$tmp"; arg="$tmp";;
	esac

	if test -e "$arg"
	then
		case `perl -ne 'print(uc $1), exit
			if /^--* *BEGIN ([\w ]*?) *--*\s*$/i' "$arg"` in
		*PRIVATE*KEY*)		type=key;;
		*PUBLIC*KEY*)		type=pub;;
		*CERTIFICATE*REQUEST*)	type=csr;;
		*CERTIFICATE*)		type=crt;;
		*X509*CRL*)		type=crl;;
		*DSA*PARAMETERS*)	type=dsa;;
		*DH*PARAMETERS*)	type=dh;;
		*)	echo "$prog: skipping $arg," \
			     "cannot determine file type" 1>&2; continue;;
		esac
	else
		type=host
		case "$arg" in
		*:*)	;;
		*)	arg="$arg:443";;
		esac
	fi 

	case "$type" in
	host)	safe -d "$timeout" -q openssl s_client -connect "$arg" \
			-servername `echo "$arg" | sed 's/:.*//'` $all \
			< /dev/null 2> /dev/null;;
	*)	cat "$arg";;
	esac |
	case "$mode" in

	-s)	case "$type" in
		crt|host)	$0 -foreach "$arg" $0 -oneline |
					perl -pe 's/; $/\n/';;
		csr)		$0 "$arg" | sed -n 2p;;
		*)		$0 -K "$arg";;
		esac 2> /dev/null;;

	-t)	case "$type" in
		key)	$0 -Foreach "$arg" openssl rsa		$opts;;
		pub)	$0 -Foreach "$arg" openssl rsa		$opts -pubin;;
		csr)	$0 -Foreach "$arg" openssl req		$opts;;
		crl)	$0 -Foreach "$arg" openssl crl		$opts;;
		dsa|dh)	$0 -Foreach "$arg" openssl ${type}param	$opts;;
		*)	$0 -Foreach "$arg" openssl x509	       $opts -purpose;;
		esac 2> /dev/null;;

	-k)	($0 -t "$arg"; echo "$none") |
			sed 's/ *([0-9]*.bit)//g;
			     1,/^ *.odulus:$/d; /xponent/,$d; s/^ *//';;
	-K)	echo "$oarg:	" | tr -d '\012' 
		($0 -k "$arg"; echo '') | sed -n 1p;;	# full read for aix

	*)	case "$type" in
		crt|host)	$0 -Foreach "$arg" \
				  openssl x509 -noout -subject \
					       -issuer -dates$ext;;
		csr)		$0 -Foreach "$arg" openssl req $opts \| \
				  sed -n s/^.*Subject:.//p;;
		*)		$0 -t "$arg";;
		esac 2> /dev/null;;
	esac
done
