#!/bin/sh

if ! type -t success >/dev/null; then
	WITHOUT_RC_COMPAT=1
	. /etc/init.d/functions
fi

OPENSSL="${OPENSSL:-openssl}"
OPENSSL_CONFIG="${OPENSSL_CONFIG:-openssl-config}"
SSLDIR="${SSLDIR:-$($OPENSSL_CONFIG --openssldir)}"
SSLDIR="${SSLDIR:-/var/lib/ssl}"

SSL_KEYDIR="$SSLDIR/private"
SSL_CERTDIR="$SSLDIR/certs"
SSL_CSRDIR="$SSLDIR/certs"

#certificate config template
DEFAULT_CERT="
[ req ]
default_bits = 1024
encrypt_key = yes
distinguished_name = req_dn
x509_extensions = cert_type
prompt = no

[ req_dn ]
CN=@HOSTNAME@
O=@PRODUCT@

[ cert_type ]
nsCertType = server
"

TEMP_CERT=

ssl_exit_handler()
{
	local rc=$?
	trap - EXIT
	[ -z "$TEMP_CERT" ] ||
	    rm -f -- "$TEMP_CERT"
	exit $rc
}

ssl_fatal()
{
    printf >&2 '%s\n' "${0##*/}: $*"
    exit 1
}

#private key

ssl_check_key()
{
    [ -n "$1" -a -f "$SSL_KEYDIR/$1.key" ]
}

ssl_make_key()
{
    ssl_check_key "$@" && return
    [ -n "$1" ] ||
	ssl_fatal 'Insufficient arguments.'

    "$OPENSSL" genrsa -out "$SSL_KEYDIR/$1.key" 1024 >/dev/null 2>&1 ||
	ssl_fatal "Unable to create private key"
}

#certificate request

_ssl_make_req()
{
    local name
    name="$1" && shift

    "$OPENSSL" req -batch -new -key "$SSL_KEYDIR/$name.key" -out "$SSL_CSRDIR/$name.csr" "$@" ||
	ssl_fatal "Unable to create sign request"
}

ssl_check_req()
{
    [ -n "$1" -a -f "$SSL_CSRDIR/$1.csr" ]
}

ssl_make_req()
{
    ssl_check_req "$@" && return
    [ -n "$1" ] ||
	ssl_fatal 'Insufficient arguments.'

    local name
    name="$1" && shift

    if [ $# -gt 0 ]; then
	if [ -f "$1" ]; then
	    _ssl_make_req "$name" -config "$1"
	else
	    _ssl_make_req "$name" -subj "$@"
	fi
    else
	local HOSTNAME="$(hostname)"
	HOSTNAME="${HOSTNAME:-localhost.localdomain}"

	trap ssl_exit_handler HUP INT QUIT TERM EXIT
	TEMP_CERT="$(mktemp -t default.cnf.XXXXXX)"
	echo "$DEFAULT_CERT" |
	    sed -e "s|@HOSTNAME@|$HOSTNAME|" -e "s|@PRODUCT@|$name|" >"$TEMP_CERT"

	_ssl_make_req "$name" -config "$TEMP_CERT"
	rm -f "$TEMP_CERT"
	TEMP_CERT=
    fi
}

#certificate

ssl_check_cert()
{
    [ -n "$1" -a -f "$SSL_CERTDIR/$1.cert" ]
}

ssl_make_cert()
{
    ssl_check_cert "$@" && return
    [ -n "$1" ] ||
	ssl_fatal 'Insufficient arguments.'


    "$OPENSSL" x509 -req -days 365 -in "$SSL_CSRDIR/$1.csr" -signkey "$SSL_KEYDIR/$1.key" -out "$SSL_CERTDIR/$1.cert" >/dev/null 2>&1 ||
	ssl_fatal 'Unable to create certificate'

    ln -sf "$1.cert" "$SSL_CERTDIR/$1.pem" &&
	c_rehash "$SSL_CERTDIR" >/dev/null
}

#PEM certificate

ssl_check_pem()
{
    [ -n "$1" -a -f "$SSL_KEYDIR/$1.pem" -a "$SSL_KEYDIR/$1.pem" -nt "$SSL_KEYDIR/$1.key" -a "$SSL_KEYDIR/$1.pem" -nt "$SSL_CERTDIR/$1.cert" ]
}

ssl_make_pem()
{
    ssl_check_pem "$@" && return
    [ -n "$1" ] ||
	ssl_fatal 'Insufficient arguments.'

    cat "$SSL_CERTDIR/$1.cert" "$SSL_KEYDIR/$1.key" > "$SSL_KEYDIR/$1.pem" ||
	ssl_fatal 'Unable to create PEM certificate'
}

#dh params

ssl_check_dhparam()
{
    [ -n "$1" -a -f "$SSL_KEYDIR/$1.dh" ]
}


ssl_make_dhparam()
{
    "$OPENSSL" dhparam -out "$SSL_KEYDIR/$1.dh" "$2" >/dev/null 2>&1 ||
	ssl_fatal 'Unable to genarate DH parameters'
}

ssl_action()
{
    local fun="$1"; shift
    local msg="$1"; shift

    printf $"Generating %s %s: " "$1" "$msg" 

    if "$fun" "$@"; then
	success "$1 $msg generation"
	echo
    else
	failure "$1 $msg generation"
	echo
	exit 1
    fi
}

ssl_generate()
{
    [ -n "$1" ] ||
	ssl_fatal 'Insufficient arguments.'

    ssl_check_key "$@" ||
	ssl_action ssl_make_key "SSL private key" "$@"

    ssl_check_req "$@" ||
	ssl_action ssl_make_req "SSL certificate request" "$@"

    ssl_check_cert "$@" ||
	ssl_action ssl_make_cert "SSL self-signed certificate" "$@"

    ssl_check_pem "$@" ||
	ssl_action ssl_make_pem "SSL PEM certificate" "$@"
}
