Skip to content

Instantly share code, notes, and snippets.

@serac
Last active January 29, 2019 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save serac/92da7e4871f4e12e1363c274860b75c6 to your computer and use it in GitHub Desktop.
Save serac/92da7e4871f4e12e1363c274860b75c6 to your computer and use it in GitHub Desktop.
Secure and Sane PGP for the Long Term

Secure and Sane PGP for the Long Term

Use the method described here if you would like most of the following benefits:

  1. Establish provenance of exactly one public key on the Internet over time (years typically).
  2. Use multiple keys daily without exposing the secret key corresponding to your published public key.
  3. Facilitate key creation and revocation.

While provenance isn't necessary for many folks, it's useful if not essential if you publish software artifacts on the Internet or issue public statements like security announcements. You establish provenance by accumulating digital signatures on your published key by other keys that are perceived to be trusted. By keeping your public key offline for daily use, you limit exposure of the key that certifies the keys you use for day-to-day use. If a subkey is lost or compromised, you simply revoke it and issue a new one that is published under your public key; there is no impact to the public key on which you have painstakingly accumulated trust.

The Debian Wiki has more to say on the benefits of using multiple subkeys for daily use.

Summary

  1. Establish a secure computing environment in which to generate and manage keys. While the details of this step are out of scope, it's vitally important for adequate security. How secure is secure depends on your needs and capabilities.
  2. Establish a removable, encrypted storage device to hold your GPG private keyring containing all active keys. After initial creation of a master key and subkeys, the volume should be taken offline and held in a secure location. It should be mounted only to create new subkeys and revoke old subkeys. Ideally all key management operations should be performed in the secure computing environment established in step 1.
  3. Export signing and encryption keys to one or more smart cards for secure and convenient day-to-day usage.

Preparation

The premise of this exercise is to create keys that are secure for years, so it merits some planning and attention to detail. The most important aspects to consider:

  1. Setting up a secure computing environment in which to perform key management. Ideally this environment would be available not only for initial key generation but for subsequent subkey management operations (creation, revocation) in the future.
  2. Managing an encrypted removable storage device for the long term.

I'll simply state what worked for my needs in those areas. I had old MacBook lying around that I reinitialized and got patched, then I downloaded Kali Linux, a security-oriented distribution. I obtained a security-oriented encrypted flash drive (Aegis Secure Key) and followed the Kali documentation for creating a bootable USB drive. Once I could boot into Kali from the flash drive, I leveraged the persistent volume feature of Kali to persist my home directory to a second volume on the flash drive. While it was a lot of work to set all that up, I can say in retrospect that it was worthwhile. Now I can just boot into Kali from the flash drive and my home directory naturally contains my .gnupg folder containing my public and private keyrings.

It's worth noting that the Aegis Secure Key has a hardware crypto engine and requires an 8-digit PIN to mount, so the details of encryption are all opaque to me. It's an expensive device, but has proven trustworthy over several years of use and I appreciate that I don't have handle the cryptographic details to use it. A cheaper alternative would be to layer an encrypted filesystem on top of an ext4 filesystem on a regular flash drive. Whatever you use, it's worth spending some time and money on durable and reliable hardware. Remember, this thing will need to last for ten years or more, which is an eternity for a computer hardware device.

Process Detail

The following shell session provides a soup-to-nuts process for generating a certificate key and subkeys that are exported to a smart card for daily use. The process assumes you are working in your secure computing environment with the home directory mounted on the encrypted flash drive. Comments are provided in hash boxes to delineate steps and important notes.

root@kali:~# rm -fR .gnupg

#################################################
# Generate a certification key
#################################################
root@kali:~# gpg --expert --full-gen-key
gpg (GnuPG) 2.2.5; 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.

gpg: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created

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)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
Your selection? 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? s

Possible actions for a RSA key: Sign Certify Encrypt Authenticate 
Current allowed actions: Certify 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 Certify Encrypt Authenticate 
Current allowed actions: Certify 

   (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) 
Key does not expire at all
Is this correct? (y/N) y

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

Real name: Marvin S. Addison
Email address: serac@vt.edu
Comment: 
You selected this USER-ID:
    "Marvin S. Addison <serac@vt.edu>"

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: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 9A1331FCCF8BA2CA marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/5C5B8648E408DE13091A163F9A1331FCCF8BA2CA.rev'
public and secret key created and signed.

pub   rsa4096 2018-06-08 [C]
      5C5B8648E408DE13091A163F9A1331FCCF8BA2CA
uid                      Marvin S. Addison <serac@vt.edu>

root@kali:~# gpg --expert --edit-key 5C5B8648E408DE13091A163F9A1331FCCF8BA2CA
gpg (GnuPG) 2.2.5; 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
sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1). Marvin S. Addison <serac@vt.edu>

#################################################
# Attach additional identities as needed
#################################################
gpg> adduid
Real name: Marvin S. Addison
Email address: marvin.addison@gmail.com
Comment: 
You selected this USER-ID:
    "Marvin S. Addison <marvin.addison@gmail.com>"

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

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1)  Marvin S. Addison <serac@vt.edu>
[ unknown] (2). Marvin S. Addison <marvin.addison@gmail.com>

#################################################
# Set all identities to ultimate trust
#################################################
gpg> trust
sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1)  Marvin S. Addison <serac@vt.edu>
[ unknown] (2). Marvin S. Addison <marvin.addison@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

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1)  Marvin S. Addison <serac@vt.edu>
[ unknown] (2). Marvin S. Addison <marvin.addison@gmail.com>

gpg> q
Save changes? (y/N) y
root@kali:~# gpg --expert --edit-key 5C5B8648E408DE13091A163F9A1331FCCF8BA2CA
gpg (GnuPG) 2.2.5; 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
sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> uid 2

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)* Marvin S. Addison <serac@vt.edu>

gpg> uid

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

#################################################
# Generate a subkey for signing
#################################################
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? e

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

   (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) 
Key does not expire at all
Is this correct? (y/N) 
Key is valid for? (0) 
Key does not expire at all
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/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

#################################################
# Generate a subkey for encryption
#################################################
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? 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) 
Key does not expire at all
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/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb  rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

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

#################################################
# Make backups and revocation keys
#################################################
root@kali:~# export KEY=9A1331FCCF8BA2CA
root@kali:~# export BAK=~/.gnupg/backup
root@kali:~# mkdir $BAK
root@kali:~# gpg --output ~/.gnupg/backup/$KEY.revoke.asc --gen-revoke $KEY

sec  rsa4096/9A1331FCCF8BA2CA 2018-06-08 Marvin S. Addison <marvin.addison@gmail.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:
> 
Reason for revocation: No reason specified
(No description given)
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!
root@kali:~# gpg --armor --output $BAK/$KEY.privkey.asc --export-secret-key $KEYroot@kali:~# gpg --armor --output $BAK/$KEY.subkeys.asc --export-secret-subkeys $KEY
root@kali:~# gpg --armor --output $BAK/$KEY.pubkey.asc --export $KEY
root@kali:~# ls $BAK
9A1331FCCF8BA2CA.privkey.asc  9A1331FCCF8BA2CA.revoke.asc
9A1331FCCF8BA2CA.pubkey.asc   9A1331FCCF8BA2CA.subkeys.asc
root@kali:~# gpg --expert --edit-key 50B2D0FBB07958AE80F1E7ADFCEB20CC6F4C5AA3
gpg (GnuPG) 2.2.5; 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.

gpg: key "50B2D0FBB07958AE80F1E7ADFCEB20CC6F4C5AA3" not found: No public key

#################################################
# Export subkeys to smartcard (i.e. YubiKey 4)
#################################################
root@kali:~# gpg --expert --edit-key $KEY
gpg (GnuPG) 2.2.5; 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/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb  rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> key 1

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb  rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> keytocard
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

gpg: WARNING: such a key has already been stored on the card!

Replace existing key? (y/N) y

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb  rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> key 2

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb* rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb* rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> keytocard
You must select exactly one key.

gpg> key 1

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb* rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

gpg: WARNING: such a key has already been stored on the card!

Replace existing key? (y/N) y

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb* rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

gpg> key

sec  rsa4096/9A1331FCCF8BA2CA
     created: 2018-06-08  expires: never       usage: C   
     trust: ultimate      validity: ultimate
ssb  rsa4096/FE5DE05A039DDED9
     created: 2018-06-08  expires: never       usage: S   
ssb  rsa4096/337B85789C73123C
     created: 2018-06-08  expires: never       usage: E   
[ultimate] (1). Marvin S. Addison <marvin.addison@gmail.com>
[ultimate] (2)  Marvin S. Addison <serac@vt.edu>

#################################################
# WARNING! WARNING! DANGER Will Robinson!
# DO NOT save changes or the secret part of your
# subkeys will be removed from your keyring
# and you will never, ever be able to recover
# them. This detail is key if you want to
# retain the capability to export subkeys to
# new cards in the future; for example, damage
# or loss.
#################################################
gpg> quit
Save changes? (y/N) N
Quit without saving? (y/N) y

#################################################
# Review the final status
#################################################
root@kali:~# gpg --card-status

Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240102010006069235230000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06923523
Name of cardholder: Marvin Addison
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 15
Signature key ....: 7DF5 3B21 62E9 9705 3C64  4629 FE5D E05A 039D DED9
      created ....: 2018-06-08 17:53:30
Encryption key....: B438 D3B6 790B B982 2398  5BA2 337B 8578 9C73 123C
      created ....: 2018-06-08 17:54:28
Authentication key: 9A75 77B3 EAD5 3B70 AFC7  69D8 E901 CE63 B0F6 2848
      created ....: 2018-03-03 12:08:52
General key info..: sub  rsa4096/FE5DE05A039DDED9 2018-06-08 Marvin S. Addison <marvin.addison@gmail.com>
sec   rsa4096/9A1331FCCF8BA2CA  created: 2018-06-08  expires: never     
ssb   rsa4096/FE5DE05A039DDED9  created: 2018-06-08  expires: never     
ssb   rsa4096/337B85789C73123C  created: 2018-06-08  expires: never     
root@kali:~# gpg --list-secret-keys --with-subkey-fingerprints
/root/.gnupg/pubring.kbx
------------------------
sec   rsa4096 2018-06-08 [C]
      5C5B8648E408DE13091A163F9A1331FCCF8BA2CA
uid           [ultimate] Marvin S. Addison <marvin.addison@gmail.com>
uid           [ultimate] Marvin S. Addison <serac@vt.edu>
ssb   rsa4096 2018-06-08 [S]
      7DF53B2162E997053C644629FE5DE05A039DDED9
ssb   rsa4096 2018-06-08 [E]
      B438D3B6790BB98223985BA2337B85789C73123C
#!/bin/bash
# Sets up symlinks to temp files to be used as Unix domain sockets by gpg-agent.
# This is necessary for any $GNUPGHOME directory on a FAT volume.
SOCKETS=(
S.dirmngr
S.gpg-agent
S.gpg-agent.browser
S.gpg-agent.extra
S.gpg-agent.ssh
S.scdaemon
)
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
for SOCK in ${SOCKETS[@]}; do
rm -f "$TMPDIR/$SOCK"
ln -fs "$TMPDIR/$SOCK" "$DIR/$SOCK"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment