GPG Key Management
Primary Key Strategy
Primary key should be used solely to sign subkeys grant and revoke access.
- daily subkeys
- create separate subkeys for Signing, Encryption and Authentication.
- cold storage
- export the primary key and save it securely offline; primary key should be removed from daily workstation.
GPG Usage
Generate a primary key
gpg --quick-generate-key "Carlos Augusto Lima Borges <gpg@carlosborges.dev>" ed25519 cert 2y
Generate subkeys
gpg --quick-add-key $KEY_ID ed25519 sign 1y gpg --quick-add-key $KEY_ID cv25519 encr 1y gpg --quick-add-key $KEY_ID ed25519 auth 1y
List public keys
gpg --list-keys --keyid-format LONG
List secret keys
gpg --list-secret-keys --keyid-format LONG
Backup keys
Exports live in a keys/ directory, the same layout the S server uses.
mkdir -p keys gpg --export --armor $KEY_ID > keys/public-key.asc gpg --export-secret-subkeys --armor $KEY_ID > keys/keys.asc gpg --export-secret-keys --armor $KEY_ID > keys/master-key.asc gpg --gen-revoke $KEY_ID > keys/revoke-certificate.asc gpg --symmetric --cipher-algo AES256 keys/keys.asc gpg --symmetric --cipher-algo AES256 keys/master-key.asc gpg --symmetric --cipher-algo AES256 keys/revoke-certificate.asc rm keys/keys.asc keys/master-key.asc keys/revoke-certificate.asc
- keys/public-key.asc
- public key; not secret, keep it unencrypted.
- keys/keys.asc.gpg
- secret subkeys only; restore this on daily workstations.
- keys/master-key.asc.gpg
- full secret key (primary + subkeys); cold storage only.
- keys/revoke-certificate.asc.gpg
- encrypted because anyone holding it can revoke the key.
Restore keys
Daily workstation (subkeys only)
GPG_TTY must be set (put it in ~/.zshrc) or pinentry fails inside pipes
with "Inappropriate ioctl for device".
export GPG_TTY=$(tty) gpg -d keys/keys.asc.gpg | gpg --import gpg --edit-key $KEY_ID gpg> trust # you should trust ultimately in this key gpg> quit gpg -K --keyid-format LONG # expect: sec# (primary offline), ssb (subkeys present)
Full restore (includes primary key)
export GPG_TTY=$(tty) gpg -d keys/master-key.asc.gpg | gpg --import gpg -K --keyid-format LONG # expect: sec (primary present)
Extend expiration
export GNUPGHOME=$(mktemp -d) gpg -d keys/master-key.asc.gpg | gpg --import # secret export also carries the public parts gpg --quick-set-expire $KEY_ID 2y # extend master key gpg --quick-set-expire $KEY_ID 1y "*" # extend all subkeys gpg --export --armor $KEY_ID > keys/public-key.asc rm -rf $GNUPGHOME unset GNUPGHOME gpg --import keys/public-key.asc gpg --keyserver hkps://keys.openpgp.org --send-keys $KEY_ID
Revoke a primary key
gpg -d keys/revoke-certificate.asc.gpg | gpg --import # or regenerate: gpg --gen-revoke <KEY_ID> gpg --keyserver hkps://keys.openpgp.org --send-keys $KEY_ID gpg --delete-secret-keys $KEY_ID gpg --delete-keys $KEY_ID
Revoke a subkey
gpg --edit-key gpg@carlosborges.dev
gpg> list
gpg> key <N>
gpg> revkey
gpg> save
gpg --keyserver hkps://keys.openpgp.org --send-keys $KEY_ID
Output symbols
- sec
- secret master key present on local system
- sec#
- secret master key is offline / stripped
- ssb
- secret subkey present
- pub
- public key
- sub
- public subkey
Keyserver
Use hkps://keys.openpgp.org to publish and search public keys.
Send your public key
gpg --keyserver hkps://keys.openpgp.org --send-keys $KEY_ID
Search public key
gpg --keyserver hkps://keys.openpgp.org --search-keys gpg@carlosborges.dev
Fetch a key
gpg --keyserver hkps://keys.openpgp.org --recv-keys $KEY_ID
Refresh keyring
gpg --refresh-keys
Integration
Import in git server
gpg --armor --export $KEY_ID