2018-07-03 01:05:34 +02:00
Title: Yubikey for EVERYTHING
2018-07-07 23:06:30 +02:00
Date: 2018-07-07T23:06+02:00
2018-07-03 01:05:34 +02:00
Author: Wxcafé
Category:
Slug: content/yubikey_for_everything
Header_Cover: //pub.wxcafe.net/img/yubikey_cover.jpeg
2018-07-07 23:06:30 +02:00
###### EDIT: Update 07/07/2018, added `SSH_AUTH_SOCK` information, a few pointers about key generation and backup, and info about gpg-agent's bad behavior.
2018-07-03 01:05:34 +02:00
When I first started at the job I'm currently at at [Gandi ](https://gandi.net ),
I was given a Yubikey NEO, looked into it for a few minutes and quickly decided
to not give more thought about it. I put it away and didn't look back, partly
because the `yubikey-personalization-gui` is maybe the most unusable and
unintelligible interface I've ever seen, and partly because I had a 4096 bit key
and didn't think to make smaller subkeys to put in the smartcard (the NEO only
supports 2048 bit keys).
A few weeks ago I decided to buy a Yubikey 4 on a drunken evening and got it in
the mail a few days later, having completely forgotten I had ordered it.
I decided to finally take a look at how this thing worked and what I could
actually do with it.
So, first things first. The Yubikey is basically a GPG smartcard, with an added
X.509 smartcard, WITH added U2F support. It can also be used to do TOTP/HOTP
with the Yubico app on android smartphones or computers. It can probably also be
programmed to solve quadratic equations, but I haven't tried.
To clarify: functionally, a smartcard is a device that has an integrated small
CPU and storage space for keys, and that you can only write keys to, not read
from. The integrated CPU can then be asked to sign/encrypt/decrypt arbitrary
data, but the keys can never be compromised from the key itself.
Anyway, my use case is as such: beforehand, I stored my GPG and SSH keys on my
everyday computers, but I couldn't use either of them on my work computers (I
didn't want to leave personal stuff like that on work equipment). I wanted to be
able to connect to my servers and ideally decrypt files on any computer
I encounter (okay, decrypting files on anyone's computer is not a great idea,
but there are a few computers I trust enough to decrypt files on them but not to
give them my private keys). I also use [pass ](https://www.passwordstore.org/ ) to
store my passwords, decrypting them with the yubikey everywhere is nice. Since
the key allows me to access my passwords, I feel like putting the second factor
of authentication on it just wouldn't be reasonable, so I'm still using my phone
as a 2fa TOTP source. Finally, I stored an X.509 cert for OpenVPN to try and see
how it would work with the yubikey. I'm not using it for now but it's there.
---
### GPG key storage
Anyways, here's how to use this thing:
- First, always keep a backup of your private keys. You'll need them to sign
other people's keys at keysigning parties, and if you lose the yubikey you'll
also need them to recover... well, everything. Anyway, keeping a good offline
backup or two is important.
- We're gonna start by adding our [GPG
subkeys](https://alexcabal.com/creating-the-perfect-gpg-keypair/) to the
2018-07-07 23:06:30 +02:00
yubikey. That article covers pretty much everything, *except* generating an
Authentication subkey, which is done by doing `gpg --expert --edit-key
< KeyID > `, then ` addkey`. You now need to select "(8) RSA (set your own
capabilities)" as the type of key, then type `S` to toggle signing off, `E` to
toggle encryption off, and finally `A` to toggle authentication on. Type `Q`
to confirm and quit, then keep as usual for the key size/expiration date/etc.
You're now done, and we can start by setting up the yubikey.
This is really easy, since the yubikey is detected as a smartcard by
2018-07-03 01:05:34 +02:00
gpg:
```
$ gpg --edit-card
gpg --card-status
Reader ...........: Yubico Yubikey 4 OTP U2F CCID 00 00
Application ID ...: D2760001240102010006076003030000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 07600303
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. D2760001240102010006076003030000 detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 3
PIN changed.
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? 1
Pin changed.
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection? q
gpg/card> url
URL to retrieve public key: https://pub.wxcafe.net/wxcafe.asc
gpg/card> name
Cardholder's surname: Hertling
Cardholder's given name: Clément
Error: Only plain ASCII is currently allowed.
Cardholder's given name: Clement
gpg/card> login
Login data (account name): wxcafe
gpg/card> sex
Sex ((M)ale, (F)emale or space): M
gpg/card> lang
Language preferences: en
gpg/card> list
Reader ...........: Yubico Yubikey 4 OTP U2F CCID 00 00
Application ID ...: D2760001240102010006076003030000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 07600303
Name of cardholder: Clement Hertling
Language prefs ...: en
Sex ..............: male
URL of public key : https://pub.wxcafe.net/wxcafe.asc
Login data .......: wxcafe
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
gpg/card> %
```
The default PINs are `123456` for the user PIN and `12345678` for the admin PIN.
Do take caution to export the private keys for safekeeping *BEFORE* moving them
to the yubikey (the gpg `keytocard` command *MOVES* the keys, after you've run it
2018-07-07 23:06:30 +02:00
*you don't have the private keys available anymore to backup*) (backups are
easily done with `gpg --armor --export-secret-keys <KeyID> > out.asc` and `gpg
--armor --export-secret-subkeys < KeyID > > subkeys_out.asc`. You obviously need
to save these to a secure location.)
2018-07-03 01:05:34 +02:00
Now that we've prepped the card, we're gonna move the keys over to it. We're
gonna move only the subkeys over, and since we're gonna need to use the yubikey
for everything we'll have an Encryption subkey, a Signing subkey and an
Authentication subkey.
```
$ gpg --edit-key wxcafe@wxcafe .net
gpg (GnuPG) 2.2.7; 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/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 1
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb* rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb* rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 1
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 2
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb* rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb* rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 2
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 3
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb* rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
sec rsa4096/58DD226B3EA71DC7
created: 2016-12-29 expires: 2019-06-18 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/11E99643DEE9E336
created: 2018-06-29 expires: 2019-06-29 usage: S
ssb rsa4096/E00F13324D0D1703
created: 2018-06-29 expires: 2019-06-29 usage: E
ssb* rsa4096/FD92FB8BD73D1D70
created: 2018-06-29 expires: 2019-06-29 usage: A
[ultimate] (1). Wxcafé < wxcafe @wxcafe .net >
[ultimate] (2) Wxcafé < wx cafe @wxcafe . net >
[ultimate] (3) Wxcafé < wxcaf e @wxcafe . net >
[ultimate] (4) Wxcafé < 🖕@fu .cking.network>
[ultimate] (5) [jpeg image of size 22243]
gpg> key 3
gpg> save
gpg> %
```
Now that this is done, we only need to `gpg --card-status` should show us this:
```
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240102010006076003030000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 07600303
Name of cardholder: Clement Hertling
Language prefs ...: en
Sex ..............: male
URL of public key : https://pub.wxcafe.net/wxcafe.asc
Login data .......: wxcafe
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 752F 1ED2 D038 BCB6 F09C A942 11E9 9643 DEE9 E336
created ....: 2018-06-29 22:27:20
Encryption key....: 37B4 4050 8744 344C 0975 2656 E00F 1332 4D0D 1703
created ....: 2018-06-29 22:28:22
Authentication key: 775D 1613 1B3F FEE7 843F D3BC FD92 FB8B D73D 1D70
created ....: 2018-06-29 22:29:29
General key info..: sub rsa4096/11E99643DEE9E336 2018-06-29 Wxcafé < wxcafe @wxcafe .net >
sec# rsa4096/58DD226B3EA71DC7 created: 2016-12-29 expires: 2019-06-18
ssb> rsa4096/11E99643DEE9E336 created: 2018-06-29 expires: 2019-06-29
card-no: 0006 07600303
ssb> rsa4096/E00F13324D0D1703 created: 2018-06-29 expires: 2019-06-29
card-no: 0006 07600303
ssb> rsa4096/FD92FB8BD73D1D70 created: 2018-06-29 expires: 2019-06-29
card-no: 0006 07600303
```
To actually use the keys we just copied over, we need to install a smarcard
daemon (`apt install scdaemon` ) and authorize our user to access it. For that we
write a udev rule in (`/etc/udev/rules.d/70-yubikey.conf` ) with this in it:
https://raw.githubusercontent.com/Yubico/libu2f-host/master/70-u2f.rules
Now we should be able to use the yubikey to sign and encrypt whatever we want!
We can test this by doing `touch test; gpg -a --sign test` , which should prompt us
for the yubikey PIN and then create the `test.asc` file.
We can still do `gpg --export-secret-keys <key-id>` , and while it looks like it
works (because GPG's output is undecipherable and it's UX is the worst thing
I've ever seen), it actually outputs "stubs", which allows a system to "see" the
keys on the card. They're not needed anymore since for a while now, gpg
--card-status automatically detects the keys on the card.
Now we want to use our gpg authentication key with SSH, to log in to our
servers. To do that, we need to tell gpg-agent to act as an ssh-agent, by adding
a single line to its configuration: `echo 'enable-ssh-support' >>
2018-07-07 23:06:30 +02:00
.gnupg/gpg-agent.conf`. Then we restart gpg-agent (` gpgconf --kill gpg-agent`).
Then, we need to tell ssh to use gpg-agent's socket as its agent. We do this by
adding a small snippet to our `$shrc` (for me, `~/.zshrc` ):
```shell
## use gpg agent as ssh agent
if which gpgconf 2>& 1 >>/dev/null ; then
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi
fi
```
Unplug the key, plug it back in, run `gpg --card-status` ,
2018-07-03 01:05:34 +02:00
then `ssh-add -L` should show you a public key that ends with
`cardno:xxxxxxxxxxxx` . That means it's done, you can now add this public key to
`.ssh/authorized_keys` on your remote systems and you should be able to log in
with that key.
2018-07-07 23:06:30 +02:00
Oh, and, side note. `gpg-agent` won't actually delete your cached keys when you
`ssh-add -D` , which is fucking bullshit, but in the meantime the solution is to
`gpg-connect-agent` , then `KEYINFO --ssh-list --ssh-fpr` to list the cached
keys, and then you can `DELETE_KEY <FINGERPRINT>` that particular key, with the
fingerprint being the part right after KEYINFO. Quit by saying `/bye`
2018-07-03 01:05:34 +02:00
---
### X.509 key and certificate storage
Now for the X.509 storage, this is a bit easier. You will need to make a pkcs12
out of your certificate and associated key (`openssl pkcs12 -export -out out.p12
-inkey key.pem -in cert.crt --certfile ca.crt -nodes`), and then we can import
it into the yubikey (this will not destroy the .p12 file, nor the key or cert,
because this has a sensible UX, as opposed to gnupg): `yubico-piv-tool -s 9c -i
out.p12 -K PKCS12 -a import-key -a import-cert -k`
In my case, I was using this with OpenVPN, so I needed to install opensc-pkcs11
(which is a library that allows applications to see certificates from
a smartcard), then to look up under which ID OpenVPN saw my certificate with
`openvpn --show-pkcs11-ids /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so` . After
that, I updated my OpenVPN configuration by replacing the cert and key lines
with
```
pkcs11-id 'piv_II/PKCS\x2315\x20emulated/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
pkcs11-providers /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
```
And then it worked like a charm! What actually stopped me is that I use
networkmanager on my machines since `wicd` is dead, and it doesn't support that
kind of config. Of course, wicd would since it can launch arbitrary scripts...
but I'm stuck with NM and so I can't use this easily, sadly.
---
### Pass
So, technically [pass ](https://www.passwordstore.org/ ) is not related to the
yubikey at all, and doesn't directly interact with it. If you haven't heard
about it, it's a simple password manager for unix written in bash by
[zx2c4 ](https://www.zx2c4.com/ ). *But* it uses GPG as an encryption mechanism,
and since I was moving towards using GPG to authenticate SSH connections,
I thought I might as well start using pass with the yubikey. So, here goes.
Pass is a very simple password manager, so simple that all it does is keep your
passwords for you and output them when you ask nicely. It's installed on
basically all systems with the package manager (in my case, `apt install pass` ),
and then it's a matter of `pass init <keyid>` to initialize the folder with the
specified gpg key id, `pass git init` and `pass git remote add origin <remote>`
to use git to store the passwords (that's optional, but it's so much better it'd
be dumb not to do it...). Then you can add a password with `pass insert <path>` ,
or generate one with `pass generate <path> <length>` . Don't forget to `pass git
push` (it'll commit automatically if it's in git).
To see all the passwords you have in pass, use `pass ls` , and to read a specific
password use `pass <path>` . The problem with that is that the password is
written to stdout, and we don't really want to a) have people able to snoop the
password, nor b) open a terminal and copy-paste every time we want to get
a password. That's where passmenu comes in! It's a simple script included with
pass (at least it is in debian) in
`/usr/share/doc/pass/examples/dmenu/passmenu` , and it relies on dmenu to show
you all of your passwords. From there, you can type a few letters and select
which password you want, and once you confirm your selection it will copy it
into your clipboard, ready for you to paste into any password field. There are
extensions to have it support TOTP and other stuff too, but as previously I'm
not too comfortable with putting all my eggs in the same basket.
So yeah, move all your passwords to pass and make them as complex as possible!
When you get to a new machine you can simply `git clone <repo> ~/.password-store`
and `apt install pass` and you're all set! Don't lose your GPG key though, or
you're **_SCREWED_** .
Don't lose it. Ever. Print it out and put it in the bank. Whatever. But don't
lose it.
Anyway, that was it! I'm seriously happy with how this solution works for me,
and how secure it is without sacrificing much towards usability, even improving
it in most cases.
(P.S.: I don't get anything by saying this, but my employer (gandi) has
a partnership thing in place with yubico, such that if you login on [this
page](https://www.yubico.com/solutions/gandi/) with a gandi account, you get 20%
off your yubikey. You don't even need to buy anything with gandi afaik, only to
have an account)