Skip to content

Instantly share code, notes, and snippets.

@arrjay
Last active January 27, 2016 05:23
Show Gist options
  • Save arrjay/646d9b32d7f44566588b to your computer and use it in GitHub Desktop.
Save arrjay/646d9b32d7f44566588b to your computer and use it in GitHub Desktop.
my dual-card gpg setup
My two-card, multiple encryption key GPG setup
==============================================
This document walks through setting up a GPG keyring that uses two smartcards to hold
two *different* authentication and encryption keys, linked to a single identity. This
keeps a master identity separate from either smart card, so if you need to revoke one
later, it is fairly easy to do. This document assumes you are working with an offline
computer, preferably one with it's own disk encryption setup.
First Steps
-----------
- Set up GPG - see included gpg.conf
- (Preference) I create a private git repo on the gpg-keying box to checkpoint operations
in case I need to revert one.
$ gpg -k
(should produce no keys output)
$ cd ~/.gnupg
$ cp [gpg.conf] gpg.conf
$ git init .
$ git add pubring.gpg secring.gpg trustdb.gpg
$ git commit -m "initial (blank keyrings)"
$ cd ~
Generate a GPG identity key
---------------------------
$ gpg --expert --gen-key
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection?
> Enter 8
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
> Enter S, E, Q (we only want the certify flag)
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
> Enter 4096
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
> Enter 3y
Key expires at [DATE] [TZ]
Is this correct? (y/N)
> Enter y
GnuPG needs to construct a user ID to identify your key.
Real name:
> Enter (Your Name)
Email address:
> Enter (an email address you use. you can add more later.)
Comment:
> Enter (LEAVE BLANK!)
You will now enter and verify a passphrase. You should probably write this down and store it
offline.
(Wait for gpg to gather entropy)
gpg: key 0xFF8383600C7C8D79 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at NNNN-NN-NN
pub 4096R/0xHHHHHHHHHHHHHHHH NNNN-NN-NN [expires: NNNN-NN-NN]
Key fingerprint = HHHH HHHH HHHH HHHH HHHH HHHH HHHH HHHH HHHH HHHH
uid [ultimate] (Your Name) <(Email)>
$ cd ~/.gnupg
$ git commit -a -m "created initial key"
Add additional email addresses
------------------------------
I prefer adding any additional emails before mucking with
$ gpg --edit-key (your email)
gpg> adduid
Real name:
> Enter (Your Name)
Email address:
> Enter (the email address you are adding)
Comment:
> Enter (LEAVE BLANK!)
You will now enter your passphrase to update the key.
gpg> save
$ cd ~/.gnupg
$ git commit -a -m "added identities"
A note about smartcards
-----------------------
Some of my smartcards can hold 4096-bit keys, and some can only hold 2048-bit keys. You can
only load a key of equal or lesser size into a smartcard - keep this in mind when generating
new subkeys!
Here's an easy way to check:
$ gpg --card-status|grep "Key attributes"
Key attributes ...: 2048R 2048R 2048R
$
The above card can only hold 2048-bit keys. A card which can hold 4096-bit keys will say 4096
in the attribute line. There are also some cards that hold 3072-bit keys, but I don't have one.
Generate Subkeys
----------------
I made 5 subkeys, but you can make as many as you want at this point. The tricky part is
only having one type flag per-key, for loading on to smart cards.
$ gpg --expert --edit-key (your email)
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection?
> 8
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
> E, Q (for a Signing key)
> S, Q (for an Encryption key)
> S, E, A, Q (for an Authtication key)
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
> (this answer is dependent on your car capabilities, see above!)
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
> (if you set an expiry on your main key, you will probably want this to expire sooner)
gpg>
[at this point, you can addkey until you have all your subkeys]
gpg> save
$ cd ~/.gnupg
$ git commit -a -m "added subkeys"
Generate master revocation
--------------------------
$ gpg --gen-revoke (your email) > master-key-revocation.asc
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
(Probably you want to select 1 here)
Your decision?
> (I actually use reason 2 here, since your master key should continue to be offline!)
Enter an optional description; end it with an empty line:
> (left it blank)
$
(Leave the file on the offline box - you only need it if you want to stop using your key)
Moving keys to multiple cards
-----------------------------
The easiest way to do this is export all your private keys, populate the first card, then
reimport all your private keys and populate the second card. Finally, remove all the
private keys and reintroduce the key stubs using gpg --card-status.
Initializing a Card
-------------------
$ gpg --card-edit
gpg/card> admin
gpg/card> lang
Language preferences: en
gpg/card> passwd
gpg: OpenPGP card no. NNNNNNNNNNN detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
(first enter the existing admin pin, then the new one + verify)
PIN changed.
Your selection? 1
(first enter the existing pin, then the new one + verify)
PIN changed.
Your selection? Q
gpg/card> quit
Moving a key to a card
----------------------
$ gpg --edit-key (your email)
gpg> toggle
gpg> key (key number to move, pick one at a time)
gpg> keytocard
(you are then asked for the card slot to store the key in. match the appropriate key type.)
(then enter the admin pin...)
gpg> key
gpg> key (some other slot)
gpg> keytocard
[...]
Generating a multi-card private keyring
---------------------------------------
After deleting all the private keys, import just the public key, then run gpg --card-status
with the first card inserted.
$ mkdir gpg-card1 gpg-card2 gpg-allcards
$ cd gpg-card1
$ gpg --card-status
$ gpg --export-secret-keys (your email) | gpgsplit -v
$ gpg --delete-secret-keys (your email)
(swap cards)
$ cd ../gpg-card2
$ gpg --card-status
$ gpg --export-secret-keys (your email) | gpgsplit -v
$ gpg --delete-secret-keys (your email)
$ cd ../gpg-allcards
Now, I don't have a great way of determining which subkeys you need for the keygrips.
I was able to work it out from the output of gpg -K while a card was loaded and pull in the
appropriate .secret_subkey files...
$ cp ../gpg-card1/* .
$ cp ../gpg-card2/000016*.secret_subkey .
$ cp ../gpg-card2/000014*.secret_subkey .
$ cat * | gpg --import
If you did this right, you should have ssb> for all your subkeys! If you're feeling bold,
you can export this private keyring to github! All it contains is the grips for smartcards.
Problems
--------
I replaced a card, and ssh consistently asked for the old card unlocking the auth key - easiest fix is to drop all your private keys (your entire .gnupg dir, really) and reimport the new stubs.
#
# This is an implementation of the Riseup OpenPGP Best Practices
# https://help.riseup.net/en/security/message-security/openpgp/best-practices
#
#-----------------------------
# behavior
#-----------------------------
# Disable inclusion of the version string in ASCII armored output
no-emit-version
# Disable comment string in clear text signatures and ASCII armored messages
no-comments
# Display long key IDs
keyid-format 0xlong
# List all keys (or the specified ones) along with their fingerprints
with-fingerprint
# Display the calculated validity of user IDs during key listings
list-options show-uid-validity
verify-options show-uid-validity
# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to
# the agent before it asks for a passphrase.
use-agent
#-----------------------------
# keyserver
#-----------------------------
# This is the server that --recv-keys, --send-keys, and --search-keys will
# communicate with to receive keys from, send keys to, and search for keys on
keyserver hkps://hkps.pool.sks-keyservers.net
# Provide a certificate store to override the system default
# Get this from https://sks-keyservers.net/sks-keyservers.netCA.pem
keyserver-options ca-cert-file=/usr/local/etc/ssl/certs/hkps.pool.sks-keyservers.net.pem
# Set the proxy to use for HTTP and HKP keyservers - default to the standard
# local Tor socks proxy
# It is encouraged to use Tor for improved anonymity. Preferrably use either a
# dedicated SOCKSPort for GnuPG and/or enable IsolateDestPort and
# IsolateDestAddr
#keyserver-options http-proxy=socks5-hostname://127.0.0.1:9050
# Don't leak DNS, see https://trac.torproject.org/projects/tor/ticket/2846
keyserver-options no-try-dns-srv
# When using --refresh-keys, if the key in question has a preferred keyserver
# URL, then disable use of that preferred keyserver to refresh the key from
keyserver-options no-honor-keyserver-url
# When searching for a key with --search-keys, include keys that are marked on
# the keyserver as revoked
keyserver-options include-revoked
#-----------------------------
# algorithm and ciphers
#-----------------------------
# list of personal digest preferences. When multiple digests are supported by
# all recipients, choose the strongest one
personal-cipher-preferences AES256 AES192 AES CAST5
# list of personal digest preferences. When multiple ciphers are supported by
# all recipients, choose the strongest one
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
# message digest algorithm used when signing a key
cert-digest-algo SHA512
# This preference list is used for new keys and becomes the default for
# "setpref" in the edit menu
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment