Skip to content

Instantly share code, notes, and snippets.

@Riebart
Created April 24, 2022 01:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Riebart/64c53f7d4ad4f5897b22c43ac0410ae5 to your computer and use it in GitHub Desktop.
Save Riebart/64c53f7d4ad4f5897b22c43ac0410ae5 to your computer and use it in GitHub Desktop.
Yubikeys as a gpg and ssh hardware engine

Yubikey first-time setup

PGP Module

Installation

  • Install GnuPG from the official site.
    • Note, do not install GPG4Win. These instructions may or may not work with the opinionated default configuration of GPG4Win.
    • Install the Simple installer for the current GnuPG installer, as this is known to work, and is the distribution that these instructions were tested with.
    • If you have a GnuPG version installed already, note that at least 2.3 is required to be able to control the User Interaction Function (uif) features of the Yubikey through gpg
  • Install, or extract manually

Manual extraction and installation

  • Extract the installer with 7-zip
  • Copy the folder contents of the package to %LOCALAPPDATA%\Programs\gnupg
    • To confirm that the directories were laid out correctly, ensure that %LOCALAPPDATA%\Programs\gnupg\bin\gpg.exe exists
  • Edit the PATH environment variable for your account to include the new gpg location
    • Start -> variables for your account -> "Edit environment variables for your account"
    • Add %LOCALAPPDATA%\Programs\gnupg\bin on a new line to the PATH environment variable in the top list (user variables), and not the bottom list (system variables)

Yubikey PGP card configuration

Plug in your USB key to your computer, and confirm that the above worked by opening a Powershell prompt:

PS C:\Users\MyUser> gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID 0
Application ID ...: D2760001240100000006179161830000
Application type .: OpenPGP
Version ..........: 0.0
Manufacturer .....: Yubico
Serial number ....: 17916183
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
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 : 0
KDF setting ......: off
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

You can get extended card details from the gpg-card utility, which lists additional information such as the card firmware version and OpenPGP module version:

PS C:\Users\MyUser> gpg-card
Reader ...........: Yubico YubiKey OTP FIDO CCID 0
Card type ........: yubikey
Card firmware ....: 5.4.3
Serial number ....: D2760001240100000006179161830000
Application type .: OpenPGP
Version ..........: 3.4
Displayed s/n ....: 17 916 183
Manufacturer .....: Yubico (6)
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......: [not set]
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 4
Capabilities .....: key-import algo-change button priv-data
KDF setting ......: on
UIF setting ......: Sign=on Decrypt=on Auth=on
Signature key ....: 49E599DB45969009FDD76E1D8E0806429B5BD1C2
      keyref .....: OPENPGP.1  (sign,cert)
      algorithm ..: brainpoolP512r1
      stored fpr .: 576FA375139B2871414656DAD0658E1F80938677
      created ....: 2021-11-15 21:11:08
Encryption key....: 7ED669F8514F18D9B2BED5611C893ACECD8F6023
      keyref .....: OPENPGP.2  (encr)
      algorithm ..: brainpoolP512r1
      stored fpr .: 9F8A78352B3CE1BC867BCFB62F6F001478A29A2F
      created ....: 2021-11-15 21:11:08
Authentication key: 5C771F3DB090AF6AAB277AB02BED944F1BB587A5
      keyref .....: OPENPGP.3  (sign,auth)
      algorithm ..: brainpoolP512r1
      stored fpr .: F69909CA4F86E30189F4CA15F4289EAF9A3F140A
      created ....: 2021-11-15 21:11:08

All of the below sections will start with gpg --edit-card to enter the interactive GPG card editor prompt.

Changing, and setting the PINs

Note that the some of the commands we run will prompt you for a PIN. The default PINs are:

  • Unlock PIN: 123456
  • Admin PIN: 12345678

The Unlock PIN is used to perform operations on the card using the private key, and is required to be entered the first time an operation is attempted after the gpg process opens the card for use.

The Admin PIN is used to change the state of the card, and to unblock the Unlock PIN if too many incorrect pin attempts are made.

There is also the Reset Code which can be used to reset the key in the event that the admin pin has been locked out.

Setting the PIN

PS C:\Users\MyUser\Desktop> gpg --edit-card
...

gpg/card> admin
Admin commands are allowed

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

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? 3
PIN changed.

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

Your selection? 4
Reset Code set.

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

Your selection? q

Public key algorithm

The short answer: Choose RSA 4096

Why: It is ubiquitous, well understood, secure for 5-10 years, and fast enough (~1200ms per encryption operation)

If you want to be able to sign hundreds of commits when rebasing a code tree, use ECC and Curve 25519.

Notes on public key algorithm security

At present, both RSA and ECC are similar in cryptographic strength and safety, for common key lengths. Specifically, Table 2 in the NIST Special Publication 800-57 Part 1 lists security strengths (in effective bits of key) for various key lengths and algorithms. Reproduced in part here, noting the key lengths in bits that are equivalent security, with an additional row interpolated for a 4096-bit RSA key:

Strength Symmetric RSA/DSA ECC
112 3TDEA 2048 224-255
128 AES-128 3072 256-383 (e.g. Curve 25519)
~170 N/A 4096 ~360
192 AES-192 7680 384-511
256 AES-256 15360 >512 (e.g. NIST P-521, Brainpool P-512)

This suggests that, at present, a 4096-bit RSA key is stronger than a 256 bit ECC key, but not a NIST P-521 key.

ECC keys are subject to an additional safety constraint as a result of the ECC curve that is chosen for various algorithms. The choice of ECC curve is made using the results of SafeCurves, which evaluates known cryptographic primitives for security across known attack and compromise/implementation areas.

Specifically, of the ECC curves supported by the Yubikey 5-series, only Curve 25519 is both safe and strong. While Brainpool P-512 (r1) is likely safe and definitely stronger, it cannot be used for SSH authentication. The NIST P-521 curve is possibly safe, and definitely strongly, there is significant lack of rigidity in how its parameters were chosen with open concerns (note: the validity of these concerns is also in questionable. c.f. Tin Foil Hat) about potential cryptographic weaknesses inherent by design. The NIST curves can be used for SSH authentication.

NOTE: The list of all supported ECC curves on the Yubikey 5-series cards with sufficient firmware revisions can be found here, as well as extensive details on additional SmartCard features of the keys, including acting a hardware random number generator.

It is notable that the GnuPG team has defaulted to using ECC as the default key type when generating new keys.

Further reading on ECC

Choosing a keypair type

ECC curves provide tradeoffs of value depending on your use cases:

  • RSA4096 is strong, ubiquitous, and the "simple" choice, with a long operation time (~1200ms per decryption operation)
  • ECC on Curve 25519 is very well supported, and has a small strength penalty for a significant performance improvement over all other options. (~100ms per decryption operation)
    • Choose this option if you expect to be using your key for signing large numbers of items, for example when rebasing commit trees with hundreds of commits non-interactively.
  • ECC on curve NIST-P 521 is the strongest option available, offering security until at least 2030 according to NIST, with a mid-range performance (~500ms per decryption operation), with strong support across a broad range of applications (including SSH). The tradeoff is that there is unverified claims that cryptographic backdoors are possible.
    • Choose this option if you want the strongest possible keypair, and are not concerned with unsubstantiated rumours of cryptographic backdoors.

All three keypairs can be used for SSH authentication, whereas Brainpool curves cannot be used for SSH authentication.

Setting the key attribute to use Curve 25519 ECC keys (requires Admin PIN)

# Nore the use of the --expert flag, which is required to see all available curves when choosing an ECC key type
PS C:\Users\MyUser> gpg --edit-card --expert
...
gpg/card> admin
Admin commands are allowed

gpg/card> key-attr
Changing card key attribute for: Signature key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (2) Curve 448
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
Your selection? 1
The card will now be re-configured to generate a key of type: ed25519
Note: There is no guarantee that the card supports the requested
      key type or size.  If the key generation does not succeed,
      please check the documentation of your card to see which
      key types and sizes are supported.
Changing card key attribute for: Encryption key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (2) Curve 448
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
Your selection? 1
The card will now be re-configured to generate a key of type: cv25519
Changing card key attribute for: Authentication key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 2
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (2) Curve 448
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
Your selection? 1
The card will now be re-configured to generate a key of type: ed25519

Setting the key attribute to use 4096-bit RSA keys (requires Admin PIN)

gpg/card> admin
Admin commands are allowed

gpg/card> key-attr
Changing card key attribute for: Signature key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Encryption key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits
Changing card key attribute for: Authentication key
Please select what kind of key you want:
   (1) RSA
   (2) ECC
Your selection? 1
What keysize do you want? (2048) 4096
The card will now be re-configured to generate a key of 4096 bits

gpg/card>

Now the key will generate 4096-bit keys, as opposed to the default 2048-bit keys.

Generating PGP Keys

When generating keys, we make specific note to not create off-key backup, and instead generate the keys entirely on the card, and never export them (the private key cannot be exported from the card after generation). This ensures that the card performs the generation efforts, and that the private key never exists anywhere except on the Yubikey itself.

The key is set not to expire intentionally, as this is a master key, and master key expiration is generally not recommended.

gpg/card> generate
Make off-card backup of encryption key? (Y/n) n

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) 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: John Doe
Email address: john.doe@example.com
Comment: ORG-YK5-1
You selected this USER-ID:
    "John Doe (ORG-YK5-1) <john.doe@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
gpg: C:\\Users\\MyUser\\AppData\\Roaming\\gnupg\\trustdb.gpg: trustdb created
gpg: key 43D4EEE22B19002B marked as ultimately trusted
gpg: directory 'C:\\Users\\MyUser\\AppData\\Roaming\\gnupg\\openpgp-revocs.d' created
gpg: revocation certificate stored as 'C:\\Users\\MyUser\\AppData\\Roaming\\gnupg\\openpgp-revocs.d\\C699DA9ECB5907E10E829CEC43D4EEE22B19002B.rev'
public and secret key created and signed.

Forcing a PIN entry and user interaction on all private key operations

THe Yubikey supports requiring a physical press on the brass circle on the top of the card during private key operations, and enabling this is good practice. This requires that a physical press is required to permit any private key operation for signing (1), decryption (2), and authentication (3).

gpg/card> admin
Admin commands are allowed

gpg/card> uif 1 on

gpg/card> uif 2 on

gpg/card> uif 3 on

(OPTIONAL) Using the forcesig option to force PIN entry on every private key operation

By default, the PIN is required on the first operation each time the key is inserted into a system or access by a gpg process. The forcesig property forces the PIN to be entered on every operation. This can make many workflows less convenient, however when in use in untrusted environments, this should be enabled.

gpg/card> admin
Admin commands are allowed

gpg/card> forcesig

Setting cardholder information

gpg/card> admin
Admin commands are allowed

gpg/card> name
Cardholder's surname: Doe
Cardholder's given name: John

gpg/card> lang
Language preferences: en

gpg/card> salutation
Salutation (M = Mr., F = Ms., or space): M

The keypair public key can be uploaded to a public location, such as GItHub, SharePoint, OneDrive, Google Drive, or any other location, and then referenced by setting it in the url property of the card. This is useful for sharing the public key of your keypair with others.

Listing the results

PS C:\Users\MikeHimbeault\Desktop> gpg --card-status
Reader ...........: Yubico YubiKey OTP FIDO CCID 0
Application ID ...: D2760001240100000006179161830000
Application type .: OpenPGP
Version ..........: 0.0
Manufacturer .....: Yubico
Serial number ....: 17916183
Name of cardholder: John Doe
Language prefs ...: en
Salutation .......: Mr.
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 5
KDF setting ......: off
UIF setting ......: Sign=on Decrypt=on Auth=on
Signature key ....: C699 DA9E CB59 07E1 0E82  9CEC 43D4 EEE2 2B19 002B
      created ....: 2021-11-10 16:34:51
Encryption key....: 25BB 6BC8 7505 7D3A 382A  5E84 3D32 2F7C E55C 258E
      created ....: 2021-11-10 16:34:51
Authentication key: E010 C1C1 976C 7CCC 98F2  A1AB E74A 4EB2 16F7 9ADA
      created ....: 2021-11-10 16:34:51
General key info..: pub  ed25519/43D4EEE22B19002B 2021-11-10 John Doe (ORG-YK5-1) <john.doe@example.com>
sec>  ed25519/43D4EEE22B19002B  created: 2021-11-10  expires: never
                                card-no: 0006 17916183
ssb>  ed25519/E74A4EB216F79ADA  created: 2021-11-10  expires: never
                                card-no: 0006 17916183
ssb>  cv25519/3D322F7CE55C258E  created: 2021-11-10  expires: never
                                card-no: 0006 17916183

Configure git on Windows to gpg-sign commits

As part of your ~/.gitconfig (or %USERPROFILE%\.gitconfig), add some lines like the following (note that we use the same key IDs from previous, so you can see which part of your key information you want to be using):

[user]
        email = john.doe@example.com
        name = John Doe
        signingkey = 43D4EEE22B19002B

[gpg]
        program = C:\\Users\\JohnDoe\\AppData\\Local\\Programs\\gnupg\\bin\\gpg.exe

[commit]
       gpgsign = true

GitHub Vigilant Mode

GitHub supports strong warnings if commits are not signed, and can be enabled through Vigilant Mode.

Using PGP keys as SSH private keys (WIP)

This section is a work in progress, however these are some references that can help.

Note that using Yubikeys on Windows as SSH private keys is challenging, especially if you want to use it within WSL:

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