Skip to content

Latest commit

 

History

History
623 lines (437 loc) · 18.4 KB

token-setup.mkd

File metadata and controls

623 lines (437 loc) · 18.4 KB

% Yubikey setup % SUNET % 2023-03-23

Yubikey setup

This guide steps you through the process of setting up a YubiKey for use with openssh and gpg.

Keys are generated outside the Yubikey for two reasons:

  1. to facilitate backups of the secret key (think loosing your Yubikey)
  2. who knows how good the RNG in the Yubikey is? http://smartfacts.cr.yp.to/

Mac instructions

Prerequisites

  • YubiKey 5 Series
  • brew

Installation

Make sure that /opt/homebrew/bin (if using an ARM Mac) or /usr/local/bin (x86) is before /bin in your $PATH. This should be the case with a standard Homebrew installation.

  1. $ brew install ykman
  2. $ brew install pinentry-mac
  3. $ brew install gnupg

Update gpg.conf

Create a gpg.conf in key_space containing:

default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
personal-digest-preferences SHA512
cert-digest-algo SHA512

Install Tugpgp and follow the instruction

  1. Install the latest release of Tugpgp
  2. Run the application and follow the guide at the wiki in Github for the next steps.

Linux instructions

Ubuntu/Debian

# sudo apt-get install gnupg2 gnupg-agent gpgsm pcscd scdaemon libfuse2

Add the following to $HOME/.gnupg/gpg-agent.conf. Don't forget to check the path to scdaemon.

scdaemon-program /usr/lib/gnupg/scdaemon
enable-ssh-support
# Enable debug logging if needed
#debug guru
#log-file /dev/shm/gpg-agent.log

Add the following to $HOME/.bashrc or equivalent

GPG_TTY=$(tty)
export GPG_TTY
# Set up ssh-agent socket as specified in gpg-agent(1) 
unset SSH_AGENT_PID 
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then 
    export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi

For gpg >= 2.4.4 (ex. Ubuntu 24.04) you need to add the following to $HOME/.gnupg/scdaemon.conf

disable-ccid
  1. Download the latest AppImage
  2. Follow along the guide at the wiki in Github for the steps.

Previous manual instructions (only saved as reference).

Mac instructions

Mac instructions

Prerequisites

  • YubiKey 5 Series
  • brew
  • a usb-memory

Installation

Make sure that /opt/homebrew/bin (if using an ARM Mac) or /usr/local/bin (x86) is before /bin in your $PATH. This should be the case with a standard Homebrew installation.

  1. $ brew install ykman
  2. $ brew install pinentry-mac
  3. $ brew install gnupg

Create a more secure workspace

  1. $ umask 077
  2. $ diskutil erasevolume HFS+ 'RAMDisk' $(hdiutil attach -nomount ram://8388608)
  3. $ cd /Volumes/RAMDisk
  4. $ mkdir key_space
  5. $ cd key_space
  6. $ chown -R $(whoami) .
  7. $ chmod 700 .

Update gpg.conf

Create a gpg.conf in key_space containing:

default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
personal-digest-preferences SHA512
cert-digest-algo SHA512

Create primary Key

$ export GNUPGHOME=$PWD

Kill any running gpg-agent process.

$ gpg --full-gen-key

  1. (1) RSA and RSA (default)
  2. 4096
  3. 1y
  4. Add Real name and Email but leave Comment empty

Keep the returning key ID handy.

Edit primary key

$ gpg --edit-key --expert <ID>

Add another UID (Optional)

gpg> adduuid # until done

Add Authenticate subkey (SSH)

gpg> addkey

  1. (8) RSA (set your own capabilities)
  2. toggle S & E & A which should result in only "Authenticate".
  3. 4096
  4. 1y

List keys

gpg> list
sec  rsa4096/0487C6AE38A74C12
     created: 2021-05-28  expires: 2022-05-28  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/2E180F6B22DFF0D0
     created: 2021-05-28  expires: 2022-05-28  usage: E
ssb  rsa4096/E641CAE29209F416
     created: 2021-05-28  expires: 2022-05-28  usage: A
[ultimate] (1). Magnus Svensson <masv@sunet.se>

gpg> save

Backup

When writing the keys to your card, gpg2 will delete the existing keys on your keyring and replace them with a stub. If you want a backup of the keys to store offline in a safe place, then now is the time to make a backup:

$ gpg --export-secret-key --armor > /Volumes/<USB_NAME>/secretkey.backup

$ gpg --output /Volumes/<USB_NAME>/revoke.asc.backup --gen-revoke <ID>

Export public key

You will also need to save your public key somewhere, so you can import it in your real GPG keyring. Something like $ gpg --armor --export <ID> > ~/my-public-key.asc

Card modifications

Change Admin PIN, PIN and set Reset Code

Type Default code
PIN 123456
Admin PIN 12345678

$ gpg --edit-card

  1. admin
  2. passwd

Follow the instructions...

Set card holder nam

$ gpg --edit-card

  1. name

Follow the instructions...

Write to card

Place each key (capability) on card. This is a general instruction.

$ gpg --edit-key <ID>

gpg> keytocard # primary key to card (Sign)

gpg> key 1

gpg> keytocard

gpg> key 1

gpg> key 2

gpg> keytocard

gpg> key 2

gpg> save

Import public key into the real keychain

$ unset GNUPGHOME

Kill gpg-agent.

$ gpg --import ~/my-public-key.asc

$ gpg --edit-key <ID>

gpg> trust

set 5

gpg> save

Verify keys on card

$ gpg -K
/Users/masv/.gnupg/pubring.kbx
------------------------------
sec>  rsa4096 2021-05-28 [SC] [expires: 2022-05-28]
      D0B2D9FF86A6B3A6314E632C5BA4BA8D2A3E5C61
      Card serial no. = 0006 10124562
uid           [ultimate] Magnus Svensson <masv@sunet.se>
ssb>  rsa4096 2021-05-28 [E] [expires: 2022-05-28]
ssb>  rsa4096 2021-05-28 [A] [expires: 2022-05-28]

Enable SSH support

$ echo "enable-ssh-support" >> ~/.gnupg/gpg-agent.conf

$ echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf

$ echo "export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)" >> ~/.zshrc

$ echo "gpgconf --launch gpg-agent" >> ~/.zshrc

$ gpg --export-ssh-key <ID> > ~/.ssh/id_rsa_yubikey.pub

Logout/login (Is this the only way of doing it?)

ssh-add -L lists ssh public-keys

Clean up RAMDisk

$ rm -Pr private-keys-v1.d/

$ rm -P pubring.kbx*

$ cd .. && rm -rf key_space/

$ sudo diskutil unmount force RAMDisk/

Enable Touch policies (Encouraged)

A touch policy takes advantage of the fact that the Yubikey is a HSM that can be restricted by touch activation.

$ ykman openpgp keys set-touch <AUT|SIG|ENC|ATT> ON

Note that attestation (ATT) is only available with YubiKey hardware version 4.3 and above.

Disable OTP to get rid of the string that is outputted everytime the key is touched

$ ykman config usb --disable OTP

Test sign

$ gpg --output /tmp/test_sign.sig --sign /tmp/test_sign

$ gpg --verify /tmp/test_sign.sig

Compare the returning key fingerprint with the sub key fingerprint with Sign capabilities, it should be equal.

$ gpg --list-keys --with-subkey-fingerprints

Test encrypt

$ gpg -e -r <YOUR_EMAIL> /tmp/test_encrypt.txt

$ gpg --decrypt /tmp/test_encrypt.txt.gpg

should return:

gpg: encrypted with rsa4096 key, ID <ENCRYPT_SUBKEY_ID>, created <DATE>
      "<NAME> <<EMAIL>>"
Linux instructions

Linux instructions

Ubuntu/Debian

# sudo apt-get install gnupg2 gnupg-agent gpgsm pcscd scdaemon

Add the following to $HOME/.gnupg/gpg-agent.conf. Don't forget to check the path to scdaemon.

scdaemon-program /usr/lib/gnupg/scdaemon
enable-ssh-support
# Enable debug logging if needed
#debug guru
#log-file /dev/shm/gpg-agent.log

Add the following to $HOME/.bashrc or equivalent

GPG_TTY=$(tty)
export GPG_TTY
# Set up ssh-agent socket as specified in gpg-agent(1) 
unset SSH_AGENT_PID 
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then 
    export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi

Disable OTP to get rid of the string that is outputted everytime the key is touched

$ ykman config usb --disable OTP

Set yubikey in CCID+HID-mode (old instruction)

From the factory the yubikey is setup only as a standard/classical OTP device. Run the following command to set it in dual HID (keyboard) and CCID mode. Resist the temptation to set it in CCID-only mode - you won't be able to use ykpersonalize again if you do.

# ykpersonalize -m82

If you failed to resist the temptation of CCID-mode you can expert-mode hack your NEO back to HID mode using this command:

$ opensc-tool -s '00 a4 04 00 07 a0 00 00 05 27 20 01 01' -s '00 01 11 00'

or, alledgedly, using the ykneomgr application found at http://opensource.yubico.com/libykneomgr/

If you want to use the token in a virtual machine (VMWare Fusion) when running OS X you can't use HID mode.

# ykpersonalize -m81

Setup user access to the yubikey USB device

This step might not be needed in all cases.

/etc/udev/rules.d/69-yubikey.rules

ACTION!="add|change", GOTO="yubico_end"

# Yubico Yubikey 4
ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0010|0110|0111|0112|0114|0116|0401|0403|0405|0406|0407|0410", \
    ENV{ID_SECURITY_TOKEN}="1", RUN+="/usr/sbin/service pcscd restart"

LABEL="yubico_end"

/etc/udev/rules.d/70-yubikey.rules

# Udev rules for letting the console user access the Yubikey USB
# device node, needed for challenge/response to work correctly.

ACTION=="add|change", SUBSYSTEM=="usb", \
  ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0010|0110|0111|0112|0114|0116|0401|0403|0405|0406|0407|0410", \
  TEST=="/var/run/ConsoleKit/database", \
  RUN+="udev-acl --action=$env{ACTION} --device=$env{DEVNAME}"

Disable GNOME Keyring's GnuPG and SSH agent emulation code

If you are using GNOME 3 and experience problems such as

# gpg2 --card-status
# gpg: OpenPGP card not available: general error

Or if you notice that you have two gpg-agents running, then you can try to disable the GNOME Keyring GnuPG/SSH agent using:

# echo 'X-GNOME-Autostart-enabled=false' >> /etc/xdg/autostart/gnome-keyring-gpg.desktop
# echo 'X-GNOME-Autostart-enabled=false' >> /etc/xdg/autostart/gnome-keyring-ssh.desktop
# echo 'X-GNOME-Autostart-enabled=false' >> /etc/xdg/autostart/gnome-keyring-pkcs10.desktop
# echo manual > /etc/xdg/systemd/gnome-keyring.override

Generate key outside card

Create some space in memory you can easily clean out later...

# umask 077
# cd /dev/shm

Create a tempdir for gnupg stuff

# mkdir foo
# cd foo

Create a gpg.conf in the foo directory containing:

default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
personal-digest-preferences SHA512
cert-digest-algo SHA512

Make sure gpg2 uses this directory and generate a key using the defaults (a 4096 bit RSA key) and set a 1 year validity.

# export GNUPGHOME=$PWD
# gpg2 --full-gen-key
[...]
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1 [enter]
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (4096) [enter]
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 [enter]
Key expires at ons 25 maj 2016 15:45:52 CEST
Is this correct? (y/N) y [enter]
[...]
Real name: Test Testsson [enter]
Email address: test@example.com [enter]
Comment: [enter] <--- Leave this field empty
You selected this USER-ID:
    "Test Testsson <test@example.com>"
    
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

Choose a strong password that is unique for this key and is made up of a random combination
of both upper and lower letters, as well as numbers.

Next edit the key in expert mode - $id is the id of the key you just created. Add your email addresses with adduid.

# gpg2 --edit-key --expert $id
gpg> adduid # until done

Now add 1 subkey to be used with SSH. Pick RSA (set your own capabilities) and toggle S & E & A which should result in only "Authenticate".

gpg> addkey
[...]
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 8 [enter]
    
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 [enter], E [enter], A [enter], Q [enter]
[...]
What keysize do you want? (4096) [enter] 
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 [enter]
Key expires at ons 25 maj 2016 16:34:06 CEST
Is this correct? (y/N) y [enter]
Really create? (y/N) y [enter]

This is what the result should look like.

gpg> list

pub  4096R/662D4043  created: 2013-10-01  expires: 2014-10-01  usage: SC
                 trust: ultimate      validity: ultimate
sub  4096R/FED803A7  created: 2013-10-01  expires: 2014-10-01  usage: E
sub  4096R/4334FEF8  created: 2013-10-01  expires: 2014-10-01  usage: A
[ unknown] (1)  Leif Johansson <leifj@nordu.net>
[ unknown] (2)  Leif Johansson <leifj@mnt.se>
[ unknown] (3). Leif Johansson <leifj@sunet.se>

Remember to save the changes when you exit edit mode using the command save.

gpg> save

When writing the keys to your card, gpg2 will delete the existing keys on your keyring and replace them with a stub. If you want a backup of the keys to store offline in a safe place, then now is the time to make a backup using either:

$ cp secring.gpg secring.gpg.backup
$ cp pubring.gpg pubring.gpg.backup
$ cp secring.gpg.backup pubring.gpg.backup /path/to/backup/media

Or by only exporting the secret key, including subkeys, to the offline backup:

$ gpg2 --export-secret-key --armor > /path/to/backup/media/secretkey.backup

You will also need to save your public key somewhere, so you can import it in your real GPG keyring. Something like

$ gpg2 --armor --export $id > ~/my-NEO-public-key.asc

Write key to card

Note that gpg2 might ask for the YubiKey admin pin (default 12345678) when moving the primary key.

# gpg2 --edit-key $id
gpg> toggle
gpg> keytocard
gpg> key 1
gpg> keytocard
gpg> key 1
gpg> key 2
gpg> keytocard

Do not forget to change the YubiKey admin pin (default 12345678), as well as the user pin (default 123456) to a strong password.

# gpg2 --card-edit
[...]
gpg/card> admin
Admin commands are allowed
    
gpg/card> passwd
[...]
    
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
    
Your selection? 1 [enter], 3 [enter], 4 [enter], Q [enter]

During this stage it is very important that only a gpg-agent with version >=2.0.22 is running. If you get errors like

gpg: error writing key to card: Not supported

it is probably not the right gpg-agent that is currently running. Kill any gpg-agent process and look in

/etc/X11/Xsession.d/90gpg-agent

for how to restart it with a gpg-agent binary that you are sure is >=2.0.22.

Tidy up before you forget

# cd /dev/shm/foo
# shred -zun 12 secring.gpg
# cd ..; rm foo -rf

Enable Touch policies (Encouraged)

A touch policy takes advantage of the fact that the Yubikey is a HSM that can be restricted by touch activation.

$ ykman openpgp keys set-touch <AUT|SIG|ENC|ATT> ON

Note that attestation (ATT) is only available with YubiKey hardware version 4.3 and above.

Test

Lets see what we have...

# gpg2 --card-status
gpg: WARNING: unsafe permissions on homedir `/dev/shm/foo'
gpg: detected reader `Yubico Yubikey NEO OTP+CCID 00 00'
Application ID ...: D2760001240102000000000000010000
Version ..........: 2.0
Manufacturer .....: test card
Serial number ....: 00000001
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: 2048R 2048R 2048R
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: F95F 1654 911B 8B21 68A1  EF18 6D13 20C7 662D 4043
Encryption key....: 609A 2FC8 5606 421D B848  14DF 3EC4 D983 FED8 03A7
Authentication key: E2A3 D430 532E F05B B37F  1822 966F 771E 4B6F EF82
General key info..: pub  2048R/662D4043 2013-10-01 Leif Johansson <leifj@sunet.se>
sec   2048R/662D4043  created: 2013-10-01  expires: 2014-10-01
ssb   2048R/FED803A7  created: 2013-10-01  expires: 2014-10-01
ssb   2048R/4B6FEF82  created: 2013-10-01  expires: 2014-10-01

Revoke old key if it is not going to be used

You can use the revoked key to verify old signatures, or decrypt data if you have not lost the private key, but it cannot be used to encrypt new messages to you.

gpg2 --output revocation-certificate.asc --gen-revoke '<fingerprint>'
[...]
Create a revocation certificate for this key? (y/N) y [enter]
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? 2 [enter]
[...]
        
gpg2 --import revocation-certificate.asc
gpg2 --send '<fingerprint>'