Skip to content

Instantly share code, notes, and snippets.

@0x7d7b
Last active November 17, 2021 20:48
Show Gist options
  • Save 0x7d7b/7d208e01bf2eb312f491964e67f62487 to your computer and use it in GitHub Desktop.
Save 0x7d7b/7d208e01bf2eb312f491964e67f62487 to your computer and use it in GitHub Desktop.
GnuPG + SSH + YubiKey

GnuPG + SSH Authentication using a YubiKey or Smartcard

This is about how I setup and use GnuPG for signing and encrypting data as well as for authenticating SSH sessions. I use both, a YubiKey (4 and 5 NFC) and a GnuPG smartcard from ZeitControl to have a backup in my wallet. As a smartcard reader I use the uTrust 2700 R which works quite well.
My typical use cases are SSH authentication, secure file exchange via public places and signing Git commits. I rarely use GnuPG for email communication. And I neither sign other GnuPG user IDs nor participate in the WOT.
Since there is no difference between setting up a YubiKey or a smartcard the following description mentions the GnuPG smartcard only.

Preparation

The following steps should be done on an offline system. No network connection! Ideally booted from a live distribution. I prefer Tails or Kali.

All resulting data should be stored on a USB stick supposed to be kept in a safe place (don't forget a backup copy as well).

The only data that will be stored in your normal working environment is the public key. The private sub-keys will be stored on your smartcard. The master key will stay offline on that USB stick.

So go ahead and create a folder named GPG somewhere on the live distribution that you've just booted. All further GPG commands will be run from inside that folder specifying the --homedir . parameter. So cd into that folder. You also might want to set more secure permissions on that folder by running chmod go-rwx . from inside that folder.

Master Key

First you need to create a master key. I recommend using a RSA 4096 bit key with a very strong password. You can also think about using an elliptic curves based key. But some systems might not support that, yet. Including the ZeitControl GnuPG smartcard. So I still use RSA keys.

To generate the master key run the following terminal command:

GPG % gpg2 --homedir . --expert --full-generate-key
gpg (GnuPG) 2.2.10; 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)
  (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

Choose option 8 here as you want to perform a more indivitual setup. The following dialog shows up:

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?

By default the key will have all the Sign Certify Encrypt capabilities. But your master key should only have the Certify capability. To remove the other capabilities first enter S. Then the same dialog appears again. Then enter E. Afterwards it will only show the Certify capability. Then continue by entering Q.

Next a dialog shows up that asks for the key size:

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096

The master key should be 4096 bit long. Then a dialog asks about how long the key should be valid:

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)

The master key should never expire so enter 0. The only keys that will expire are the sub-keys which you will create later. In case you loose access to the master key a revocation certificate will be automatically generated.

Next you will be asked whether all settings are correct. Answer with y.

Is this correct? (y/N) y

In the next dialog you will be asked for further details to create a user ID.

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

Real name:

I tend to not give any personal information, here. Neither my real name nor an email address. I prefer to have my key decoupled from my current email address. Mail addresses may change often. Also I don't like my name to be published on any keyserver. Keep in mind that whenever you publish a key you will never be able to delete your personal data from the keyservers! You might be able to revoke your keys but your personal data will remain. See also: security.stackexchange.com

But anyhow keep in mind that some systems require a valid email address in order to perform a proper user verification. Examples are the new OpenPGP keyserver, github or bitbucket.

So you might want to leave this attribute empty and simply hit RETURN.

Next you will be asked for an email address:

Email address:

Here you might also want to leave it empty for the same reasons mentioned above. So hit RETURN.

Next you will be asked for a comment:

Comment: Just a demo key

I usually leave this empty as well. For this article I added the comment Just a demo key.

After that you need to confirm that all provided information is correct.

You selected this USER-ID:
    " (Just a demo key)"

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

If everything is ok enter O.

Then you are asked for a password. Pick a strong one. It's your master key! I usually use a password generation tool like pwgen to do the job (e.g.: pwgen -cnys 32 1 which will generate a strong 32 char long password).

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: /your/path/to/GPG/temp/trustdb.gpg: trustdb created
gpg: key 5FEBE3828C49B399 marked as ultimately trusted
gpg: directory '/your/path/to/GPG/temp/openpgp-revocs.d' created
gpg: revocation certificate stored as '/your/path/to/GPG/temp/openpgp-revocs.d/CC0D71386C4BC7E7F1A279315FEBE3828C49B399.rev'
public and secret key created and signed.

pub   rsa4096 2019-08-02 [C]
    CC0D71386C4BC7E7F1A279315FEBE3828C49B399
uid                       (Just a demo key)

Now the master key with id CC0D71386C4BC7E7F1A279315FEBE3828C49B399 is ready.

In addition to the master key a revocation certificate has automatically been generated at /your/path/to/GPG/temp/openpgp-revocs.d/CC0D71386C4BC7E7F1A279315FEBE3828C49B399.rev. It should be stored that in a safe place as well (I even printed it just in case).

From now on the master key will only be used to update the sub-keys expiration date (after we created them of course which is described in the next chapter).

The master key would also be used to sign other users ids. But I usually don't do that.

Sub-Keys

Next the sub-keys need to be created. One for encryption, one for signing and one for authentication.

Encryption Key

To create an encryption key run the following command:

GPG % gpg2 --homedir . --edit-key 8C49B399
gpg (GnuPG) 2.2.10; 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
[ultimate] (1).  (Just a demo key)

gpg> addkey

Type in the master key password. Then a prompt will appear. Type 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

Create an RSA encryption key by entering 6:

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096

Answer the question about the keysize with 4096 (the maximum that is currently supported by smartcards):

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) 1y

The question about validity I usually answer with 1 year. So enter 1y.

Key expires at So 2 Aug 12:17:35 2020 CET
Is this correct? (y/N) y

Approve by entering y.

Really create? (y/N) y

Approve the security question again by typing in y. You will then be prompted for your master key password.

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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/8AD7B4D0119944B1
    created: 2019-08-02  expires: 2020-08-02  usage: E
[ultimate] (1).  (Just a demo key)

gpg> save

To save the created encryption key type save on the prompt.

Signing Key

Now do the same to create a signing key:

GPG % gpg2 --homedir . --edit-key 8C49B399
gpg (GnuPG) 2.2.10; 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
[ultimate] (1).  (Just a demo key)

gpg> addkey

Enter addkey as before.

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

The question about the key type needs to be answered with 4 as we want an RSA signing key.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096

Again the key size should be 4096 bit.

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) 1y

And again the validity should be 1y.

Key expires at So 2 Aug 12:33:47 2020 CET
Is this correct? (y/N) y
Really create? (y/N) y

Answer the security questions with y. Then type in your master keys passwort when prompted.

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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
[ultimate] (1).  (Just a demo key)

gpg> save

At the end type save to store the key.

Authentication Key

Now you need to create the authentication key. Therefore the --expert command line option is required otherwise you would not be able to create it:

GPG % gpg2 --homedir . --expert --edit-key 8C49B399
gpg (GnuPG) 2.2.10; 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
[ultimate] (1).  (Just a demo key)

gpg> addkey

Type 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

Choose 8 as you need to specify an RSA key with user defined capabilities.

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?

Note that again Sign Encrypt are the default capabilities. So enter A, S, E and then Q to add authentication, disable encrypt and signing capabilities and to continue.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096

Next use 4096 again as the key length.

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) 1y

Again use a validity of 1y.

Key expires at So 2 Aug 12:45:13 2020 CET
Is this correct? (y/N) y
Really create? (y/N) y

Answer all security questions with 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A
[ultimate] (1).  (Just a demo key)

gpg> save

Type in your master keys password when prompted and save your changes.

Smartcard Setup

Now the master key and its sub-keys have been successfuly created.

Backup First

The most important thing before continuing is to create a backup of the GPG folder, now. Put the folder to an offline stick. Then continue.

This is mandatory as moving the sub-keys to the smartcard will make them unavailable in the PGP folder. And reading sub-keys from the smartcard is not possible. So backup all keys before you do any smartcard configuration.

This also implies that when you need to load the same keys to more than one smartcard you need to restore the GPG folder from the backup everytime you do that!

Hardware Check

Plug in the reader and insert your card. Then list the card status to verify that your smartcard has been detected successfully:

GPG % gpg2 --card-status
Reader ...........: Identive CLOUD 2700 R Smart Card Reader
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 00123456
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

Moving Keys to the Smartcard

Now move the keys to the smartcard. Therefore edit the key:

GPG % gpg2 --homedir . --edit-key 8C49B399
gpg (GnuPG) 2.2.10; 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A
[ultimate] (1).  (Just a demo key)

gpg> key 1

Then select the first key (the encryption key) with key 1. It will be marked with an *:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb* rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

Then move it to the smartcard entering the keytocard command:

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

Select 2 to move the encryption key to the smartcard. You will first be prompted for the master key password and then for the admin PIN of your smartcard. When it's done the keys will be displayed again:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb* rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

gpg> 

Now unselect the first key by typing key 1 and then select the second one (the signing key) by typing key 2:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb* rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

gpg> keytocard

Then run the keytocard command again:

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

Choose the signature key by typing in 1. You will be prompted for the master key password first and then for the smartcard admin PIN. Afterwards the keys will be displayed again:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb* rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

gpg>

Now unselect the second key by typing key 2 and select the last one (the authentication key) by typing key 3:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb* rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

gpg> keytocard

Move it to the smartcard as well by typing keytocard:

Please select where to store the key:
(3) Authentication key
Your selection? 3

This time select 3 for the authentication key. You will again be prompted for the master key password first and then for the smartcard admin PIN. Then the keys will be displayed again:

sec  rsa4096/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb* rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A

gpg> save

Then quit GnuPG by typing save.

To verify that everything has been loaded successfully to the smartcard show its status again:

GPG % gpg2 --homedir . --card-status
Reader ...........: Identive CLOUD 2700 R Smart Card Reader
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 00123456
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 111A 5178 5C7D 91BB E8A3  939B 1991 8F1B AD45 F37C
    created ....: 2019-08-02 11:31:05
Encryption key....: 3FCA F9CE 3D4C 59C9 9CE3  0B32 C297 B8F7 7E02 9CE1
    created ....: 2019-08-02 11:20:33
Authentication key: 9C99 8AE3 97AD 813C 84D3  72CA 9EA6 1616 8252 BBD9
    created ....: 2019-08-02 11:44:55
General key info..: sub  rsa4096/19918F1BAD45F37C 2019-08-02  (Just a demo key)
sec   rsa4096/5FEBE3828C49B399  created: 2019-08-02  expires: never
ssb>  rsa4096/C297B8F77E029CE1  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/19918F1BAD45F37C  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/9EA616168252BBD9  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456

You see that there are all three keys available on your smartcard.

Further Smartcard Configuration

You might want to configure further details of your smartcard like its PINs and some meta information:

Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]

Therefore enable the card edit mode:

GPG % gpg2 --homedir . --card-edit
Reader ...........: Identive CLOUD 2700 R Smart Card Reader
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 00123456
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 111A 5178 5C7D 91BB E8A3  939B 1991 8F1B AD45 F37C
    created ....: 2019-08-02 11:31:05
Encryption key....: 3FCA F9CE 3D4C 59C9 9CE3  0B32 C297 B8F7 7E02 9CE1
    created ....: 2019-08-02 11:20:33
Authentication key: 9C99 8AE3 97AD 813C 84D3  72CA 9EA6 1616 8252 BBD9
    created ....: 2019-08-02 11:44:55
General key info..: sub  rsa4096/19918F1BAD45F37C 2019-08-02  (Just a demo key)
sec   rsa4096/5FEBE3828C49B399  created: 2019-08-02  expires: never
ssb>  rsa4096/C297B8F77E029CE1  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/19918F1BAD45F37C  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/9EA616168252BBD9  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456

gpg/card> admin

Change to the admin menu by typing admin.

From there you can type the following commands to change meta information: sex, lang, login, name and url:

gpg/card> sex
Sex ((M)ale, (F)emale or space): m

gpg/card> lang
Language preferences: en

gpg/card> login
Login data (account name): hs

gpg/card> name
Cardholder's surname: Surename
Cardholder's given name: GivenName

gpg/card>

The login might be relevant when performing authentication with your smartcard. The url could point to a web page where the GnuPG public key is stored.

To change your cards PIN numbers type passwd:

gpg/card> passwd
gpg: OpenPGP card no. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX detected

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

Your selection?

You should specify a strong PIN and an even stronger unblock and admin PIN. When done, quit GnuPG by typing quit.

Then you can review your changes:

GPG % gpg2 --homedir . --card-status
Reader ...........: Identive CLOUD 2700 R Smart Card Reader
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Version ..........: 2.1
Manufacturer .....: ZeitControl
Serial number ....: 00123456
Name of cardholder: GivenName Surename
Language prefs ...: en
Sex ..............: male
URL of public key : [not set]
Login data .......: hs
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 32 32 32
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 111A 5178 5C7D 91BB E8A3  939B 1991 8F1B AD45 F37C
    created ....: 2019-08-02 11:31:05
Encryption key....: 3FCA F9CE 3D4C 59C9 9CE3  0B32 C297 B8F7 7E02 9CE1
    created ....: 2019-08-02 11:20:33
Authentication key: 9C99 8AE3 97AD 813C 84D3  72CA 9EA6 1616 8252 BBD9
    created ....: 2019-08-02 11:44:55
General key info..: sub  rsa4096/19918F1BAD45F37C 2019-08-02  (Just a demo key)
sec   rsa4096/5FEBE3828C49B399  created: 2019-08-02  expires: never
ssb>  rsa4096/C297B8F77E029CE1  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/19918F1BAD45F37C  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456
ssb>  rsa4096/9EA616168252BBD9  created: 2019-08-02  expires: 2020-08-02
                                card-no: 0000 00123456

Export the Public Key

Since on a smartcard there is not enough space for the public key you need to export it separately.

GPG % gpg2 --homedir . --armor --export > 8C49B399.pub.asc

The file 8C49B399.pub.asc now contains your public key in ASCII format.

Store it to a different USB stick (not the one for the backup - you will need it, soon).

You might also want to upload it to the url specified during the smartcard setup. You can also modify the corresponding smartcard parameter again, later.

Now, remove your smartcard. And delete your current GPG working folder (you made a backup!). Reboot into your normal working environment.

Usage

The following chapters show some common GnuPG use cases.

Basic Setup

Assuming you did not use GnuPG so far on your computer, issue the following command to initialize a new .gnupg directory:

~ % gpg2 --list-keys
gpg: keybox '/my/path/to/GPG/pubring.kbx' created
gpg: /my/path/to/GPG/temp2/trustdb.gpg: trustdb created

No keys are available, yet.

Now import the public key that you have stored on the other USB stick in the last chapter.

~ % gpg2 --import 8C49B399.pub.asc
gpg: key 5FEBE3828C49B399: public key " (Just a demo key)" imported
gpg: Total number processed: 1
gpg:               imported: 1

Then list the keys:

~ % gpg2 --list-keys
pub   rsa4096 2019-08-02 [C]
    CC0D71386C4BC7E7F1A279315FEBE3828C49B399
uid           [ unknown]  (Just a demo key)
sub   rsa4096 2019-08-02 [E] [expires: 2020-08-02]
sub   rsa4096 2019-08-02 [S] [expires: 2020-08-02]
sub   rsa4096 2019-08-02 [A] [expires: 2020-08-02]

As it shows the public key has been successfully imported.

When you list the secret keys, you will notice that they are not available locally. You only get their stubs listed:

~ % gpg2 --list-secret-keys
sec#  rsa4096 2019-08-02 [C]
    CC0D71386C4BC7E7F1A279315FEBE3828C49B399
uid           [ unknown]  (Just a demo key)
ssb>  rsa4096 2019-08-02 [E] [expires: 2020-08-02]
ssb>  rsa4096 2019-08-02 [S] [expires: 2020-08-02]
ssb>  rsa4096 2019-08-02 [A] [expires: 2020-08-02]

The # character at sec# says that the master key is offline. The > character at sub> says that these sub-keys are stored on a smartcard.

Basic Commands

Here is a short overview about the basic commands you might need to use GnuPG.

Import Public Keys

When you encrypt files you need the public key from the recepient. And when you need to verify a signature you also need the public key of the sender.

You can either download public keys from one of the keyservers in case it is available there. Or simply import it from a file on commandline:

~ % gpg2 --import otherkey.pub.asc
~ % gpg2 --recv-keys <key id>

To have a look at a key file before importing it you can list its packets by:

~ % gpg2 --list-packets pubkey.pgp.asc

# off=0 ctb=99 tag=6 hlen=3 plen=525
:public key packet:
    version 4, algo 1, created 1575715762, expires 0
    pkey[0]: [4096 bits]
    pkey[1]: [17 bits]
    keyid: 5FEBE3828C49B399
# off=528 ctb=b4 tag=13 hlen=2 plen=18
:user ID packet: " (Just a demo key)"
# off=548 ctb=89 tag=2 hlen=3 plen=590
:signature packet: algo 1, keyid 5FEBE3828C49B399
    version 4, created 1575715762, md5len 0, sigclass 0x13
    digest algo 8, begin of digest fc 23
    hashed subpkt 33 len 21 (issuer fpr v4 CC0D71386C4BC7E7F1A279315FEBE3828C49B399)
    hashed subpkt 2 len 4 (sig created 2019-08-02)
    hashed subpkt 27 len 1 (key flags: 01)
    hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 2)
    hashed subpkt 21 len 5 (pref-hash-algos: 10 9 8 11 2)
    hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
    hashed subpkt 30 len 1 (features: 01)
    hashed subpkt 23 len 1 (keyserver preferences: 80)
    subpkt 16 len 8 (issuer key ID 5FEBE3828C49B399)
    data: [4094 bits]
# off=1141 ctb=b9 tag=14 hlen=3 plen=525
:public sub key packet:
    version 4, algo 1, created 1575717633, expires 0
    pkey[0]: [4096 bits]
    pkey[1]: [17 bits]
    keyid: C297B8F77E029CE1
# off=1669 ctb=89 tag=2 hlen=3 plen=572
:signature packet: algo 1, keyid 5FEBE3828C49B399
    version 4, created 1575717633, md5len 0, sigclass 0x18
    digest algo 8, begin of digest 61 c7
    hashed subpkt 33 len 21 (issuer fpr v4 CC0D71386C4BC7E7F1A279315FEBE3828C49B399)
    hashed subpkt 2 len 4 (sig created 2019-08-02)
    hashed subpkt 27 len 1 (key flags: 0C)
    hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
    subpkt 16 len 8 (issuer key ID 5FEBE3828C49B399)
    data: [4096 bits]
# off=2244 ctb=b9 tag=14 hlen=3 plen=525
:public sub key packet:
    version 4, algo 1, created 1575718265, expires 0
    pkey[0]: [4096 bits]
    pkey[1]: [17 bits]
    keyid: 19918F1BAD45F37C
# off=2772 ctb=89 tag=2 hlen=3 plen=1138
:signature packet: algo 1, keyid 5FEBE3828C49B399
    version 4, created 1575718265, md5len 0, sigclass 0x18
    digest algo 8, begin of digest d6 11
    hashed subpkt 33 len 21 (issuer fpr v4 CC0D71386C4BC7E7F1A279315FEBE3828C49B399)
    hashed subpkt 2 len 4 (sig created 2019-08-02)
    hashed subpkt 27 len 1 (key flags: 02)
    hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
    subpkt 16 len 8 (issuer key ID 5FEBE3828C49B399)
    subpkt 32 len 563 (signature: v4, class 0x19, algo 1, digest algo 8)
    data: [4096 bits]
# off=3913 ctb=b9 tag=14 hlen=3 plen=525
:public sub key packet:
    version 4, algo 1, created 1575719095, expires 0
    pkey[0]: [4096 bits]
    pkey[1]: [17 bits]
    keyid: 9EA616168252BBD9
# off=4441 ctb=89 tag=2 hlen=3 plen=572
:signature packet: algo 1, keyid 5FEBE3828C49B399
    version 4, created 1575719095, md5len 0, sigclass 0x18
    digest algo 8, begin of digest 26 a5
    hashed subpkt 33 len 21 (issuer fpr v4 CC0D71386C4BC7E7F1A279315FEBE3828C49B399)
    hashed subpkt 2 len 4 (sig created 2019-08-02)
    hashed subpkt 27 len 1 (key flags: 20)
    hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
    subpkt 16 len 8 (issuer key ID 5FEBE3828C49B399)
    data: [4094 bits]

Encrypt

To encrypt a file use the --encrypt option like:

# Create a test file.
~ % echo "Test." > test.txt
# Assuming that you have a public key imported from recipient@example.com
~ % gpg2 --encrypt [--armor] test.txt -r recipient@example.com

This will create a binary test.txt.gpg file or an ASCII test.txt.asc file depending on the --armor parameter.

Sign

To sign a file use the --sign option like:

~ % gpg2 --sign [--armor] test.txt

You will be prompted for the smartcard PIN. This will create a binary test.txt.gpg file or an ASCII test.txt.asc file depending on the --armor parameter.

Encrypt + Sign

You can combine the encrypt and sign steps using both parameters like:

~ % gpg2 --encrypt --sign [--armor] test.txt -r recipient@example.com

This will create a binary file test.txt.gpg or an ascii file test.txt.asc depending on the --armor command line argument.

Verify

To verify a signature file run:

~ % gpg2 --verify test.txt.[gpg|asc]

Decrypt

Decryption automatically verifies an encrypted file in case a signature has been found. To do so run:

~ % gpg2 --output test.txt --decrypt test.txt.[gpg|asc]

You will be prompted for the smartcard PIN. This will decrypt the file and write the results to the test.txt file. When you leave out the --output parameter the decrypted content will be written to STDOUT.

SSH Setup

To enable SSH support for GnuPG you need to add the enable-ssh-support property to the ~/.gnupg/gpg-agent.conf file. Also the SSH_AUTH_SOCK and GPG_TTY environment variable need to be set properly. Please have a look at the configuration files section below. You probably want to run gpg-connect-agent updatestartuptty /bye &>/dev/null as well. See stackoverflow.com for details.

Once the environment has been setup properly the key need to be added to the ssh-agent. Therefore put the authentication keys keygrip into a ~/.gnupg/sshcontrol file. It can be listed by running gpg2 --list-keys --with-keygrip. Afterwards check its availability with ssh-add -l.

Now go and copy your SSH public key to the remote systems where you need to login. This can be done by running ssh-add -L. Copy the STDOUT into the remote authorized_keys file.

Configuration Files

Here you find my GnuPG configuration files. They are the best fit for my personal requirements and contain a proper SSH setup as well.

~/.gnupg/gpg.conf:

default-key 0x5FEBE3828C49B399
trusted-key 0x5FEBE3828C49B399
# I always want to be able to decrypt my own encrypted files
hidden-encrypt-to 0x5FEBE3828C49B399
default-recipient-self
throw-keyids
expert
use-agent
no-greeting
keyid-format 0xlong
with-keygrip
fingerprint
fixed-list-mode
no-escape-from-lines
require-cross-certification
charset utf-8
utf8-strings
no-mangle-dos-filenames
# Choose a more secure keyserver connection by default
keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options auto-key-retrieve no-honor-keyserver-url
auto-key-locate hkps://hkps.pool.sks-keyservers.net
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 ZLIB BZIP2 ZIP Uncompressed
# 3DES and SHA-1 are implicitly added by GnuPG
personal-digest-preferences SHA512 SHA384 SHA256
personal-cipher-preferences AES256 AES192
personal-compress-preferences ZLIB BZIP2 ZIP
no-emit-version
force-mdc
ask-cert-level
# Do not ask for sig expiration everytime as that would
# make git commits/pushs to ask every time
#ask-sig-expire
ask-cert-expire
verify-options show-notations,show-policy-urls,show-keyserver-urls
list-options show-policy-urls,show-notations,show-sig-expire,show-keyserver-urls,show-uid-validity,show-unusable-uids,show-unusable-subkeys,show-keyring
# Salt passwords and iterate 3 times
# https://tools.ietf.org/html/rfc4880#section-3.7.1
s2k-mode 3

~/.gnupg/dirmngr.conf:

keyserver hkps://hkps.pool.sks-keyservers.net
hkp-cacert ~/.gnupg/sks-keyservers.netCA.pem

Make sure to download https://sks-keyservers.net/sks-keyservers.netCA.pem and store it to ~/.gnupg/sks-keyservers.netCA.pem!

~/.gnupg/gpg-agent.conf:

default-cache-ttl 600
max-cache-ttl 7200
# We want to have SSH support for our authentication key
enable-ssh-support
# Change to whatever pinentry program you want to use
#pinentry-program /usr/local/bin/pinentry
allow-loopback-pinentry

~/.gnupg/gpa.conf:

default-key CC0D71386C4BC7E7F1A279315FEBE3828C49B399
advanced-ui
show-advanced-options
detailed-view

~/.gnupg/scdaemon.conf:

verbose
card-timeout 1
disable-ccid

~/.gnupg/sshcontrol:

# This is the authentication keys keygrip
96849EDD0C4BEF24E96E8545BC04E2BDC3487FAD

~/.bashrc:

# GPG 2.1.x SSH support
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
export GPG_TTY=$(tty)
# The following line fixes this issue:
# https://stackoverflow.com/questions/44250002/sign-and-send-pubkey-signing-failed-agent-refused-operation
gpg-connect-agent updatestartuptty /bye &>/dev/null
# Reload the components, otherwise ssh login would not work upfront
# without having lazily loaded gpg by e.g. doing a key listing.
gpgconf --reload dirmngr
gpgconf --reload gpg-agent
gpgconf --reload gpg
gpgconf --reload scdaemon
gpgconf --reload pinentry
gpgconf --reload gpgsm

Publishing the Public Key

You may want to publish your public key to a keyserver. In my configuration file above I use the keyserver at hkps://hkps.pool.sks-keyservers.net:

~ % gpg2 --send-keys 0x5FEBE3828C49B399

In addition I usually place my public key somewhere on the net as well. Then I can point to it by my smartcard url property and use it in scripts easily without using a keyserver. You can find mine at https://md.sachse.info/.well-known/pubkey.pgp.asc.

You could also store your public SSH key at the same location.

Key Expiration

Above you created the sub-keys with an exiration time of one year. But what if that year is over? Simply edit the keys and change their expiration date!

This is one of the rare situations where you need the offline master key again. So: go offline with your computer, boot up from a live distribution again. Plug in the backup stick with your master key. Copy the backup to a folder on the live system, say GPG. Remove the backup stick, cd into that GPG folder and proceed:

GPG % gpg2 --homedir . --edit-key 8C49B399
gpg (GnuPG) 2.2.10; 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/5FEBE3828C49B399
    created: 2019-08-02  expires: never       usage: C
    trust: ultimate      validity: ultimate
ssb  rsa4096/C297B8F77E029CE1
    created: 2019-08-02  expires: 2020-08-02  usage: E
ssb  rsa4096/19918F1BAD45F37C
    created: 2019-08-02  expires: 2020-08-02  usage: S
ssb  rsa4096/9EA616168252BBD9
    created: 2019-08-02  expires: 2020-08-02  usage: A
[ultimate] (1).  (Just a demo key)

gpg> key 1
gpg> key 2
gpg> key 3
gpg> expire
Are you sure you want to change the expiration time for multiple subkeys? (y/N) y
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) 1y
gpg> save

As printed above select all 3 subkeys with key 1, key 2 and key 3. Then run the expire command. Here we add one more year by typing 1y. Then save your changes.

The only thing that you need to do now is to re-export the public key. You don't need to do any changes on the smartcard!

So export the public key now, store it to a different usb stick. Then remove the stick with the master key, shutdown your live system and boot normally.

Then import the public key from the stick into your normal GnuPG working environment and publish it to the keyservers and the other places where you offer it for download. That's it.

Revoking the Master Key

In case you need to revoke the master key (hopefully that never happens) you first need to import the revocation certificate. It has been created alongside the master key. It's stored on your offline backup stick. To do so copy the revocation certificate from there to you normal working environment and run:

~ % gpg2 --import CC0D71386C4BC7E7F1A279315FEBE3828C49B399.rev

Then (locally) the master key has been revoked. Now you only need to publish that information to the keyserver by simply sending the public key again.

~ % gpg2 --send-keys 0x5FEBE3828C49B399

Done.

Background Processes

Sometimes it is necessary to stop all GnuPG background processes. There are several services started: gpg-agent, scdaemon, dirmanager, pinentry and others. To stop all of them run:

~ % gpg-agent --kill all

If afterwards there are still running processes, try to kill them like:

ps axf | grep scdaemon
kill -9 <pid of scdaemon>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment