#!/bin/sh
set -e -u

assert() {
	printf 'checking %s...' "${1:?}"
	shift
	if test "$@"
	then
		echo ''
	else
		echo " ! ($*)"
		rc=1
	fi
}

trap 'exit $((rc))' EXIT


CA_DIR=${AUTOPKGTEST_TMP:-/tmp}/easyrsa-cadir

# parameters
bits=2048
ca_days=3650
cert_days=365
ca_cn='My Example CA'
extended_cert_days=1095


make-cadir "${CA_DIR}"

export EASYRSA_BATCH=1

cd "${CA_DIR}"


# prepare PKI
./easyrsa init-pki

sed -i \
	-e "s/^#*\\(set_var EASYRSA_KEY_SIZE[[:space:]]*\\)[0-9]*$/\\1$((bits))/" \
	-e "s/^#*\\(set_var EASYRSA_CA_EXPIRE[[:space:]]*\\)[0-9]*$/\\1$((ca_days))/" \
	-e "s/^#*\\(set_var EASYRSA_CERT_EXPIRE[[:space:]]*\\)[0-9]*$/\\1$((cert_days))/" \
"${CA_DIR}/vars"


# create CA
./easyrsa --req-cn="${ca_cn}" build-ca nopass

test -s "${CA_DIR}/pki/ca.crt"


# create server certificates
./easyrsa build-server-full sample1.example.net nopass

test -s pki/private/sample1.example.net.key
test -s pki/issued/sample1.example.net.crt

./easyrsa --days=$((extended_cert_days)) --keysize=$((2 * bits)) build-server-full sample2.example.net nopass

test -s pki/private/sample2.example.net.key
test -s pki/issued/sample2.example.net.crt

./easyrsa --req-cn=sample3.example.net gen-req req-cn-test nopass
./easyrsa --days=365 sign-req server req-cn-test

test -s pki/private/req-cn-test.key
test -s pki/issued/req-cn-test.crt


# checks

cert_lifetime() {
	openssl x509 -dateopt iso_8601 -noout -dates -in "${1:?}" \
	| awk '
	  function toepoch(s,  cmd, r) {
		  cmd = "date -u -d \"" s "\" +%s"
		  cmd | getline r
		  close(cmd)
		  return r
	  }

	  /^notBefore=/ { not_before = toepoch(substr($0, index($0, "=")+1)) }
	  /^notAfter=/ { not_after = toepoch(substr($0, index($0, "=")+1)) }
          END { print ((not_after - not_before) / 86400) }
	  '
}
cert_pubkey_size() {
	openssl x509 -noout -text -in "${1:?}" \
	| sed -n -e '/Public-Key: /s/^[[:space:]]*Public-Key:[[:space:]]*(\([0-9]*\) bit)$/\1/p'
}

# The default value for the -nameopt option changed in OpenSSL 3.2 from
# `oneline' to `utf8'. The `oneline' option also included a space around
# the fields which is not the case for `utf8'. This means that
#         CN = domain.tld
# 
# changed to
# 
#         CN=domain.tld
# 
# and is now longer recognized, leading to test failure.
# This can be fixed by either going back to `oneline' or keeping `utf8'
# and adding additionally `space_eq'. Anoter way would be to teach the
# expect that the space is optional.
# 
# Add explicit -nameopt option with `utf8,space_eq' which is understood by
# by OpenSSL 3.2 and earlier to make it explicit.
# 
# Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
cert_subject() {
	openssl x509 -noout -nameopt utf8,space_eq -subject -in "${1:?}" | sed 's/^subject=//'
}


# check CA
assert 'CA public key length' \
	"$(cert_pubkey_size "${CA_DIR}/pki/ca.crt")" -eq $((bits))
assert 'CA subject' \
	"$(cert_subject "${CA_DIR}/pki/ca.crt")" = "CN = ${ca_cn}"
assert 'CA lifetime' \
	"$(cert_lifetime "${CA_DIR}/pki/ca.crt")" -eq $((ca_days))

# check sample1.example.net
assert 'sample1.example.net public key length' \
	"$(cert_pubkey_size "${CA_DIR}/pki/issued/sample1.example.net.crt")" -eq $((bits))
assert 'sample1.example.net subject' \
	"$(cert_subject "${CA_DIR}/pki/issued/sample1.example.net.crt")" = "CN = sample1.example.net"
assert 'sample1.example.net lifetime' \
	"$(cert_lifetime "${CA_DIR}/pki/issued/sample1.example.net.crt")" -eq $((cert_days))

# check sample2.example.net
assert 'sample2.example.net public key length' \
	"$(cert_pubkey_size "${CA_DIR}/pki/issued/sample2.example.net.crt")" -eq $((2 * bits))
assert 'sample2.example.net subject' \
	"$(cert_subject "${CA_DIR}/pki/issued/sample2.example.net.crt")" = "CN = sample2.example.net"
assert 'sample2.example.net lifetime' \
	"$(cert_lifetime "${CA_DIR}/pki/issued/sample2.example.net.crt")" -eq $((extended_cert_days))

# check req-cn-test
assert 'req-cn-test public key length' \
	"$(cert_pubkey_size "${CA_DIR}/pki/issued/req-cn-test.crt")" -eq $((bits))
assert 'req-cn-test subject' \
	"$(cert_subject "${CA_DIR}/pki/issued/req-cn-test.crt")" = "CN = sample3.example.net"
assert 'req-cn-test lifetime' \
	"$(cert_lifetime "${CA_DIR}/pki/issued/req-cn-test.crt")" -eq $((cert_days))
