#!/bin/bash
set -e
export LC_ALL=C
umask 077

this=$(dirname $0)
BINDIR=${this:=.}
LIBDIR=$(readlink -f "$BINDIR"/../lib)
VARSFILE="$LIBDIR"/vars.sh

if (( $# == 0  ))    # need the name
then
    $0 -h >&2
    exit 1
fi

tmp=$(getopt -n $0 -o hr -l help,revoke -- "$@")
eval set -- "$tmp"
while true
do
    o=$1; shift
    case "$o" in
    -h|--help)	cat <<-_HELP
	$0 [-revoke] CN [SAN]...
	    This creates a file "NAME-ssl.pem" containing the full bundle
	    (CA, Cert, Key) for the client named CN

            Example: $0 cert-proxy.example.com
                     $0 cert-proxy.example.com cert-proxy
_HELP
        exit 0 ;;
    -r|--revoke)
	mode=revoke;;
    --) break ;;
    esac
done

test -f "$VARSFILE" || {
    echo "$0: Can't source $VARSFILE" >&2
    exit 1
}

source "$VARSFILE"

function _git() {
    git -C "$CA_DIR" "$@"
}
function _gitclean() {
    _git reset --hard
    _git clean -d -f
}

trap _gitclean ERR

test -d "$CA_DIR" || {
    echo "$0: CA $CA_DIR is missing. Please run lib/mkca first" >&2
    exit 1
}

_gitclean

if test "$mode" = revoke
then
    cn="$1"; shift
    echo "revoking $cn"
    read -sp 'password: ' pw
    certs=$(grep "^V.*/CN=$cn$" $CA_DIR/index.txt \
	|| { echo "$cn not found" >&2
	  exit 1
	})
    <<<$certs tr -s '[[:space:]]' ' ' | cut -f3 -d' ' \
    | {
	while read serial; do
	serials+=($serial)
	pw=$pw openssl ca -passin env:pw -revoke $CA_DIR/newcerts/$serial.pem
    done
    test -f $CA_DIR/crlnumber || echo 00 > $CA_DIR/crlnumber
    (
	tmp=`mktemp`
	trap 'rm -f $tmp' EXIT
	pw=$pw openssl ca -passin env:pw -gencrl > $tmp
	mv $tmp crl.pem
    )
    _git add crlnumber
    _git add -u
    _git commit -m "Revoke $cn (${serials[@]})"
    }
else	# issue
    REQ_DIR=$CA_DIR/requests
    install -d -m 0700 "$REQ_DIR"

    cn=$1; shift

    install -d -m 0700 "$REQ_DIR/$cn"
    openssl genrsa -out "$REQ_DIR/$cn/key.pem" 4096
    gitfiles+=("$REQ_DIR/$cn/key.pem")

    ext="subjectAltName = DNS:$cn"
    for dns in $@; do
	ext+=", DNS:$dns"
    done

    openssl req -new -key "$REQ_DIR/$cn/key.pem" \
		-out "$REQ_DIR/$cn/csr.pem" \
		-subj "/C=$CA_DEFAULT_C/ST=$CA_DEFAULT_ST/L=$CA_DEFAULT_L/O=$CA_DEFAULT_O/OU=$CA_DEFAULT_OU/CN=$cn" \
		-addext "$ext"
    gitfiles+=("$REQ_DIR/$cn/csr.pem")

    install -d -m 0755 "$CA_DIR/certs"
    openssl ca -rand_serial -notext -out "$CA_DIR/certs/$cn.pem" -in "$REQ_DIR/$cn/csr.pem"
    gitfiles+=("$CA_DIR/certs/$cn.pem")
    gitfiles+=("$CA_DIR/newcerts")

    # the rest looks spooky, but we didn't want to touch new files until we
    # got our data
    ssl=(
	"$(openssl x509 -in "$CA_DIR/certs/$cn.pem")"
	"$(openssl rsa  -in "$REQ_DIR/$cn/key.pem")"
	"$(openssl x509 -in "$CA_DIR/cacert.pem")"
    )
    IFS=$'\x0a'; echo "${ssl[*]}" | tee "$cn-ssl.pem" >"$REQ_DIR/$cn/ssl.pem"
    gitfiles+=("$REQ_DIR/$cn/ssl.pem")

    openssl x509 -in "$CA_DIR/certs/$cn.pem" >"$REQ_DIR/$cn/crt.pem"
    gitfiles+=("$REQ_DIR/$cn/crt.pem")

    _git add "${gitfiles[@]}"
    _git add -u
    _git commit -m "New Cert for $cn"
fi
