#!/bin/sh
#
# Generate-once a DEDICATED self-signed SIP-TLS cert/key (single-purpose —
# never the uhttpd WebUI key). Signed by the per-device CA, registered in the
# Certificate Manager as service 'asterisk:sip-tls' for independent rotation.
# Skips if a cert already exists (prior boot or operator-supplied).

. /lib/functions.sh

OPENSSL_BIN="/usr/bin/openssl"

SIP_CERT="/etc/certificates/asterisk-sip.crt"
SIP_KEY="/etc/certificates/asterisk-sip.key"
CA_CERT="/etc/certificates/uhttpd-ca.crt"
CA_KEY="/etc/certificates/uhttpd-ca.key"

DAYS=3650

# Key algorithm — selectable from UCI (WebUI-bindable later).
#   asterisk.general.tls_key_type  = ec (default) | rsa
#   asterisk.general.tls_ec_curve  = P-384 (default) | P-256
#   asterisk.general.tls_rsa_bits  = 2048 (default)
# EC P-384 (~192-bit, CNSA-1.0 aligned) is the default: stronger than RSA-2048
# (NIST-deprecated after 2030, shorter than this cert's lifetime) and cheap to
# generate on the SoC — SIP-TLS handshakes are per-connection, not per-packet.
# Set tls_key_type=rsa only if an upstream PBX can't negotiate ECDSA.
config_load asterisk 2>/dev/null
config_get KEY_TYPE general tls_key_type ec
config_get EC_CURVE general tls_ec_curve P-384
config_get RSA_BITS general tls_rsa_bits 3072

if [ "$KEY_TYPE" = "rsa" ]; then
	KEY_OPTS="rsa:$RSA_BITS"
	ENC="rsa"
	KEY_SIZE="$RSA_BITS"
else
	KEY_TYPE="ec"
	KEY_OPTS="ec -pkeyopt ec_paramgen_curve:$EC_CURVE"
	ENC="ecc"
	KEY_SIZE="${EC_CURVE#P-}"
fi

[ -x "$OPENSSL_BIN" ] || exit 0

# Generate-once, BUT regenerate if the on-disk cert's algorithm no longer
# matches the requested tls_key_type — that's what makes a UI switch between
# EC and RSA take effect on the next reload. A cert matching the request (or
# an operator-uploaded one of the right type) is left alone.
if [ -s "$SIP_CERT" ] && [ -s "$SIP_KEY" ]; then
	cur_algo="$($OPENSSL_BIN x509 -in "$SIP_CERT" -noout -text 2>/dev/null | \
		grep -i 'Public Key Algorithm')"
	case "$cur_algo" in
		*id-ecPublicKey*) [ "$KEY_TYPE" = "ec" ]  && exit 0 ;;
		*rsaEncryption*)  [ "$KEY_TYPE" = "rsa" ] && exit 0 ;;
	esac
	# mismatch or unreadable → fall through and regenerate
fi

# CA absent = uhttpd cert tooling hasn't run yet; init.d retries next reload.
[ -s "$CA_CERT" ] && [ -s "$CA_KEY" ] || exit 0

MAC="$(mnf_info -m 2>/dev/null)"

TMP_KEY="$(mktemp)"
TMP_CRT="$(mktemp)"
TMP_REQ="$(mktemp)"
EXT="$(mktemp)"
trap 'rm -f "$TMP_KEY" "$TMP_CRT" "$TMP_REQ" "$EXT"' EXIT

$OPENSSL_BIN req -nodes \
	-subj "/O=Teltonika/CN=Teltonika${MAC}-sip" \
	-newkey $KEY_OPTS -keyout "$TMP_KEY" -out "$TMP_REQ" >/dev/null 2>&1 || exit 0

# serverAuth for the [tls] transport, clientAuth for outbound trunk registration.
printf 'extendedKeyUsage=serverAuth,clientAuth\nsubjectAltName=DNS:Teltonika%s\n' \
	"$MAC" > "$EXT"

$OPENSSL_BIN x509 -req -in "$TMP_REQ" -CA "$CA_CERT" -CAkey "$CA_KEY" \
	-out "$TMP_CRT" -days "$DAYS" -extfile "$EXT" >/dev/null 2>&1 || exit 0

cat "$TMP_KEY" > "$SIP_KEY"
cat "$TMP_CRT" > "$SIP_CERT"
chown uhttpd:uhttpd "$SIP_CERT" "$SIP_KEY" 2>/dev/null || true
chmod 0660 "$SIP_CERT" "$SIP_KEY"

# Register in the Certificate Manager so the WebUI can track expiry and
# rotate/replace it. Fields mirror the uhttpd cert tool's registration.
if [ -e /etc/config/certificates ]; then
	expiry=$(( $(date +%s) + $DAYS * 86400 ))

	if ! uci -q get certificates.asterisk_sip_cert >/dev/null 2>&1; then
		uci -q set certificates.asterisk_sip_cert='certificate'
		uci -q set certificates.asterisk_sip_cert.type='cert'
		uci -q set certificates.asterisk_sip_cert.cert_type='server'
		uci -q set certificates.asterisk_sip_cert.name='Asterisk SIP-TLS'
		uci -q set certificates.asterisk_sip_cert.fullname="$(basename "$SIP_CERT")"
		uci -q set certificates.asterisk_sip_cert.path="$SIP_CERT"
		uci -q add_list certificates.asterisk_sip_cert.services='asterisk@sip_gateway:1'
	fi
	uci -q set certificates.asterisk_sip_cert.datetime="$expiry"
	uci -q set certificates.asterisk_sip_cert.encryption="$ENC"
	uci -q set certificates.asterisk_sip_cert.key_size="$KEY_SIZE"

	if ! uci -q get certificates.asterisk_sip_key >/dev/null 2>&1; then
		uci -q set certificates.asterisk_sip_key='certificate'
		uci -q set certificates.asterisk_sip_key.type='key'
		uci -q set certificates.asterisk_sip_key.cert_type='server'
		uci -q set certificates.asterisk_sip_key.pass_required='0'
		uci -q set certificates.asterisk_sip_key.name='Asterisk SIP-TLS key'
		uci -q set certificates.asterisk_sip_key.fullname="$(basename "$SIP_KEY")"
		uci -q set certificates.asterisk_sip_key.path="$SIP_KEY"
		uci -q add_list certificates.asterisk_sip_key.services='asterisk@sip_gateway:1'
	fi
	uci -q set certificates.asterisk_sip_key.datetime="$expiry"
	uci -q set certificates.asterisk_sip_key.encryption="$ENC"
	uci -q set certificates.asterisk_sip_key.key_size="$KEY_SIZE"

	uci -q commit certificates
fi

exit 0
