Skip to content

Instantly share code, notes, and snippets.

@bradfa
Last active March 16, 2024 22:46
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradfa/e73883a73f3a86e555fc43bf326edaa6 to your computer and use it in GitHub Desktop.
Save bradfa/e73883a73f3a86e555fc43bf326edaa6 to your computer and use it in GitHub Desktop.
PGP Bootable USB Flash Drive

PGP Bootable USB Flash Drive Creation and Operation

Create a bootable USB flash drive for generating and managing PGP keys. The keys will be generated and stored, encrypted, on the drive but then also transferred to Yubikeys for general use. Unless a Yubikey is lost or damaged, use of the flash drive should be extremely limited, if it is used at all.

A master certifying and signing (CS) key will be created, then sub-key signing (S), encrypting (E), and authenticating (A) keys will be created and signed by the C key. The C key will be archived with a password to the flash drive as well as transferred to a Yubikey 4. The SE&A sub keys will also be archived to the flash drive as part of the C key but then transferred to a daily-use Yubikey 5 NFC. The private key components will be printed on paper using a laser printer via paperkey.

The C key will have a life of 10 years. Each sub key will have a life of 2 years.

All keys will use my common UIDs of: andrew@bradfordembedded.com and bradfa@gmail.com

The flash drive, printed private keys, and Yubikey 4 will be stored in a safe place. They Yubikey 5 NFC will travel with me on my keychain.

Every time I generate new subkeys, it may be wise to reprint my private keys, but if I want to treat them as volatile then just having the ability to revoke them and generate new ones will be good enough.

The bootable flash drive will run Ubuntu 18.04 LTS server amd64. The root file system will be encrypted via LUKS using a password. Only packages required to perform the above activies will be installed and recorded, here.

Ubuntu 18.04 LTS Install Notes

Before installing, repartition the USB flash drive to use a GPT partition table, create a 200MB EFI system partition, create a 1GB Linux partition which will be /boot partition, and create the rest of the disk as a Linux partition. Then start the Ubuntu server installer and at the partitioning step, format the EFI system partition as such, format the /boot partition with ext4, and configure the last partition as a physical volume for encryption. Within the encrypted volume setup, configure a password to decrypt and create a single partition to be the root file system and format it with ext4.

After install is complete, perform an update, then install:

  • libykpers-1-1 (to get yubikey udev rules)
  • cups (so we can print)
  • paperkey (for easy printing for archival)

Exact Steps for Key Creation

First create a certifying and signing RSA-4096 keypair (this is not my actual key info, just a representation):

$ gpg --full-generate-key
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

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)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
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) 10y
Key expires at Sun 17 Feb 2030 02:08:51 PM EST
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Andrew Bradford
Email address: bradfa@gmail.com
Comment: 
You selected this USER-ID:
    "Andrew Bradford <bradfa@gmail.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 0CCE890A32249506 marked as ultimately trusted
gpg: directory '/home/andrew/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/andrew/.gnupg/openpgp-revocs.d/9E650DF1D57679A2EEC461620CCE890A32249506.rev'
public and secret key created and signed.

Note that this key cannot be used for encryption.  You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub   rsa4096 2020-02-20 [SC] [expires: 2030-02-17]
      9E650DF1D57679A2EEC461620CCE890A32249506
uid                      Andrew Bradford <bradfa@gmail.com>

Now create the (E) encrypting and (S) signing keys:

$ gpg --edit-key 9E650DF1D57679A2EEC461620CCE890A32249506
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2030-02-17
sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

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)
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
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) 2y
Key expires at Sat 19 Feb 2022 02:14:05 PM EST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

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)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
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) 2y
Key expires at Sat 19 Feb 2022 02:14:47 PM EST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
ssb  rsa4096/B240F62D893A7D1C
     created: 2020-02-20  expires: 2022-02-19  usage: S   
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

gpg> quit
Save changes? (y/N) y

Now finally create the (A) authentication key, using the expert mode:

$ gpg --expert --edit-key 9E650DF1D57679A2EEC461620CCE890A32249506
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
ssb  rsa4096/B240F62D893A7D1C
     created: 2020-02-20  expires: 2022-02-19  usage: S   
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

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)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
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? S

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Encrypt 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Authenticate 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
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) 2y
Key expires at Sat 19 Feb 2022 02:19:45 PM EST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
ssb  rsa4096/B240F62D893A7D1C
     created: 2020-02-20  expires: 2022-02-19  usage: S   
ssb  rsa4096/33EF6796E27F98C4
     created: 2020-02-20  expires: 2022-02-19  usage: A   
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

gpg> quit
Save changes? (y/N) y

Add my other email address to my keys. At the end of this it'll show the new UID as "unknown" trust level but once you save and exit gpg then the next time you start it it'll show as "ultimate" trust level as we expect:

$ gpg --edit-key 9E650DF1D57679A2EEC461620CCE890A32249506
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2030-02-17
sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
ssb  rsa4096/B240F62D893A7D1C
     created: 2020-02-20  expires: 2022-02-19  usage: S   
ssb  rsa4096/33EF6796E27F98C4
     created: 2020-02-20  expires: 2022-02-19  usage: A   
[ultimate] (1). Andrew Bradford <bradfa@gmail.com>

gpg> adduid
Real name: Andrew Bradford
Email address: andrew@bradfordembedded.com
Comment: 
You selected this USER-ID:
    "Andrew Bradford <andrew@bradfordembedded.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

sec  rsa4096/0CCE890A32249506
     created: 2020-02-20  expires: 2030-02-17  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/70324A9C2EBB90AE
     created: 2020-02-20  expires: 2022-02-19  usage: E   
ssb  rsa4096/B240F62D893A7D1C
     created: 2020-02-20  expires: 2022-02-19  usage: S   
ssb  rsa4096/33EF6796E27F98C4
     created: 2020-02-20  expires: 2022-02-19  usage: A   
[ultimate] (1)  Andrew Bradford <bradfa@gmail.com>
[ unknown] (2). Andrew Bradford <andrew@bradfordembedded.com>

gpg> q
Save changes? (y/N) y

Export the public keys to a file at ~/gpg-key.public and the secret keys to a file at ~/gpg-key.private so that when we transfer them to the Yubikeys (which by default deletes the local key) that we have a backup:

$ gpg --export --output ~/gpg-public.asc
$ gpg --export-secret-keys --output ~/gpg-private.asc

Verify that gpg still knows about our keys:

$ gpg --list-keys
gpg --list-keys
/home/bradfa/.gnupg/pubring.kbx
-------------------------------
pub   rsa4096 2020-10-17 [SC] [expires: 2030-10-15]
      B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
uid           [ultimate] Andrew Bradford <andrew@bradfordembedded.com>
uid           [ultimate] Andrew Bradford <bradfa@gmail.com>
sub   rsa4096 2020-10-17 [E] [expires: 2022-10-17]
sub   rsa4096 2020-10-17 [S] [expires: 2022-10-17]
sub   rsa4096 2020-10-17 [A] [expires: 2022-10-17]

Generate a revocation certificate text file, in case we ever need to revoke our certifying key in the future. Since you need access to the key to create the revocation cert, let's do it now:

$ gpg --output ~/gpg-revocation-cert.txt --gen-revoke B2B3A55CC4DCC1CD2624B82CBA3960057EF21997

sec  rsa4096/BA3960057EF21997 2020-10-17 Andrew Bradford <andrew@bradfordembedded.com>

Create a revocation certificate for this key? (y/N) y
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? 0
Enter an optional description; end it with an empty line:
> General revocation certificate.
> 
Reason for revocation: No reason specified
General revocation certificate.
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

You should now have 3 files in your home directory related to our current key work:

$ ls
gpg-private.asc  gpg-public.asc  gpg-revocation-cert.txt

Connect the Yubikey 4 and verify that gnupg can access it:

$ gpg --card-status
Reader ...........: 1050:0407:X:0
Application ID ...: <redacted>
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: <redacted>
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

Perform a factory reset of your Yubikey 4's OpenPGP applet:

$ gpg --card-edit

Reader ...........: 1050:0407:X:0
Application ID ...: <redacted>
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: <redacted>
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> admin
Admin commands are allowed

gpg/card> factory-reset
gpg: OpenPGP card no. <redacted> detected

gpg: Note: This command destroys all keys stored on the card!

Continue? (y/N) y
Really do a factory reset? (enter "yes") yes

gpg/card> quit

Set the Yubikey 4 admin and normal PIN since we do not want to use the default PIN of 123456 or the default Admin PIN of 12345678. You'll have to enter the current (default) admin and user PIN when prompted as well as double entries of the new PINs you're selecting:

$ gpg --card-edit

Reader ...........: 1050:0407:X:0
Application ID ...: <redacted>
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: <redacted>
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> admin
Admin commands are allowed

gpg/card> passwd
gpg: OpenPGP card no. <redacted> detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? Q

gpg/card> quit

If you want to require a code in order to return the Yubikey OpenPGP applet back to factory defaults in the future, also set a "Reset Code" but be warned that this is dangerous as you may lock yourself out of being able to use this Yubikey for OpenPGP uses in the future. I am not setting one.

Now, transfer your primary [CS] key to the Yubikey 4, enter the admin PIN you just created when prompted:

$ gpg --edit-key B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

sec  rsa4096/BA3960057EF21997
     created: 2020-10-17  expires: 2030-10-15  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C59A68A9AD2E836B
     created: 2020-10-17  expires: 2022-10-17  usage: E   
ssb  rsa4096/835D994D83AA7699
     created: 2020-10-17  expires: 2022-10-17  usage: S   
ssb  rsa4096/0BDC91EE02BEE34C
     created: 2020-10-17  expires: 2022-10-17  usage: A   
[ultimate] (1). Andrew Bradford <andrew@bradfordembedded.com>
[ultimate] (2)  Andrew Bradford <bradfa@gmail.com>

gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

sec  rsa4096/BA3960057EF21997
     created: 2020-10-17  expires: 2030-10-15  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa4096/C59A68A9AD2E836B
     created: 2020-10-17  expires: 2022-10-17  usage: E   
ssb  rsa4096/835D994D83AA7699
     created: 2020-10-17  expires: 2022-10-17  usage: S   
ssb  rsa4096/0BDC91EE02BEE34C
     created: 2020-10-17  expires: 2022-10-17  usage: A   
[ultimate] (1). Andrew Bradford <andrew@bradfordembedded.com>
[ultimate] (2)  Andrew Bradford <bradfa@gmail.com>

gpg> quit
Save changes? (y/N) y

Now when you have gnupg show you your keys, it'll say "pub" instead of "sec" for your primary key, since the key is no longer stored locally by gnupg, it's on your Yubikey 4 now:

$ gpg --list-keys
/home/bradfa/.gnupg/pubring.kbx
-------------------------------
pub   rsa4096 2020-10-17 [SC] [expires: 2030-10-15]
      B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
uid           [ultimate] Andrew Bradford <andrew@bradfordembedded.com>
uid           [ultimate] Andrew Bradford <bradfa@gmail.com>
sub   rsa4096 2020-10-17 [E] [expires: 2022-10-17]
sub   rsa4096 2020-10-17 [S] [expires: 2022-10-17]
sub   rsa4096 2020-10-17 [A] [expires: 2022-10-17]

You can show the keys on the Yubikey. It's a little confusing but the way gnupg shows the primary key is to also list all subkeys even though the subkeys aren't on the card. It's only the keys which have the > after their type which are actually on the card:

$ gpg --card-status
Reader ...........: 1050:0407:X:0
Application ID ...: <redacted>
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: <redacted>
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: B2B3 A55C C4DC C1CD 2624  B82C BA39 6005 7EF2 1997
      created ....: 2020-10-17 17:05:37
Encryption key....: [none]
Authentication key: [none]
General key info..: pub  rsa4096/BA3960057EF21997 2020-10-17 Andrew Bradford <andrew@bradfordembedded.com>
sec>  rsa4096/BA3960057EF21997  created: 2020-10-17  expires: 2030-10-15
                                card-no: 0006 07756688
ssb   rsa4096/C59A68A9AD2E836B  created: 2020-10-17  expires: 2022-10-17
ssb   rsa4096/835D994D83AA7699  created: 2020-10-17  expires: 2022-10-17
ssb   rsa4096/0BDC91EE02BEE34C  created: 2020-10-17  expires: 2022-10-17

You can verify that the 3 subkeys are still local by looking at the size and last modification time of the gnupg private key files, one key will be much smaller than the others now, that's the primary key which we've sent to the Yubikey:

$ ls .gnupg/private-keys-v1.d/ -l
total 16
-rw------- 1 bradfa bradfa 2072 Oct 17 13:09 5EDDEDFB5985D9E5A7DE91AF22D1E22024D3BD49.key
-rw------- 1 bradfa bradfa 2056 Oct 17 13:07 7A51300C1DE24F0223852BDE93C0F6EFAF395A86.key
-rw------- 1 bradfa bradfa  615 Oct 17 14:00 CD64AECB7DF245DB35A4D0A52E878498EBF49CD9.key
-rw------- 1 bradfa bradfa 2072 Oct 17 13:06 EC31B67E33245B2CCF1400D76DFD731259F986CF.key

Publish your primary key to a keyserver, such as https://pgp.mit.edu/. To get the ASCII armoured public key for uploading to the key server:

gpg --armour --export B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
<and you'll get a lot of output that you can copy-paste to the keyserver's UI>

The public key holds info about all your subkeys as well as any signatures you've received from others, so it can be kind of large. You can even embed a photo of yourself into it, although I'm not going to do that.

Don't be afraid to send your public key to lots of places, maybe multiple key servers. Just in case one of the keyservers dies, as your public key is not within your Yubikeys! Only the secret crypto parts of your keys are in the Yubikeys, any signatures you've received from others on your public key are not stored in the Yubikeys. You probably should have 1 main key server where you store your public key and then backups stored in other places, or on multiple machines, or whatnot. It's just annoying to update all of them if someone else signs your key or if you need to revoke a subkey and/or generate new subkeys.

Now you can set the Yubikey 4 OpenPGP card info on the card as you see fit, and set the "url" to be the address which you've uploaded your key to the keyserver, which the keyserver will tell you when you've successfully completed the upload:

$ gpg --card-edit

Reader ...........: 1050:0407:X:0
Application ID ...: <redacted>
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: <redacted>
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: B2B3 A55C C4DC C1CD 2624  B82C BA39 6005 7EF2 1997
      created ....: 2020-10-17 17:05:37
Encryption key....: [none]
Authentication key: [none]
General key info..: 
pub  rsa4096/BA3960057EF21997 2020-10-17 Andrew Bradford <andrew@bradfordembedded.com>
sec>  rsa4096/BA3960057EF21997  created: 2020-10-17  expires: 2030-10-15
                                card-no: 0006 07756688
ssb   rsa4096/C59A68A9AD2E836B  created: 2020-10-17  expires: 2022-10-17
ssb   rsa4096/835D994D83AA7699  created: 2020-10-17  expires: 2022-10-17
ssb   rsa4096/0BDC91EE02BEE34C  created: 2020-10-17  expires: 2022-10-17

gpg/card> admin
Admin commands are allowed

gpg/card> name
Cardholder's surname: Bradford
Cardholder's given name: Andrew

gpg/card> forcesig

gpg/card> url
URL to retrieve public key: https://pgp.mit.edu/pks/lookup?op=get&search=0xBA3960057EF21997

gpg/card> quit

Now we can repeat the process of setting up the Yubikey but with our Yubikey 5. Do the factory reset, set the admin and normal PIN, and then we're ready to "toggle" each of the subkeys using the "key" command within gpg --edit-key <keyid> (no arguments selects no keys, key 1 toggles selection of the first key, etc) and send each of the subkeys to the card.

Finally, you should be in a situation where gnupg knows about all of your keys (the primary, plus the 3 subkeys) but none are local to gnupg on disk any longer (except the backups we made).

Now you'll need to re-import the backed up keys, this way you'll have a USB flash drive which can do everything, a Yubikey 4 which can be used for key signings and other once-in-a-while tasks, and a Yubikey 5 that goes with you everywhere. If the flash drive dies, you still have a hard copy print out and the Yubikey 4 to perform all operations. If the Yubikey 4 dies, you can make a new one using the USB flash drive. If the Yubikey 5 dies, you can create a new one or revoke the keys and create new "daily use" keys from the flash drive and/or the Yubikey 4.

To make printable versions of our secret keys, use paperkey, like:

$ paperkey --secret-key gpg-private.asc | lpr

To reimport the keys we saved off, first delete gnupg's concept of them:

$ gpg --delete-secret-keys B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


sec  rsa4096/BA3960057EF21997 2020-10-17 Andrew Bradford <andrew@bradfordembedded.com>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

And now the public keys:

$ gpg --delete-keys B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


pub  rsa4096/BA3960057EF21997 2020-10-17 Andrew Bradford <andrew@bradfordembedded.com>

Delete this key from the keyring? (y/N) y

And now import our saved off private key:

$ gpg --import gpg-private.key
gpg: key BA3960057EF21997: public key "Andrew Bradford <andrew@bradfordembedded.com>" imported
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key BA3960057EF21997: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

And then mark the newly imported key as ultimately trusted:

$ gpg --edit-key B2B3A55CC4DCC1CD2624B82CBA3960057EF21997
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret subkeys are available.

pub  rsa4096/BA3960057EF21997
     created: 2020-10-17  expires: 2030-10-15  usage: SC  
     trust: unknown       validity: unknown
sub  rsa4096/C59A68A9AD2E836B
     created: 2020-10-17  expires: 2022-10-17  usage: E   
ssb  rsa4096/835D994D83AA7699
     created: 2020-10-17  expires: 2022-10-17  usage: S   
ssb  rsa4096/0BDC91EE02BEE34C
     created: 2020-10-17  expires: 2022-10-17  usage: A   
[ unknown] (1). Andrew Bradford <andrew@bradfordembedded.com>
[ unknown] (2)  Andrew Bradford <bradfa@gmail.com>

gpg> trust
pub  rsa4096/BA3960057EF21997
     created: 2020-10-17  expires: 2030-10-15  usage: SC  
     trust: unknown       validity: unknown
sub  rsa4096/C59A68A9AD2E836B
     created: 2020-10-17  expires: 2022-10-17  usage: E   
ssb  rsa4096/835D994D83AA7699
     created: 2020-10-17  expires: 2022-10-17  usage: S   
ssb  rsa4096/0BDC91EE02BEE34C
     created: 2020-10-17  expires: 2022-10-17  usage: A   
[ unknown] (1). Andrew Bradford <andrew@bradfordembedded.com>
[ unknown] (2)  Andrew Bradford <bradfa@gmail.com>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

pub  rsa4096/BA3960057EF21997
     created: 2020-10-17  expires: 2030-10-15  usage: SC  
     trust: ultimate      validity: unknown
sub  rsa4096/C59A68A9AD2E836B
     created: 2020-10-17  expires: 2022-10-17  usage: E   
ssb  rsa4096/835D994D83AA7699
     created: 2020-10-17  expires: 2022-10-17  usage: S   
ssb  rsa4096/0BDC91EE02BEE34C
     created: 2020-10-17  expires: 2022-10-17  usage: A   
[ unknown] (1). Andrew Bradford <andrew@bradfordembedded.com>
[ unknown] (2)  Andrew Bradford <bradfa@gmail.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> quit
@bradfa
Copy link
Author

bradfa commented Oct 17, 2020

TODO: Make sure all the example keys match as this has been written over a year's time across multiple different systems using fake demonstration keys.

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