The byhand-code-sign-user script receives a .tar.xz file (that can contain efi images and linux modules) in stdin, sign them using keys as configured in the configuration file and generate a .tar.xz with all the signatures in stdout
This script is meant to be called by another byhand script which will run it as a different user. stdin and stdout is used for passing the .tar.xz files as this script may not have permission to access the .tar.xz It can sign using a token as a Yubikey or through a certificate database depending on the configuration Contributions: Julien Cristau <jcris...@debian.org> Ben Hutchings <b...@decadent.org.uk> --- This patch series is based on https://ftp-master.debian.org/git/dak.git master Patches are also available here: https://github.com/helen-fornazier/dak/tree/review TESTS ----- I tested the byhan-code-sign-user using the script here: https://github.com/helen-fornazier/dak-codesign-test/blob/master/dak-codesign-test.sh That covers with and without an Yubikey and creating a privkey with or without a password To execute it, create a test.tar.xz files with efi and linux modules, install gnutls-bin, yubico-piv-tool, libnss3-tools and run ./dak-codesign-test.sh test.tar.xz It should work with a yubikey with default configuration (key and pin code), otherwise you will need to adjust those parameters in the script. Changes from last version: None --- config/debian-security/byhand-code-sign.conf | 43 +++++++++++ config/debian/byhand-code-sign.conf | 43 +++++++++++ scripts/debian/byhand-code-sign-user | 103 +++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 config/debian-security/byhand-code-sign.conf create mode 100644 config/debian/byhand-code-sign.conf create mode 100755 scripts/debian/byhand-code-sign-user diff --git a/config/debian-security/byhand-code-sign.conf b/config/debian-security/byhand-code-sign.conf new file mode 100644 index 0000000..7818b8d --- /dev/null +++ b/config/debian-security/byhand-code-sign.conf @@ -0,0 +1,43 @@ +# Configuration for byhand-sign shell script + +# The directory of the certificate database created with certutil +# where the certificate and possibly the private key (if a token +# is not used) for signing efi images are stored +#EFI_CERT_DIR=/etc/dak/efi/certdir +EFI_CERT_DIR= + +# The name that identifies the certificate in the certificate +# database or in the token. +# Yubikey is usually "Certificate for Digital Signature" +# The label can be verified by executing: +# pkcs11-tool --module=/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so -O +EFI_CERT_NAME="Certificate for Digital Signature" + +# The label of the token as shown in `p11tool --list-tokens` +# Set to "NSS Certificate DB" if the private key is in the certificate +# database and a token will not be used +#EFI_TOKEN_NAME="NSS Certificate DB" +EFI_TOKEN_NAME="PIV_II (PIV Card Holder pin)" + +# The token pin or the certificate database slot password (if a +# token is not used) for signing efi images. This is optional in +# case a token is not used and no slot password is set +#EFI_SIGN_PIN=123456 + +# The sign-file linux program to sign modules +#LINUX_SIGNFILE=/usr/lib/linux-kbuild-4.6/scripts/sign-file +LINUX_SIGNFILE= + +# The private key to use to sign the kernel modules or the token URI +# as shown by `p11tool --list-tokens` +#LINUX_MODULES_PRIVKEY=/etc/dak/efi/kernel-key.rsa +LINUX_MODULES_PRIVKEY="pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=00000000;token=PIV_II%20%28PIV%20Card%20Holder%20pin%29" + +# The certificate to verify the kernel modules signature +#LINUX_MODULES_CERT=/etc/dat/efi/kernel-cert.pem +LINUX_MODULES_CERT= + +# The token pin or the certificate database slot password (if a +# token is not used) for signing kernel modules. This is optional in +# case no slot password is set +#LINUX_SIGN_PIN=123456 diff --git a/config/debian/byhand-code-sign.conf b/config/debian/byhand-code-sign.conf new file mode 100644 index 0000000..7818b8d --- /dev/null +++ b/config/debian/byhand-code-sign.conf @@ -0,0 +1,43 @@ +# Configuration for byhand-sign shell script + +# The directory of the certificate database created with certutil +# where the certificate and possibly the private key (if a token +# is not used) for signing efi images are stored +#EFI_CERT_DIR=/etc/dak/efi/certdir +EFI_CERT_DIR= + +# The name that identifies the certificate in the certificate +# database or in the token. +# Yubikey is usually "Certificate for Digital Signature" +# The label can be verified by executing: +# pkcs11-tool --module=/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so -O +EFI_CERT_NAME="Certificate for Digital Signature" + +# The label of the token as shown in `p11tool --list-tokens` +# Set to "NSS Certificate DB" if the private key is in the certificate +# database and a token will not be used +#EFI_TOKEN_NAME="NSS Certificate DB" +EFI_TOKEN_NAME="PIV_II (PIV Card Holder pin)" + +# The token pin or the certificate database slot password (if a +# token is not used) for signing efi images. This is optional in +# case a token is not used and no slot password is set +#EFI_SIGN_PIN=123456 + +# The sign-file linux program to sign modules +#LINUX_SIGNFILE=/usr/lib/linux-kbuild-4.6/scripts/sign-file +LINUX_SIGNFILE= + +# The private key to use to sign the kernel modules or the token URI +# as shown by `p11tool --list-tokens` +#LINUX_MODULES_PRIVKEY=/etc/dak/efi/kernel-key.rsa +LINUX_MODULES_PRIVKEY="pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=00000000;token=PIV_II%20%28PIV%20Card%20Holder%20pin%29" + +# The certificate to verify the kernel modules signature +#LINUX_MODULES_CERT=/etc/dat/efi/kernel-cert.pem +LINUX_MODULES_CERT= + +# The token pin or the certificate database slot password (if a +# token is not used) for signing kernel modules. This is optional in +# case no slot password is set +#LINUX_SIGN_PIN=123456 diff --git a/scripts/debian/byhand-code-sign-user b/scripts/debian/byhand-code-sign-user new file mode 100755 index 0000000..3477d6c --- /dev/null +++ b/scripts/debian/byhand-code-sign-user @@ -0,0 +1,103 @@ +#!/bin/bash + +set -u +set -e +set -o pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 config_file" + exit 1 +fi + +# This script receives a .tar.xz file from stdin and generates a .tar.xz in stdout +# Prevent any possible output to stdout, redirect them to stderr instead +# Save STDOUT in fd_stdout +exec {fd_stdout}>&1 +# Redirect STDOUT to STDERR +exec 1>&2 + +config_file="$1" + +error() { + echo >&2 "E: $*" + exit 1 +} + +# Read and trivially validate our configuration +. "$config_file" +for var in EFI_CERT_DIR EFI_CERT_NAME EFI_TOKEN_NAME \ + LINUX_SIGNFILE LINUX_MODULES_PRIVKEY LINUX_MODULES_CERT; do + test -v "$var" || error "$var is not defined in configuration" + test -n "${!var}" || error "$var is empty in configuration" +done +# these variables are optional, set it to empty string to avoid unbound variable error +EFI_SIGN_PIN=${EFI_SIGN_PIN-''} +LINUX_SIGN_PIN=${LINUX_SIGN_PIN-''} + +# If we fail somewhere, cleanup the temporary directories +in_dir= +out_dir= +cleanup() { + for dir in "$in_dir" "$out_dir" ; do + test -z "$dir" || rm -rf "$dir" + done +} +trap cleanup EXIT + +# Extract the data from stdin into the input directory +in_dir="$(mktemp -td byhand-code-sign-in.XXXXXX)" +tar xJ --directory="$in_dir" <&0 + +# Create hierarchy of detached signatures in parallel to the uploaded files +out_dir="$(mktemp -td byhand-code-sign-out.XXXXXX)" + +while read filename; do + # Skip changelog + if [ "$filename" == changelog ]; then + continue + fi + mkdir -p "$out_dir/${filename%/*}" + case "${filename##*/}" in + *.efi | vmlinuz-*) + expect <<- EOF + log_user 0 + spawn pesign -i "${in_dir}/${filename}" --export-signature "${out_dir}/${filename}.sig" \ + --sign -d sha256 -n "${EFI_CERT_DIR}" -c "${EFI_CERT_NAME}" -t "${EFI_TOKEN_NAME}" + expect { + "Enter Password *:" {send "${EFI_SIGN_PIN}\r"; exp_continue} + "Enter passphrase *:" {send "${EFI_SIGN_PIN}\r"; exp_continue} + timeout {exit 1} + eof + } + lassign [wait] wait_pid spawn_id exec_rc wait_code + if {\$exec_rc != 0} {exit 1} + exit \$wait_code + EOF + ;; + *.ko) + KBUILD_SIGN_PIN="$LINUX_SIGN_PIN" "$LINUX_SIGNFILE" -d sha256 "$LINUX_MODULES_PRIVKEY" \ + "$LINUX_MODULES_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' '' + +# Restore STDOUT from fd_stdout +exec 1>&"$fd_stdout" + +# Build tarball of signatures +chmod -R a+rX "$out_dir" +tar -cJf - --directory="$out_dir" . -- 2.7.4