--- /dev/null
+#!/bin/bash
+
+set -u
+set -e
+set -o pipefail
+
+if [ $# -lt 5 ]; then
+ echo "Usage: $0 filename version arch changes_file suite"
+ exit 1
+fi
+
+IN_TARBALL="$1" # Tarball to read, compressed with xz
+VERSION="$2"
+ARCH="$3"
+CHANGES="$4" # Changes file for the upload
+SUITE="$5"
+
+error() {
+ echo >&2 "E: $*"
+ exit 1
+}
+
+export OPENSSL_CONF=/dev/null
+
+# Read dak configuration for security or main archive
+case "$SUITE" in
+ *-security)
+ configdir="/srv/security-master.debian.org/dak/config/debian-security"
+ ;;
+ *)
+ configdir="/srv/ftp-master.debian.org/dak/config/debian"
+ ;;
+esac
+. "$configdir/vars"
+
+# Read and trivially validate our configuration
+. "$configdir/byhand-code-sign.conf"
+for var in EFI_BINARY_PRIVKEY EFI_BINARY_CERT \
+ LINUX_SIGNFILE LINUX_MODULE_PRIVKEY LINUX_MODULE_CERT; do
+ test -v $var || error "$var is not defined in configuration"
+ test -n "${!var}" || error "$var is empty in configuration"
+done
+
+TARGET="$ftpdir/dists/$SUITE/main/code-sign/"
+OUT_TARBALL="$TARGET/${IN_TARBALL##*/}"
+OUT_TARBALL="${OUT_TARBALL%.tar.xz}_sigs.tar.xz"
+
+# Check that this source/arch/version hasn't already been signed
+if [ -e "$OUT_TARBALL" ]; then
+ error "Signature tarball already exists: $OUT_TARBALL"
+fi
+
+# If we fail somewhere, cleanup the temporary directories
+IN_DIR=
+OUT_DIR=
+CERT_DIR=
+cleanup() {
+ for dir in "$IN_DIR" "$OUT_DIR" "$CERT_DIR"; do
+ test -z "$dir" || rm -rf "$dir"
+ done
+}
+trap cleanup EXIT
+
+# Extract the data into the input directory
+IN_DIR="$(mktemp -td byhand-code-sign-in.XXXXXX)"
+tar xaf "$IN_TARBALL" --directory="$IN_DIR"
+
+case "$EFI_BINARY_PRIVKEY" in
+ pkcs11:*)
+ # Translate from OpenSSL PKCS#11 enigne syntax to pesign parameters
+ # See: https://sources.debian.net/src/engine-pkcs11/0.2.2-1/src/engine_pkcs11.c
+ pkcs11_pin_value=
+ old_IFS="$IFS"
+ IFS=';'
+ for kv in ${EFI_BINARY_PRIVKEY#pkcs11:}; do
+ case "$kv" in
+ token=*)
+ pkcs11_token="${kv#*=}"
+ ;;
+ object=*)
+ pkcs11_object="${kv#*=}"
+ ;;
+ pin-value=*)
+ pkcs11_pin_value="${kv#*=}"
+ ;;
+ esac
+ done
+ IFS="$old_IFS"
+ unset old_IFS
+ # TODO: unlock it
+ PESIGN_PARAMS=(-t "$pkcs11_token" -c "$pkcs11_object")
+ ;;
+ *)
+ # Create certificate store for pesign
+ CERT_DIR="$(mktemp -td byhand-code-sign-cert.XXXXXX)"
+ chmod 700 "$CERT_DIR"
+ mkdir "$CERT_DIR/store"
+ certutil -N --empty-password -d "$CERT_DIR/store"
+ openssl pkcs12 -export \
+ -inkey "$EFI_BINARY_PRIVKEY" -in "$EFI_BINARY_CERT" \
+ -out "$CERT_DIR/efi-image.p12" -passout pass: \
+ -name efi-image
+ pk12util -i "$CERT_DIR/efi-image.p12" -d "$CERT_DIR/store" -K '' -W ''
+ PESIGN_PARAMS=(-n "$CERT_DIR/store" -c efi-image)
+ ;;
+esac
+
+# Create hierarchy of detached signatures in parallel to the uploaded files
+OUT_DIR="$(mktemp -td byhand-code-sign-out.XXXXXX)"
+while read filename; do
+ mkdir -p "$OUT_DIR/${filename%/*}"
+ case "${filename##*/}" in
+ *.efi | vmlinuz-*)
+ pesign -i "$IN_DIR/$filename" \
+ --export-signature "$OUT_DIR/$filename.sig" --sign \
+ -d sha256 "${PESIGN_PARAMS[@]}"
+ ;;
+ *.ko)
+ "$LINUX_SIGNFILE" -d sha256 "$LINUX_MODULE_PRIVKEY" \
+ "$LINUX_MODULE_CERT" "$IN_DIR/$filename"
+ mv "$IN_DIR/$filename.p7s" "$OUT_DIR/$filename.sig"
+ ;;
+ *)
+ echo >&2 "W: Not signing unrecognised file: $filename"
+ continue
+ ;;
+ esac
+ if [ ${#filename} -gt 60 ]; then
+ filename_trunc="...${filename:$((${#filename} - 57)):57}"
+ else
+ filename_trunc="$filename"
+ fi
+ printf 'I: Signed %-60s\r' "$filename_trunc"
+done < <(find "$IN_DIR" -type f -printf '%P\n')
+
+# Clear last progress message
+printf '%-70s\r' ''
+
+# Build tarball of signatures
+chmod -R a+rX "$OUT_DIR"
+mkdir -p "$TARGET"
+tar caf "$OUT_TARBALL" --directory="$OUT_DIR" .
+echo "I: Created $OUT_TARBALL"
+
+trap - EXIT
+cleanup
+
+exit 0