#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
#
# Verify pesign signature on appropriate PE binaries
#
# Copyright (c) 2021 Vitaly Chikunov <vt@altlinux.org>.

set -efu
export LC_ALL=C
SBVERIFY=sbverify
declare -i good=0 bad=0

cleanup_tmpdir()
{
	rm -rf "$temp"
	exit $@
}
temp=$(mktemp -d)
trap 'cleanup_tmpdir $?' EXIT
trap 'exit 143' HUP INT QUIT PIPE TERM

cert=
convert_cert() {
	local cert_der=/etc/pki/uefi/altlinux.cer
	# C = RU, O = ALT Linux Team, OU = ALT Certification Authority, CN = ALT UEFI SB CA 2021

	if [ -z "$cert" ]; then
		cert=$temp/altlinux.pem
		openssl x509 -in $cert_der -inform der -out $cert
	fi
}

# White List from rpmrebuild-pesign pesign-change-files.sh
whitelisted() {
	case "$1" in
		/usr/lib64/efi/mmx64.efi|/usr/lib64/efi/mmia32.efi)
			return 0 ;;
		/usr/lib64/efi/fbx64.efi|/usr/lib64/efi/fbia32.efi)
			return 0 ;;
		/usr/lib64/efi/grubx64.efi|/usr/lib64/efi/grubia32.efi)
			return 0 ;;
		/usr/lib64/efi/fwupdx64.efi)
			return 0 ;;
		/boot/vmlinuz-*)
			return 0 ;;
		*)
			return 1 ;;
		esac
}

pesign_verify() {
	local force=$1
	local pefile=$2

	if [ "$force" = "no" ]; then
		if [ "$HOSTTYPE" != x86_64 ]; then
			echo "Warning: Architecture ($HOSTTYPE) does not support pesigning, skipping checks." >&2
			exit 0
		fi
		whitelisted "$pefile" || return 0
		objdump -rw "$pefile" 2>/dev/null | grep -q 'file format pei-\(x86-64\|i386\)' || return 0
	fi
	convert_cert
	echo "- Verifying $pefile"
	if $SBVERIFY --cert $cert "$pefile" 2>/dev/null; then
		good+=1
	else
		bad+=1
	fi
}

force=no
if [ "${1-}" = "-" ]; then
	# Reading from filetrigger.
	cat > $temp/pefiles.txt
elif [ -n "${1-}" ]; then
	if ! type $SBVERIFY >/dev/null 2>&1; then
		echo "Error: Architecture $HOSTTYPE does not support sbverify."
		exit 1
	fi
	for i; do
		echo "$i"
	done > $temp/pefiles.txt
	force=yes
else
	find /boot /usr/lib64/efi \
		-type f \( \
		-path '/boot/vmlinuz-*' -o \
		-path '/usr/lib64/efi/*.efi' -o \
		-path '/usr/lib/systemd/boot/efi/*.efi' \) > $temp/pefiles.txt 2>/dev/null ||:
fi

while read pefile; do
	pesign_verify "$force" "$pefile"
done < $temp/pefiles.txt

[ $good -eq 0 -a $bad -eq 0 ] && exit 0
echo >&2 "= PESIGN verification failures $bad, successes $good."
exit $((bad > 0))
