Skip to content

Instantly share code, notes, and snippets.

@ageis
Last active September 17, 2022 02:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ageis/e609053307b5cdaed48179e111a10d67 to your computer and use it in GitHub Desktop.
Save ageis/e609053307b5cdaed48179e111a10d67 to your computer and use it in GitHub Desktop.
Generate a GPG key suitable for an OpenPGP smartcard or YubiKey device (utilizing three slots and all four capabilities)
#!/bin/bash
# script generates a GPG master key with Certify+Sign capabilities, and two subkeys each possessing the Encrypt and Authenticate capabilities.
# intended to fill the 3 slots on a YubiKey <https://www.yubico.com/products/yubikey-hardware/> or OpenPGP card <https://g10code.com/p-card.html>
# allows selection of variables via a single dependency besides GnuPG 2.x: dialog
# kevin gallagher (@ageis) <kevingallagher@gmail.com>
function gen_smartcard_key() {
local GPG_KEY_ALGO="RSA"
local GPG_KEY_CREATION_DATE="$(date +%Y-%m-%d)"
if [[ -z "${GNUPGHOME}" ]]; then
exec 4>&1;
export GNUPGHOME=$(dialog --inputbox 'Confirm your GNUPGHOME:' 0 0 "${HOME}/.gnupg" 2>&1 1>&4)
exec 4>&-;
fi
echo -e "GNUPGHOME is ${GNUPGHOME}\n"
exec 5>&1;
local GPG_KEY_PASSWORD=$(dialog --passwordbox 'Password:' 0 0 2>&1 1>&5);
exec 5>&-;
exec 6>&1;
local GPG_KEY_NAME=$(dialog --inputbox 'Name:' 0 0 2>&1 1>&6);
exec 6>&-;
exec 7>&1;
local GPG_KEY_EMAIL=$(dialog --inputbox 'E-mail:' 0 0 2>&1 1>&7);
exec 7>&-;
exec 8>&1;
local GPG_KEY_EXPIRY=$(dialog --inputbox 'Expiry:' 0 0 '5y' 2>&1 1>&8);
exec 8>&-;
local DIALOG_RESULT=$(mktemp 2>/dev/null)
# trap "rm -f ${DIALOG_RESULT}" 0 1 2 5 15
local GPG_KEY_SIZE=$(whiptail --title "GPG key size" --radiolist "Choose:" 12 40 4 \
1 "1024" off \
2 "2048" off \
3 "3072" off \
4 "4096" on 3>&1 1>&2 2>&3)
case $(echo ${GPG_KEY_SIZE}) in
1) local GPG_KEY_LENGTH=1024;;
2) local GPG_KEY_LENGTH=2048;;
3) local GPG_KEY_LENGTH=3072;;
4) local GPG_KEY_LENGTH=4096;;
esac
echo -e "We'll generate a cert+sign primary key with the following parameters:\n"
echo -e "Key-Type: ${GPG_KEY_ALGO}\n"
echo -e "Key-Length: ${GPG_KEY_LENGTH}\n"
echo -e "Name-Real: ${GPG_KEY_NAME}\n"
echo -e "Name-Email: ${GPG_KEY_EMAIL}\n"
echo -e "Expire-Date: ${GPG_KEY_EXPIRY}\n"
echo -e "Passphrase: ${GPG_KEY_PASSWORD}\n"
echo -e "Creation-Date: ${GPG_KEY_CREATION_DATE}\n"
export GPG_PARAM_FILE="$(mktemp)"
export GPG_KEY_TEMP_ALIAS=$(basename "${GPG_PARAM_FILE}" | cut -d'.' -f2)
cat << EOF > "${GPG_PARAM_FILE}"
%echo Generating a GPG key...
Key-Type: ${GPG_KEY_ALGO}
Key-Length: ${GPG_KEY_LENGTH}
Key-Usage: cert,sign
Name-Real: ${GPG_KEY_NAME}
Name-Email: ${GPG_KEY_EMAIL}
Expire-Date: ${GPG_KEY_EXPIRY}
Creation-Date: ${GPG_KEY_CREATION_DATE}
Passphrase: ${GPG_KEY_PASSWORD}
%no-protection
%transient-key
%pubring ${GNUPGHOME}/${GPG_KEY_TEMP_ALIAS}.pub
%secring ${GNUPGHOME}/${GPG_KEY_TEMP_ALIAS}.sec
%commit
%echo Done
EOF
export GPG_FINGERPRINT=$(gpg --homedir "${GNUPGHOME}" --verbose --batch --status-fd=1 --generate-key "${GPG_PARAM_FILE}" | cut -d' ' -f4)
gpg --import "${GNUPGHOME}/${GPG_KEY_TEMP_ALIAS}.pub"
gpg --import "${GNUPGHOME}/.gnupg/private-keys-v1.d/${GPG_FINGERPRINT}.key"
for cap in encrypt auth; do
echo -e "Generating $cap key for ${GPG_FINGERPRINT}...\n"
gpg --homedir "${GNUPGHOME}" --verbose --batch --quick-add-key ${GPG_FINGERPRINT} ${GPG_KEY_ALGO}${GPG_KEY_LENGTH} $cap ${GPG_KEY_EXPIRY}
done
echo -e "Setting your new key to ultimately trusted...\n"
gpg --homedir "${GNUPGHOME}" --verbose --yes --list-keys --fingerprint --with-colons "${GPG_FINGERPRINT}" |
sed -E -n -e 's/^fpr:::::::::([0-9A-F]+):$/\1:6:/p' |
gpg --homedir "${GNUPGHOME}" --verbose --import-ownertrust --yes
}
@xslim
Copy link

xslim commented Oct 21, 2019

Are you using this in a Docker?
which docker image you are using and how do you connect yubikey to it?

@desnij
Copy link

desnij commented May 7, 2021

You should be able to use any image with gpg et al installed, but you would need to add -v /dev/bus/usb:/dev/bus/usb and maybe --privileged, or figure out which CAP you'd need

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment