From 9cc55bf99db30be35f70e19058e4fe5dbdb17ede Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 27 Jun 2016 23:34:36 +0200 Subject: [PATCH] Add byhand script to perform code signing It takes a tarball of code objects and generates a tarball of corresponding detached PKCS#7 signatures (with '.sig' suffixes). It will sign: - EFI binaries (*.efi, vmlinuz-*) using pesign - Linux kernel modules (*.ko) using sign-file from linux-kbuild- Currently it should work with private key files and certificates. It may be able to sign kernel modules with a key on a PKCS#11 device. It definitely can't sign EFI binaries using a PKCS#11 device yet. --- scripts/debian/byhand-code-sign | 148 ++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100755 scripts/debian/byhand-code-sign diff --git a/scripts/debian/byhand-code-sign b/scripts/debian/byhand-code-sign new file mode 100755 index 00000000..8038813e --- /dev/null +++ b/scripts/debian/byhand-code-sign @@ -0,0 +1,148 @@ +#!/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 -- 2.39.5