#!/bin/sh

po_domain="alterator-sslkey"
alterator_api_version=1

. alterator-sh-functions
. shell-config
. cert-sh-functions

OPENSSL="${OPENSSL:-/usr/bin/openssl}"
sysconfigclock_file=/etc/sysconfig/clock
zonetab_file=/usr/share/zoneinfo/zone.tab

get_expire_date()
{
    local cert="$1"; shift
    local d="$($OPENSSL x509 -noout -enddate -in "$cert" | sed -nr 's/^[[:blank:]]*notAfter=(.+)$/\1/p' 2>/dev/null)"

    [ -n "$d" ] && date --date="$d" +%x
}

is_cert()
{
    [ -n "$1" ] || return 1
    $OPENSSL x509 -noout -in "$1" 2>/dev/null
}

ssl_modulus_md5()
{
    [ -n "$1" -a -n "$2" ] || return 1
    $OPENSSL "$1" -noout -modulus -in "$2" | $OPENSSL md5
}

validate_cert()
{
    local cert="$1"; shift
    local key="$1"; shift

    [ -f "$cert" -a -f "$key" ] && is_cert "$cert" && \
    [ "$(ssl_modulus_md5 x509 "$cert")" = "$(ssl_modulus_md5 rsa "$key")" ]
}

### lists
list_keys()
{
	find "$SSL_KEYDIR" -type f -name \*.key -printf "%f\n" | sed s/.key//g 2>/dev/null
}

list_sslfiles()
{
	local str= expire=
	list_keys | sort | while read i;
	do
		if ssl_check_cert "$i"; then
			if validate_cert "$SSL_CERTDIR/$i.cert" "$SSL_KEYDIR/$i.key"; then
                expire="$(get_expire_date "$SSL_CERTDIR/$i.cert")"
                if [ -n "$expire" ]; then
                    str="(`_ "expire"`: $expire)"
                else
                    str="(`_ "OK certificate"`)"
                fi
			else
				str="(`_ "Invalid certificate"`)"
			fi
		else
			str="(`_ "No certificate"`)"
		fi
		write_enum_item "$i" "$i $str"
	done
}

### read
_get_subj_item()
{
	[ -n "$1" -a -n "$2" -a -n "$3" ] || return
	$OPENSSL "$1" -noout -subject -in "$2" | sed -rn "s|^.*/$3=([^/]+).*$|\1|p" 2>/dev/null
}

get_subj_item()
{
	local name="$1"; shift
	local item="$1"; shift
	[ -n "$name" -a -n "$item" ] || return

	if ssl_check_req "$name"; then
		_get_subj_item req "$SSL_CSRDIR/$name.csr" "$item"
	elif ssl_check_cert "$name"; then
		_get_subj_item x509 "$SSL_CERTDIR/$name.cert" "$item"
	fi
}

read_ssl()
{
	local items='CN O C L OU emailAddress'
	if [ -n "$1" ] && ssl_check_key "$1"; then
		write_bool_param key_exist true
		for i in $items; do
			write_string_param "$i" "$(get_subj_item "$1" "$i")"
		done
	else
		write_bool_param key_exist false
	fi
}

read_zone()
{
	shell_config_get "$sysconfigclock_file" ZONE
}

read_country()
{
	local zone="$(read_zone)"

	[ -n "$zone" ] || return

	grep "$zone" "$zonetab_file" | cut -f1
}

read_location()
{
	local zone="$(read_zone)"

	echo "${zone##*/}"
}

read_ssl_defaults()
{
	write_string_param CN "$DEFAULT_CN"
	write_string_param O "$DEFAULT_O"
	write_string_param C "$(read_country)"
	write_string_param L "$(read_location)"
	write_string_param OU "$DEFAULT_OU"
	write_string_param emailAddress "$DEFAULT_emailAddress"
}
### write
make_name()
{
	local name=

	if [ -n "$in_CN" ]; then
		name="$in_CN"
	elif [ -n "$in_O" ]; then
		name="$in_O"
	elif [ -n "$in_OU" ]; then
		name="$in_OU"
	else
		return
	fi

	echo "$name"
}

create_sslconf()
{
	local cn="$in_CN"
	local org="${in_O:+O=$in_O\n}"
	local country="${in_C:+C=$in_C\n}"
	local locality="${in_L:+L=$in_L\n}"
	local ounit="${in_OU:+OU=$in_OU\n}"
	local email="${in_emailAddress:+emailAddress=$in_emailAddress\n}"
	local sslconf=

	[ -n "$1" ] || return
	if [ -z "$cn" ]; then
		local hostname="$(hostname)"
		cn="${hostname:-localhost.localdomain}"
	fi

	sslconf="$(mktemp -t "ssl_$1.conf.XXXXXXXX")"
	echo "$DEFAULT_CERT" |
	sed -e "s|@HOSTNAME@|$cn|" \
	-e "s|^O=@PRODUCT@|$org$country$locality$ounit$email|" \
	>"$sslconf"

	echo "$sslconf"
}

write_ssl()
{
	local sslconf="$(create_sslconf "$1")"
	if [ -n "$sslconf" ]; then
		rm -f "$SSL_KEYDIR/$1.key"
		rm -f "$SSL_CSRDIR/$1.csr"
		ssl_make_key "$1" "$sslconf"
		ssl_make_req "$1" "$sslconf"
		rm "$sslconf"
	fi
}

###

on_message()
{
	case "$in_action" in
        type)
        write_type_item CN ssl-cert-field
        write_type_item C ssl-cert-country-code
        write_type_item L ssl-cert-field
        write_type_item O ssl-cert-field
        write_type_item OU ssl-cert-field
        write_type_item emailAddress e-mail
		;;
		read)
		case "$in__objects" in
			/)
			read_ssl "$in_name"
            if [ -n "$in_name" ]; then
                SSL_FILES_NAME="$in_name"
            fi
			;;
			name)
			write_string_param name "$SSL_FILES_NAME"
			;;
			sslkey-default)	read_ssl_defaults
			;;
			csr)
			write_string_param csr "$SSL_CSRDIR/$SSL_FILES_NAME.csr"
			;;
			make-name)
			local name="$(make_name)"
			if [ -n "$name" ]; then  
				SSL_FILES_NAME="$name"
				write_string_param name "$name"
			else
				write_error "`_ "Unable to determine file name"`"
			fi
			;;
			*)
			;;
		esac
		;;
		write)
		case "$in__objects" in
			/)
			if [ -n "$in_name" ]; then
				SSL_FILES_NAME="$in_name"
				write_ssl "$in_name"
			fi
			;;
			reset-name)
			SSL_FILES_NAME="$in_name"
			;;
			upload|import-cert)
			local name="${in_name:-$SSL_FILES_NAME}"
			[ -n "$in_certificate" -a -n "$name" ] || return

			local keyfile="$SSL_KEYDIR/$name.key"
			local certfile="$SSL_CERTDIR/$name.cert"

			if validate_cert "$in_certificate" "$keyfile"; then
				cp -f "$in_certificate" "$certfile"
				chmod 644 "$certfile"
			else
				write_error "`_ "Invalid certificate file"`"
			fi
			;;
			export-request)
			if [ -n "$in_path" -a -n "$in_name" ]; then
				if [ ! -f "$SSL_CSRDIR/$in_name.csr" ]; then
					write_error "`_ "Sign request does not exist"`"
				elif [ ! -d "$in_path" ]; then
					write_error "`_ "Target directory does not exist"`"
				else
					cp -T "$SSL_CSRDIR/$in_name.csr" "$in_path/$in_name.csr" ||
						write_error "`_ "Export sign request failed"`"
				fi
			fi
			;;
			delete)
			if [ -n "$in_name" ]; then
				rm -f "$SSL_KEYDIR/$in_name.key" "$SSL_CERTDIR/$in_name.cert" "$SSL_CSRDIR/$in_name.csr"
			fi
			;;
		esac
		;;
		list)
		case "${in__objects##*/}" in
			avail_keys)
            set_locale
            list_sslfiles
			;;
			*)
			;;
		esac
		;;
	esac
}

message_loop

