#!/usr/bin/bash
#
# sb-sign-binary -- Signs UEFI binaries on Arch Linux
# Copyright (C) 2016 Antoine Damhet <antoine.damhet@lse.epita.fr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

getopt --test > /dev/null
if [[ $? != 4 ]]; then
	echo "I’m sorry, `getopt --test` failed in this environment."
	exit 1
fi

function usage {
	echo "Usage:" >&2
	echo -e "\t${0} [-d <dir>] [(--key <key>|--cert <cert>)] [-o <outfile>] [--config <config>] binary" >&2
	echo -e "\t${0} --key <key> --cert <cert> [-o <outfile>] [--config <config>] binary" >&2
	echo "" >&2
	echo "Wrapper of sbsign."
	echo "" >&2
	echo -e "  -d, --dir, --cert-dir\tThe directory containing the certificates. (defaults to /etc/efi-keys)" >&2
	echo -e "  -o, --output\t\tThe output binary (defaut the first binary." >&2
	echo -e "      --key\t\tThe key used to sign." >&2
	echo -e "      --cert\t\tThe certificate to use." >&2
	echo -e "  -h, --help\t\tPrints this help." >&2
	echo -e "      --config\t\tOverride the default configuration file."

	exit $1
}

SHORT=d:o:h
LONG=cert-dir:,dir:,key:,cert:,output:,help,config:

# -temporarily store output to be able to check for errors
# -activate advanced mode getopt quoting e.g. via “--options”
# -pass arguments only via   -- "$@"   to separate them correctly
PARSED=`getopt --options $SHORT --longoptions $LONG --name "$0" -- "$@"`
if [[ $? != 0 ]]; then
	# e.g. $? == 1
	#  then getopt has complained about wrong arguments to stdout
	exit 2
fi
# use eval with "$PARSED" to properly handle the quoting
eval set -- "$PARSED"

CONFIG="/etc/sbtools.conf"

# now enjoy the options in order and nicely split until we see --
while true; do
	case "$1" in
	-d|--cert-dir|--dir)
		options[keysdir]="$2"
		shift 2
		;;
	-o|--output)
		OUT="$2"
		shift 2
		;;
	--key)
		options[key]="$2"
		shift 2
		;;
	--cert)
		options[cert]="$2"
		shift 2
		;;
	-h|--help)
		usage 0
		;;
	--config)
		CONFIG="$2"
		shift 2
		;;
	--)
		shift
		break
		;;
	*)
		usage 3
		;;
	esac
done

for i in /usr/local/share/sbtools /usr/share/sbtools; do
	[ -e $i/loadconfig.sh ] && . $i/loadconfig.sh && break
done

if [ ! -f "$1" ]; then
	echo "No input file provided" >&2
	usage 2
fi

if [ ! -f "${options[key]}" ]; then
	if [ ! -d "${options[keysdir]}" ]; then
		echo "key or dir must be specified" >&2
		usage 1
	fi
	options[key]="${options[keysdir]}/DB.key"
fi

if [ ! -f "${options[cert]}" ]; then
	if [ ! -d "${options[keysdir]}" ]; then
		echo "key or dir must be specified" >&2
		usage 1
	fi
	options[cert]="${options[keysdir]}/DB.crt"
fi

if [ -z "$OUT" ]; then
	OUT="$1"
fi

if sbverify --cert "${options[cert]}" "$1" >/dev/null 2>&1; then
	echo "$1 was already signed."
	exit 0
fi

sbsign --key "${options[key]}" --cert "${options[cert]}" --output "${OUT}" "${1}"
