Last active
October 28, 2021 07:00
-
-
Save o0-o/61e11c9928fd7698f1aaae55473e6456 to your computer and use it in GitHub Desktop.
Unattended/Automated GPG Key Scripts for Yubikey
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
# Run this on an air-gapped computer with an encrypted hard drive to set up GPG keys on your yubikey. | |
# Derived from https://github.com/drduh/YubiKey-Guide | |
# Assumes OS has already been prepared (packages, services, etc) -- see dr duh guide. | |
# Does not configure PINs on the yubikey. If no admin pin is provided, the default 12345678 is used. | |
# | |
# Usage: gpg_add_yubi.sh gpg-backup.tar.gz gpg_passhrase [yubikey_admin_pin] | |
######################################################################## | |
# Safety and portability | |
set -eu | |
set -o posix || true #notably dash doesn't support this | |
set -o pipefail || true #not technically posix but widely supported | |
# Define key and yubi parameters | |
export GNUPGHOME="$(mktemp -d)" | |
chmod 0700 "$GNUPGHOME" | |
backup="$1" | |
passphrase="$2" | |
puk="${3-12345678}" | |
key_type="rsa2048" | |
cd "$GNUPGHOME" | |
# Restore backup | |
tar -xzf "${backup}" | |
fpr="$(gpg --list-options 'show-only-fpr-mbox' --list-secret-keys | awk '{print $1}')" | |
# Issue superfluous admin command on the yubi so that it won't prompt | |
# for the admin pin on the next command | |
printf '%s\n' \ | |
'admin' \ | |
'lang' \ | |
'en' \ | |
'q' | | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$puk" \ | |
--command-fd 0 \ | |
--edit-card | |
# Copy keys to the yubi | |
printf '%s\n' \ | |
'key 1' \ | |
'keytocard' \ | |
'1' \ | |
'y' \ | |
'key 1' \ | |
'key 2' \ | |
'keytocard' \ | |
'2' \ | |
'y' \ | |
'key 2' \ | |
'key 3' \ | |
'keytocard' \ | |
'3' \ | |
'y' \ | |
'save' | | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--edit-key "$fpr" | |
# Print gpg key and yubi details | |
gpg --card-status | |
gpg -K | |
gpg --delete-secret-key | |
cd | |
rm -rf "$GNUPGHOME" | |
echo 'Reboot soon and before restoring network connectivity.' 1>&2 | |
# Just cause | |
unset fpr GNUPGHOME passphrase | |
# vim: ts=8:sw=8:sts=8:noet:ft=sh |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
# Run this on an air-gapped computer with an encrypted hard drive to set up GPG keys on your yubikey. | |
# Derived from https://github.com/drduh/YubiKey-Guide | |
# Assumes OS has already been prepared (packages, services, etc) -- see dr duh guide. | |
# Does not configure PINs on the yubikey. If no admin pin is provided, the default 12345678 is used. | |
# Some older Yubikeys do not support rsa4096. Change key_type to rsa2048. | |
# The GPG key passphrase is randomly generated and printed to stderr at the end of the script. | |
# Copy the backup tar.gz file to an encrypted drive. | |
# | |
# Usage: gpg_gen_yubi.sh name email [yubikey_admin_pin] | |
######################################################################## | |
# Safety and portability | |
set -eu | |
set -o posix || true #notably dash doesn't support this | |
set -o pipefail || true #not technically posix but widely supported | |
# Backup targets -- set these or the master key will be deleted permanently | |
crypt1='/mnt/crypt1' #entire GNUPGHOME directory is backed up to $crypt1 and $crypt2 | |
crypt2='/mnt/crypt2' | |
pub1='/mnt/pub1' #public and revocation keys are copied to $pub1 and $pub2 | |
pub2='/mnt/pub2' | |
# Define key and yubi parameters | |
export GNUPGHOME="$(mktemp -d)" | |
chmod 0700 "$GNUPGHOME" | |
name="$1" | |
email="$2" | |
passphrase="$( dd if=/dev/urandom bs=1k count=1 2>/dev/null | | |
LC_ALL=C tr -dc '\41\43-\46\60-\71\74-\132' | | |
cut -c 1-24 )" | |
puk="${3-12345678}" | |
key_type="rsa4096" | |
subkey_expire='2y' | |
cd "$GNUPGHOME" | |
# Configure gpg based on dr duh guide | |
printf '%s\n' \ | |
'personal-cipher-preferences AES256 AES192 AES' \ | |
'personal-digest-preferences SHA512 SHA384 SHA256' \ | |
'personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed' \ | |
'default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed' \ | |
'cert-digest-algo SHA512' \ | |
's2k-digest-algo SHA512' \ | |
's2k-cipher-algo AES256' \ | |
'charset utf-8' \ | |
'fixed-list-mode' \ | |
'no-comments' \ | |
'no-emit-version' \ | |
'keyid-format 0xlong' \ | |
'list-options show-uid-validity' \ | |
'verify-options show-uid-validity' \ | |
'with-fingerprint' \ | |
'require-cross-certification' \ | |
'no-symkey-cache' \ | |
'use-agent' \ | |
'throw-keyids' \ | |
>'gpg.conf' | |
chmod 0600 'gpg.conf' | |
# Unattended key generation | |
gpg --batch \ | |
--passphrase "$passphrase" \ | |
--quick-gen-key "${name} <${email}>" \ | |
"$key_type" \ | |
'cert' \ | |
'0' | |
fpr="$(gpg --list-options 'show-only-fpr-mbox' --list-secret-keys | awk '{print $1}')" | |
gpg --batch \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--quick-add-key "$fpr" \ | |
"$key_type" \ | |
'sign' \ | |
"$subkey_expire" | |
gpg --batch \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--quick-add-key "$fpr" \ | |
"$key_type" \ | |
'encrypt' \ | |
"$subkey_expire" | |
gpg --batch \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--quick-add-key "$fpr" \ | |
"$key_type" \ | |
'auth' \ | |
"$subkey_expire" | |
# Exports | |
printf '%s\n' \ | |
'y' \ | |
'0' \ | |
'This revocation certificate was created pre-emptively' \ | |
'' \ | |
'y' \ | |
'y' | | |
gpg --output "revoke-no-reason-$fpr.asc" \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--gen-revoke "$fpr" | |
printf '%s\n' \ | |
'y' \ | |
'1' \ | |
'This revocation certificate was created pre-emptively' \ | |
'' \ | |
'y' \ | |
'y' | | |
gpg --output "revoke-compromised-$fpr.asc" \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--gen-revoke "$fpr" | |
printf '%s\n' \ | |
'y' \ | |
'2' \ | |
'This revocation certificate was created pre-emptively' \ | |
'' \ | |
'y' \ | |
'y' | | |
gpg --output "revoke-superseded-$fpr.asc" \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--gen-revoke "$fpr" | |
printf '%s\n' \ | |
'y' \ | |
'3' \ | |
'This revocation certificate was created pre-emptively' \ | |
'' \ | |
'y' \ | |
'y' | | |
gpg --output "revoke-no-longer-used-$fpr.asc" \ | |
--pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--gen-revoke "$fpr" | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--armor \ | |
--export-secret-keys "$fpr" \ | |
>'master.key' | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--armor \ | |
--export-secret-subkeys "$fpr" \ | |
>'sub.key' | |
gpg --armor \ | |
--export "$fpr" \ | |
>"gpg-${fpr}-$(date +%F).asc" | |
# Copy public key to unencrypted store | |
for pub_key in "gpg-${fpr}-"*".asc"; do | |
cp "$pub_key" "${pub1-/dev/null}" | |
cp "$pub_key" "${pub2-/dev/null}" | |
done | |
# Copy revocation certificates to unencrypted store | |
for rev_cert in "revoke-"*"-${fpr}.asc"; do | |
cp "$rev_cert" "${pub1-/dev/null}" | |
cp "$rev_cert" "${pub2-/dev/null}" | |
done | |
# Must back up to encrypted store before copying to yubi | |
tar -czf "backup-$(date +%F).tar.gz" * | |
cp "backup-"*".tar.gz" "${crypt1-/dev/null}" | |
cp "backup-"*".tar.gz" "${crypt2-/dev/null}" | |
# Issue superfluous admin command on the yubi so that it won't prompt | |
# for the admin pin on the next command | |
printf '%s\n' \ | |
'admin' \ | |
'lang' \ | |
'en' \ | |
'q' | | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$puk" \ | |
--command-fd 0 \ | |
--edit-card | |
# Copy keys to the yubi | |
printf '%s\n' \ | |
'key 1' \ | |
'keytocard' \ | |
'1' \ | |
'y' \ | |
'key 1' \ | |
'key 2' \ | |
'keytocard' \ | |
'2' \ | |
'y' \ | |
'key 2' \ | |
'key 3' \ | |
'keytocard' \ | |
'3' \ | |
'y' \ | |
'save' | | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--edit-key "$fpr" | |
# Print gpg key and yubi details | |
gpg --card-status | |
gpg -K | |
gpg --delete-secret-key | |
cd | |
rm -rf "$GNUPGHOME" | |
printf '%s\n' \ | |
'WRITE THIS DOWN IN A SECURE PLACE' "$passphrase" \ | |
'Reboot soon and before restoring network connectivity.' 1>&2 | |
# Just cause | |
unset fpr GNUPGHOME passphrase | |
# vim: ts=8:sw=8:sts=8:noet:ft=sh |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
# Run this on an air-gapped computer with an encrypted hard drive to set up GPG keys on your yubikey. | |
# Derived from https://github.com/drduh/YubiKey-Guide | |
# Assumes OS has already been prepared (packages, services, etc) -- see dr duh guide. | |
# Does not configure PINs on the yubikey. If no admin pin is provided, the default 12345678 is used. | |
# | |
# Usage: gpg_renew_yubi.sh gpg-backup.tar.gz gpg_passhrase | |
######################################################################## | |
# Safety and portability | |
set -eu | |
set -o posix || true #notably dash doesn't support this | |
set -o pipefail || true #not technically posix but widely supported | |
# Define key and yubi parameters | |
export GNUPGHOME="$(mktemp -d)" | |
chmod 0700 "$GNUPGHOME" | |
backup="$1" | |
passphrase="$2" | |
subkey_expire='2y' | |
cd "$GNUPGHOME" | |
# Backup targets | |
#crypt1='/mnt/crypt1' | |
#crypt2='/mnt/crypt2' | |
#pub1='/mnt/pub1' | |
#pub2='/mnt/pub2' | |
# Restore backup | |
tar -xzf "${backup}" | |
fpr="$(gpg --list-options 'show-only-fpr-mbox' --list-secret-keys | awk '{print $1}')" | |
# Renew keys | |
printf '%s\n' \ | |
'key 1' \ | |
'expire' \ | |
"$subkey_expire" \ | |
'key 1' \ | |
'key 2' \ | |
'expire' \ | |
"$subkey_expire" \ | |
'key 2' \ | |
'key 3' \ | |
'expire' \ | |
"$subkey_expire" \ | |
'save' | | |
gpg --pinentry-mode 'loopback' \ | |
--passphrase "$passphrase" \ | |
--command-fd 0 \ | |
--edit-key "$fpr" | |
# Export new public key | |
gpg --armor \ | |
--export "$fpr" \ | |
>"gpg-${fpr}-$(date +%F).asc" | |
# Copy public key to unencrypted store | |
: rm "gpg-${fpr}-"*'.asc' | |
: cp "gpg-${fpr}-"*'.asc' "${pub1-/dev/null}" | |
: cp "gpg-${fpr}-"*'.asc' "${pub2-/dev/null}" | |
gpg --import "gpg-${fpr}-"*'.asc' | |
# Must back up to encrypted store before copying to yubi | |
: rm 'backup-'*'.tar.gz' | |
tar -czf "backup-$(date +%F).tar.gz" * | |
: cp 'backup-'*'.tar.gz' "${crypt1-/dev/null}" | |
: cp 'backup-'*'.tar.gz' "${crypt2-/dev/null}" | |
gpg --import "gpg-${fpr}-"*'.asc' | |
# Print gpg key and yubi details | |
gpg --card-status | |
gpg -K | |
gpg --delete-secret-key | |
cd | |
rm -rf "$GNUPGHOME" | |
echo 'Reboot soon and before restoring network connectivity.' 1>&2 | |
# Just cause | |
unset fpr GNUPGHOME passphrase | |
# vim: ts=8:sw=8:sts=8:noet:ft=sh |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment