#!/usr/bin/sh
# SPDX-License-Identifier: MIT

die() {
  echo "${1}" >&2
  echo "Usage: ${0} <MOK crt> <PK crt> <PK key> <KEK crt> <KEK key> <OVMF vars file> <WORKDIR>" >&2
  exit 1
}

get_pem_crt() {
  _in="${1:-}"
  _out="${2-}"

  [ -n "${1}" ] || return 1
  [ -n "${2}" ] || return 1

  # Make sure the path to the destination file exists.
  _bd="$(dirname "${2}")" || return 1
  mkdir -p "${_bd}" || return 1

  # Try to obtain a PEM certificate in _out from _in.
  if openssl x509 -inform DER -in "${_in}" -noout -text 2>/dev/null >&2; then
    # Try to convert from DER -> PEM.
    openssl x509 -inform DER -in "${_in}" -outform PEM -out "${_out}"
    # Save the original cert, for reference/debugging.
    _outdir="$(dirname "${_out}")"
    cp -f "${_in}" "${_outdir}/"
  elif openssl x509 -inform PEM -in "${_in}" -noout -text 2>/dev/null >&2; then
    # Just copy the certificate, as it is already in PEM format.
    cp -f "${_in}" "${_out}"
  else
    die "The provided certificate (${_in}) is not a valid x509 PEM/DER certificate"
  fi

  # Now make sure _out is indeed a valid PEM certificate.
  openssl x509 -inform PEM -in "${_out}" \
    -noout -text 2>/dev/null >&2 \
    || die "Unable to get a PEM certificate from ${_in}"
}

get_libvirt_user() {
  if id "libvirt-qemu" >/dev/null 2>&1; then
    echo "libvirt-qemu"
  elif id "qemu" >/dev/null 2>&1; then
    echo "qemu"
  else
    echo "ERROR: No QEMU user found!" >&2
    exit 1
  fi
}

MOK="${1:-}"
PK_CRT="${2:-}"
PK_KEY_O="${3:-}"
KEK_CRT="${4:-}"
KEK_KEY_O="${5:-}"
VARSFILE_O="${6:-}"
WORKDIR="${7:-}"

[ -n "${MOK}" ] || die "Please, specify a MOK certificate as the first parameter to ${0}"
[ -e "${MOK}" ] || die "The indicated MOK certificate (${MOK}) does not exist"
[ -r "${PK_CRT}" ] || die "Unable to read Platform Key (PK) certificate at ${PK_CRT}"
[ -r "${PK_KEY_O}" ] || die "Unable to read Platform Key (PK) key at ${PK_KEY_O}"
[ -r "${KEK_CRT}" ] || die "Unable to read Key Exchange Key (KEK) certificate at ${KEK_CRT}"
[ -r "${KEK_KEY_O}" ] || die "Unable to read Key Exchange Key (KEK) key at ${KEK_KEY_O}"
[ -r "${VARSFILE_O}" ] || die "Unable to read OVMF variable files at ${VARSFILE_O}"

WORKDIR="$(realpath "${WORKDIR}")"
[ -d "${WORKDIR}" ] || die "WORKDIR (${WORKDIR}) does not exist or is not accessible"

SWD="${WORKDIR}/secureboot"
mkdir -p "${SWD}" || die "Unable to prepare secureboot dir within WORKDIR"

# PEM files.
MOK_PEM="${SWD}/MOK.pem"
PK_PEM="${SWD}/PK.pem"
PK_KEY="${SWD}/PK.key"
KEK_PEM="${SWD}/KEK.pem"
KEK_KEY="${SWD}/KEK.key"
VARS="${SWD}/ovmf-vars.fd"

# Prepare workdir with the required files.
# cert-to-efi-sig-list requires PEM format certificates as input, so we
# make sure to have them in the required format, with get_pem_crt().
get_pem_crt "${MOK}" "${MOK_PEM}" || die "Error while trying to obtain a PEM certificate for the MOK (${MOK})"
get_pem_crt "${PK_CRT}" "${PK_PEM}" || die "Error while trying to obtain a PEM certificate for the PK (${PK_CRT})"
get_pem_crt "${KEK_CRT}" "${KEK_PEM}" || die "Error while trying to obtain a PEM certificate for the KEK (${KEK_CRT})"
cp -f "${VARSFILE_O}" "${VARS}".original
cp -f "${VARSFILE_O}" "${VARS}"
cp -f "${PK_KEY_O}" "${PK_KEY}"
cp -f "${KEK_KEY_O}" "${KEK_KEY}"

CENTOS_PEM=/usr/share/10mt/secureboot/centos.crt
FEDORA_PEM=/usr/share/10mt/secureboot/fedora.crt
MICROSOFT_PEM=/usr/share/10mt/secureboot/microsoft-uefca2011-2011-06-27.crt

# Add PK cert to PK variable and sign it with PK itself.
10mt-ovmf-vars --add "${PK_PEM}" \
  --sign-cert "${PK_PEM}" --sign-key "${PK_KEY}" -f "${VARS}" -n PK
# Add KEK cert to KEK variable, and signit with PK also.
10mt-ovmf-vars --add "${KEK_PEM}" \
  --sign-cert "${PK_PEM}" --sign-key "${PK_KEY}" -f "${VARS}" -n KEK
# Add MS + distro certs to the db variable.
10mt-ovmf-vars --add "${FEDORA_PEM}" \
               --add "${CENTOS_PEM}" \
               --add "${MICROSOFT_PEM}" \
  -f "${VARS}" -n db

# Add MOK to MokList
10mt-ovmf-vars --add "${MOK_PEM}" -f "${VARS}" -n MokListRT

# Let's re-sign both db and dbx with the KEK.
#10mt-ovmf-vars --re-sign \
#  --sign-cert "${KEK_PEM}" --sign-key "${KEK_KEY}" -f "${VARS}" -n db
#10mt-ovmf-vars --re-sign \
#  --sign-cert "${KEK_PEM}" --sign-key "${KEK_KEY}" -f "${VARS}" -n dbx

# Let's convert it also to qcow2, which may be useful at some point.
qemu-img convert -f raw -O qcow2 "${VARS}" "${VARS}".qcow2

# We will have to set ownership + SELinux context.
LIBVIRT_USER="$(get_libvirt_user)"
SELINUX=
command -v restorecon >/dev/null && SELINUX=true

for _f in "${VARS}" "${VARS}".qcow2; do
  chown "${LIBVIRT_USER}": "${_f}"
  chmod 644 "${_f}"

  if [ -n "${SELINUX}" ]; then
    # Apply the correct context.
    chcon -t svirt_image_t "${_f}"
    # Make the context permanent after reboot.
    semanage fcontext -a -t svirt_image_t "$(realpath "${_f}")"
    restorecon -v "${_f}"
  fi

  # And save them to (re)use in the provisioning step.
  _bname="$(basename "${_f}")"
  cp -af "${_f}" "${SWD}/${_bname}".pre-installation
done

# vim:set ts=2 sw=2 et:
