#!/bin/sh #---help--- # Usage: efi-mkkeys -s [-b ] [-d ] [-e] [-o ] # efi-mkkeys [-h] [-V] # # Generate self-signed PK, KEK and db key for UEFI Secure Boot, including .esl # and .auth files, with a single command. # # Options: # -s Certificate subject; full DN or CN. If doesn't start # with "/", it will be rewritten to "/CN= (%s)/". # Placeholder "%s" will be replaced with the key type # (PK, KEK, or db). This option is required! # # -b RSA key size in bits; defaults to 2048. Change only if you know # that your system supports longer keys! # # -d Validity period in days for all keys; defaults to 3650 (10 y). # # -e Encrypt all private keys with AES-256-CBC using a single # pass phrase (you will be prompted for it). The keys will be # written to disk unencrypted for a short moment before ESLs are # signed and then they will be encrypted with the provided pass. # # -o Output directory; defaults to the current directory. # # -h Show this message and exit. # # -V Print the program version and exit. # # Please report bugs at . #---help--- set -eu if ( set -o pipefail 2>/dev/null ); then set -o pipefail fi PROGNAME='efi-mkkeys' VERSION='0.1.0' help() { sed -n '/^#---help---/,/^#---help---/p' "$0" | sed 's/^# \?//; 1d;$d;' } die() { printf "$PROGNAME: %s\n" "$@" >&2 exit 2 } # Defaults bits=2048 days=3650 encrypt=no outdir= passphrase= subj= while getopts ':b:d:eo:s:hV' OPT; do case "$OPT" in b) bits=$OPTARG;; d) days=$OPTARG;; e) encrypt=yes;; o) outdir=$OPTARG;; s) subj=$OPTARG;; h) help; exit 0;; V) echo "$PROGNAME $VERSION"; exit 0;; \?) die "unknown option: -$OPTARG (see '$0 -h)";; esac done shift $((OPTIND - 1)) [ $# -eq 0 ] || die "unexpected arguments: $* (see '$0 -h')" [ "$subj" ] || die 'missing required option: -s' case "$subj" in /*) ;; *) subj="/CN=$subj (%s)/";; esac if [ "$encrypt" = yes ]; then printf 'Enter PEM pass phrase for encrypting keys: ' # POSIX-compatible way to read password stty -echo trap 'stty echo' INT read -r passphrase stty echo printf '\n' [ "$passphrase" ] || die 'no pass phrase provided!' fi if [ "$outdir" ]; then mkdir -p "$outdir" cd "$outdir" fi guid=$(uuidgen) for name in PK KEK db; do openssl req -new -x509 \ -newkey "rsa:$bits" -nodes -keyout "$name.key" \ -subj "$(printf "$subj" "$name")" -days "$days" -sha256 -out "$name.crt" chmod 0600 *.key # this should be by default, just to be sure... # Some UEFI key managers require certificates in DER format. openssl x509 -in "$name.crt" -out "$name.cer" -outform DER cert-to-efi-sig-list -g "$guid" "$name.crt" "$name.esl" done timestamp=$(date +'%Y-%m-%d %H:%M:%S') sign-efi-sig-list -t "$timestamp" -k PK.key -c PK.crt PK PK.esl PK.auth >/dev/null sign-efi-sig-list -t "$timestamp" -a -k PK.key -c PK.crt KEK KEK.esl KEK.auth >/dev/null sign-efi-sig-list -t "$timestamp" -a -k KEK.key -c KEK.crt db db.esl db.auth >/dev/null [ "$encrypt" = yes ] && for name in PK KEK db; do printf '%s\n' "$passphrase" \ | openssl rsa -aes256 -passout stdin -in "$name.key" -out "$name.key.enc" mv "$name.key.enc" "$name.key" done cat <<'EOF' Done. TIP: Before modifying EFI variables, be sure to backup the current values: for var in PK KEK db dbx; do efi-readvar -v $var -o $var-orig.esl; done EOF