The perfect password manager¶
TL;DR: Use a Yubikey 4 with touch-to-sign to store your GPG keys, and use these keys for SSH authentication and storing your secrets with password-store.
The problem¶
For a long time, I’ve been searching for a robust and secure way to store my passwords, and secrets in general (SSH and GPG keys, personal files…)
There is one thing that bothered me in all the solutions I knew about, be it a software like KeePass, or a cloud solution like LastPass: if my computer is compromised at some point in time, it will be possible to extract all of my secrets when I open my vault to access one.
In that regard, a piece of paper in my wallet would be much more secure, as my computer would only know the secrets I copy over when I need them.
The only device solving that problem is the mooltipass, an external device containing all your passwords that can simulate a keyboard and type them when you need them. It’s an interesting device, completely open source, and you should definitely check it out.
But there is an alternative I want to talk about, based on the well-known Yubikey, plus a combination of tools that fit all my needs, not only for storing password but also to connect to remote SSH servers and decrypt/sign PGP messages, while giving me strong security guarantees.
The solution¶
In the true Unix fashion, I use a combination of tools doing a simple job each. Let’s start with the password manager:
GPG for your password manager: password-store¶
As you probably guessed in the title, it all rests on GPG and we’ll see later how we secure these GPG keys.
But for now, let’s introduce a tool called password-store.
It’s a pretty simple wrapper around GPG (a bash script, in fact) that allows you to store each of your secret in a GPG-encrypted file.
The GPG key that you use for storing your password will be required each time that you access a password. Because it’s public key cryptography, it means that you can create new passwords without needing to access your key!
In term of security, well, it’s GPG. Each of your secret is stored in a file in your home directory, so it’s up to you to do backups. But it’s all neat and simple :)
zx2c4@laptop ~ $ pass
Password Store
├── Business
│ ├── some-silly-business-site.com
│ └── another-business-site.net
├── Email
│ ├── donenfeld.com
│ └── zx2c4.com
└── France
├── bank
├── freebox
└── mobilephone
There are even browser extensions (firefox, chrome), to integrate password-store!
GPG for your SSH keys: gpg-agent¶
I also want to do a quick disgression, and tell you that you can use GPG not only to store your password, but to authenticate to remote servers.
Moreover, you can use key forwarding (so that in these servers, you can access the SSH keys from your local machine and connect to other machines in turn) without much risk of the server using them in your back: all the uses will require you to touch your Yubikey!
For example, I connect to my server using my Yubikey, and on that remote server I can copy files to another server, or push code to my git repository by touching my Yubikey too. For all that, I don’t have to type a single password.
For that you need to replace your SSH agent by gpg-agent, it’s all explained in the appendix.
Secure GPG key storage: Yubikey¶
Some of you may already have heard of Yubikeys. The idea is to have a Yubikey storing GPG keys that you generated on an air-gapped computer.
It primarily serve for second-factor authentication, but here we will only focus on its GPG smartcard function.
Once you set it up, GPG will connect to your Yubikey each time it needs to access to your secret key. The Yubikey will do all the cryptographic work, so that your secret key never leaves it. In case your computer is compromised, an attacker can only use your secret key if your Yubikey is connected and unlocked.
This was not satisfying for me yet, because it meant that if I connect and unlock my Yubikey, a compromised computer can tell the Yubikey to decrypt all my secret files, connect to all my servers… without me noticing: pretty bad.
That’s where the last generation of Yubikeys (Yubikey 4) have a feature that went relatively unpublicized: you can have them require the user to touch it everytime an operation on the secret key is requested. This means that it’s impossible to access your secrets without you physically allowing it!
When combined with the tools above you will need to touch your Yubikey every time you want to access one of your password, decrypt or sign a GPG message, or connect to your server. Without you having unlocked, and touching your Yubikey, it becomes impossible to connect to your servers or access your passwords. Even if your computer is fully compromised.
Conclusion¶
I find this solution very secure, and quite easy to use and non-intrusive.
Also, to contradict the title of this article, here are a few security caveats I could think of:
Even though it’s not possible to access your secrets, it’s still possible to replace them, because the public key encryption doesn’t require any secret. This could be fixed by forcing all your secret files to be signed by your secret key.
In case your computer is compromised, it could be possible to ask your Yubikey to do something else than what you intented, but then you would need to touch it twice, and will probably notice it :)
Oh, and sadly, the newer version of the Yubikey (the 4, with touch-to-sign) doesn’t have an open source firmware…
But compared to the other solutions I know, I think these are quite minor, and that there is a much better security overall.
Appendix: let’s do it!¶
Generate your PGP keys¶
Master key¶
For this scheme to be secure, you need to generate your GPG keys on a secure computer, disconnected from the internet. Or at least from a live CD, or something you can trust better than your day-to-day computer.
Once you are on this secure, throwaway system, use gpg to generate a master key (if you don’t have one already).
$ gpg --gen-key
Generate a sign only key (the rest will go into our subkeys).
I suggest that you use all the defaults, but that you set an expiration date in case you would loose your key (a few years into the future).
As long as you are in a secure system and you don’t plan to copy your secret key anywhere (except to an encrypted, offline storage, as explained below), you can leave the password used to protect the key empty.
Sub-keys¶
Now that you have your master key, let’s add three sub-keys: these will go to your Yubikey.
$ gpg --expert --edit-key palkeo
Replace “palkeo” by the name that you provided for your master key, or the key ID
you can see by doing gpg --list-secret-keys
.
You should now have GPG prompt: gpg>
.
You will use this prompt to create three subkeys.
One for encryption: to decrypt GPG messages you receive, including your secrets in password-store.
One for signature: to sign GPG messages you send.
One for authentication: mainly for SSH authentication.
Let’s see how to create the encryption key, for example:
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
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
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 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) 5y
Key expires at Wed Dec 8 22:56:10 2021 UTC
Is this correct? (y/N) y
Really create? (y/N) y
...
pub 2048R/A41164CD created: 2016-12-09 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/D7857578 created: 2016-12-09 expires: 2021-12-08 usage: E
gpg>
You can see that I toggled the capabilities until there is only encryption left:
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt
Repeat the process with the addkey
command again, but this time leaving
the Sign
capability left.
Do it one last time, for the Authenticate
capability.
You should now have three sub-keys. These will go to your Yubikey soon.
Backup time¶
Now is backup time, don’t neglect this step!
Export your secret key and subkeys, like that:
$ gpg -a --export-secret-keys A41164CD > key.txt
$ gpg -a --export-secret-subkeys A41164CD > subkeys.txt
Now copy these files to a secure storage. It should be offline, so that your computer can’t access it, and you probably also want to encrypt it. But you should be able to access it in case you lose your Yubikey, and want to export the keys to a new one.
I also recommend that you make a copy of the ~/.gnupg
directory that you
used to generate these keys.
Setup your Yubikey¶
Once you have your Yubikey, it’s time to set it up:
Smartcard setup¶
Note
Because you are accessing/copying your secret keys, this is to be done on an offline/secure computer again. I recommend you generate the keys and copy them at once, when you have your Yubikey.
First of all, most of the articles I could find mention the use of ykpersonalize
to enable GPG on the Yubikey. I found out it’s not needed (at least for the
Yubikey 4), as it’s enabled by default (U2F too).
You now need to install the smartcard support in GPG:
$ sudo apt-get install scdaemon pcscd gnupg-agent
Now you can plug your Yubikey, and execute gpg --card-status
. You should
see something like:
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240102010006050314690000
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 05031469
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]
Let’s set it up:
$ gpg --card-edit
... (same as above) ...
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? 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> quit
You will be asked for the original admin PIN, which is 12345678. Same for the original PIN, which is 123456.
Make sure that your new admin PIN is secret/unguessable. You can store a backup along with your GPG keys. It’s only used to administrate the Yubikey GPG smartcard.
The “normal” PIN is the one you will have to type to unlock your Yubikey, when you connect it to your computer. The goal is to prevent someone stealing your Yubikey to impersonate you.
GPG keys setup¶
Now, let’s move the keys to your Yubikey:
$ gpg --edit-key palkeo
pub 2048R/A41164CD created: 2016-12-09 expires: 2021-12-08 usage: SC
trust: ultimate validity: ultimate
sub 2048R/486B21CF created: 2016-12-09 expires: 2021-12-08 usage: S
sub 2048R/D7857578 created: 2016-12-09 expires: 2021-12-08 usage: E
sub 2048R/DA1E5137 created: 2016-12-09 expires: 2021-12-08 usage: A
[ultimate] (1). palkeo
gpg> toggle
sec 3744R/1C5C4717 created: 2016-12-09 expires: 2021-12-08
ssb 2048R/486B21CF created: 2016-12-09 expires: 2021-12-08
ssb 2048R/A11F46D2 created: 2016-12-09 expires: 2021-12-08
ssb 2048R/DA1E5137 created: 2016-12-09 expires: 2021-12-08
(1) palkeo
gpg> key 1
sec 3744R/1C5C4717 created: 2016-12-09 expires: 2021-12-08
ssb* 2048R/486B21CF created: 2016-12-09 expires: 2021-12-08
ssb 2048R/A11F46D2 created: 2016-12-09 expires: 2021-12-08
ssb 2048R/DA1E5137 created: 2016-12-09 expires: 2021-12-08
(1) palkeo
gpg> keytocard
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
sec 3744R/1C5C4717 created: 2016-12-09 expires: 2021-12-08
ssb* 2048R/486B21CF created: 2016-12-09 expires: 2012-12-08
card-no: 0060 00000042
ssb 2048R/A11F46D2 created: 2016-12-09 expires: 2012-12-08
ssb 2048R/DA1E5137 created: 2016-12-09 expires: 2012-12-08
(1) palkeo
gpg>
This is an example moving my signature key to my Yubikey. Note that the key is moved (that’s why you need to have done backups before!), and replaced by a stub pointing to unique identifier of the smartcard.
You need to reproduce that process again two times, to move the two other keys
too (use the key
command to deselect the key 1, select the key 2…).
Once it’s done, do a gpg --card-status
to check that your keys were
sucessfully moved to your Yubikey.
Touch-to-sign setup¶
We also need to enable the functionality forcing you to touch your Yubkey when a cryptographic operation is requested.
It’s quite granular, as this flag is set per key slot. But I recommend that you set it to all your three keys.
This link contains all
the information you need. It points to a yubitouch.sh
script that you
have to download and run to enable this feature.
Have your machines use the Yubikey¶
For your machines to use your Yubikey, you need to export your public keys on your offline system:
$ gpg -a --export palkeo > public-key.txt
Move that file (and only this one, not your secret keys!) to your day-to-day machine, and import it like that:
$ gpg --import < public-key.txt
That’s it, you are all set, and you should now be able to transparently use your Yubikey to encrypt/sign GPG messages :)
Setup password-store¶
Once you have GPG set up to use your Yubikey, password-store is trivial to use:
First, you have to initialize it, by passing the ID of your master key:
pass init 1C5C4717
Then, you are free to add new passwords with pass insert
. Remember that
it won’t ask you for your Yubikey when you add passwords
(only when you access them).
Note
If you use pass edit
to edit your secrets in your preferred text editor,
be aware that they are unencrypted to a temporary directory
and that your text editor may backup the file elsewhere, while it’s unencrypted!
If you use vim, there is a plugin
that you can install to avoid that. There are also other interesting scripts
in the contrib/ directory of password-store.
Use your key for SSH authentication¶
We will use the GPG agent to replace the SSH agent.
First, you have to enable that support in the GPG agent:
echo enable-ssh-support >> $HOME/.gnupg/gpg-agent.conf
Then, start the agent:
eval `gpg-agent --daemon`
This has the side-effect of setting environment variables like SSH_AUTH_SOCK
.
You will also have to make sure you start it at the beginning of each session, or at each login if it’s not started already.
You should see your shiny new SSH key by doing ssh-add -l
.
Note that using ssh-add -L
will give it in a format that’s ready to add
to the authorized_keys
file on a remote host.
An important reminder¶
I just wanted to remind you these two things, that are on the basis of all this:
Make sure that the admin PIN of your Yubikey is set up and stored offline with your secret keys: with it, it become possible to disable touch-to-sign.
You need to make sure that you always have an offline backup of the secret key that’s on your Yubikey, so that if you lose it you still have a way to copy that secret key to a new Yubikey, and access your encrypted passwords securely again.