#!/usr/bin/env bash

set -eux

if ! groups | grep -q softhsm; then
    echo "User $(whoami) is not in 'softhsm' group. Fixing permissions..."
    sudo adduser $(whoami) softhsm
    exec newgrp -c "$0" softhsm
fi

tests_dir=$(dirname "$(realpath $0)")
tmpdir=$(mktemp -d -t "swugenerator-autopkgtest-XXXXXX")

export CA_DIR="${tmpdir}"
echo -n 01 > "${CA_DIR}/serial"
touch "${CA_DIR}/index.txt"
mkdir -p "${CA_DIR}/new_certs"

module=$(realpath "$(find /usr/lib/*softhsm/libsofthsm2.so | head -n 1)")
token_name="autopkgtest"
pin="1234"
obj_id="0001"
echo -n "$pin" > "${tmpdir}/pinfile"

# Init softhsm

slot=$(softhsm2-util \
  --init-token \
  --label "$token_name" \
  --pin "$pin" --so-pin "$pin" --free | \
  sed -n 's/.*slot \([[:digit:]]\+\)/\1/p')

trap 'softhsm2-util --delete-token --token "$token_name"' EXIT

softhsm2-util --show-slots

# Debian's swupdate is compiled with CONFIG_SIGALG_CMS, thus
# it can only verify CMS signatures. We need a custom method to
# verify raw signatures as created with swugenerator -k PKCS11.

function verify_image_cms() {
  local img="$1"
  shift

  swupdate -c -v \
    -i "$img" \
    -H "autopkgtest:1.0" \
    --ca-path "${CA_DIR}/test-root-CA.pem" \
    --cert-purpose codeSigning | \
    grep "swupdate_verify_file.*Verified OK"
}

function verify_image_raw() {
  local img="$1"
  shift

  local xdir="${tmpdir}/${img}.x"
  mkdir -p "$xdir"
  cpio -i -D "$xdir" < "$img" "sw-description*"
  openssl x509 \
    -pubkey -noout \
    -in "${tmpdir}/test-signer-0001.pem" > \
    "${tmpdir}/test-signer-0001-pubkey.pem"
  openssl dgst \
    -verify "${tmpdir}/test-signer-0001-pubkey.pem" \
    -signature "${xdir}/sw-description.sig" \
    "${xdir}/sw-description"
}

## Root CA certificate generation

openssl req \
  -config "${tests_dir}/root_ca.config" -batch \
  -x509 -new --newkey rsa:2048 -nodes \
  -keyout "${CA_DIR}/test-root-CA-key.pem" -sha256 -days 1024 -set_serial 1 \
  -extensions v3_ca \
  -out "${CA_DIR}/test-root-CA.pem"

openssl x509 -noout -in "${CA_DIR}/test-root-CA.pem"

## Signer leaf certificate generation

openssl req \
  -config "${tests_dir}/signer.config" \
  -new -newkey rsa:2048 -nodes \
  -reqexts req_exts \
  -keyout "${CA_DIR}/test-signer-0001-key.pem" \
  -out "${CA_DIR}/test-signer-0001-request.pem"

openssl req -text -noout \
  -in "${tmpdir}/test-signer-0001-request.pem"

openssl ca \
  -config "${tests_dir}/root_ca.config" -batch -notext \
  -keyfile "${CA_DIR}/test-root-CA-key.pem" \
  -in "${CA_DIR}/test-signer-0001-request.pem" \
  -days 365 -extensions usr_cert \
  -out "${CA_DIR}/test-signer-0001.pem"

openssl x509 -noout \
  -in "${tmpdir}/test-signer-0001.pem"

pkcs11-tool \
  --module "$module" \
  --write-object "${CA_DIR}/test-signer-0001-key.pem" \
  --type privkey \
  --id "$obj_id" \
  -p "$pin"

pkcs11-tool \
  --module "$module" \
  --write-object "${CA_DIR}/test-signer-0001.pem" \
  --type cert \
  --id "$obj_id" \
  -p "$pin"

# Test: Sign image with key from file system using CMS feature

swugenerator \
  -a "${tests_dir}/artifacts" \
  -s "${tests_dir}/sw-description" \
  -o "${tmpdir}/signed_with_cms_file_key.swu" \
  -k "CMS,${CA_DIR}/test-signer-0001-key.pem,${CA_DIR}/test-signer-0001.pem" \
  create

verify_image_cms "${tmpdir}/signed_with_cms_file_key.swu"

# Test: Sign image with key from HSM by PKCS#11 URI using CMS feature

swugenerator \
  -a "${tests_dir}/artifacts" \
  -s "${tests_dir}/sw-description" \
  -o "${tmpdir}/signed_with_cms_pkcs11_uri.swu" \
  -g pkcs11 \
  -f engine \
  -k "CMS,pkcs11:token=${token_name};id=%00%01;type=private&pin-source=${tmpdir}/pinfile,${CA_DIR}/test-signer-0001.pem" \
  create

verify_image_cms "${tmpdir}/signed_with_cms_pkcs11_uri.swu"

# Test: Sign image with key from softhsm using PKCS11 feature

swugenerator \
  -a "${tests_dir}/artifacts" \
  -s "${tests_dir}/sw-description" \
  -o "${tmpdir}/signed_with_pkcs11.swu" \
  -k "PKCS11,${pin},${module},${slot},${obj_id}" \
  create

verify_image_raw "${tmpdir}/signed_with_pkcs11.swu"
