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:
        Skip the changelog file

/scripts/debian/byhand-code-sign-user
@@ -52,6 +52,10 @@ tar xJ --directory="$in_dir" <&0
 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-*)
---
 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

Reply via email to