Create README.md
parent
6f1fcddea1
commit
172a4292a5
|
@ -0,0 +1,897 @@
|
||||||
|
This is a guide to using YubiKey as a SmartCard for storing GPG keys.
|
||||||
|
|
||||||
|
An authentication key can also be created for SSH using gpg-agent.
|
||||||
|
|
||||||
|
Keys stored on a smartcard like YubiKey seem more difficult to steal than ones stored on disk, and are convenient for everyday use.
|
||||||
|
|
||||||
|
Instructions written on Debian GNU/Linux 8 (jessie) using YubiKey 4 in OTP+CCID mode.
|
||||||
|
|
||||||
|
Debian live install images are available from [here](https://www.debian.org/CD/live/) and are suitable for writing to USB keys.
|
||||||
|
|
||||||
|
If you have a comment or suggestion, please open an issue on GitHub.
|
||||||
|
|
||||||
|
- [Purchase YubiKey](#purchase-yubikey)
|
||||||
|
- [Install required software](#install-required-software)
|
||||||
|
- [Creating keys](#creating-keys)
|
||||||
|
- [Create temporary working directory for GPG](#create-temporary-working-directory-for-gpg)
|
||||||
|
- [Create configuration](#create-configuration)
|
||||||
|
- [Create master key](#create-master-key)
|
||||||
|
- [Create revocation certificate](#create-revocation-certificate)
|
||||||
|
- [Back up master key](#back-up-master-key)
|
||||||
|
- [Create subkeys](#create-subkeys)
|
||||||
|
- [Signing key](#signing-key)
|
||||||
|
- [Encryption key](#encryption-key)
|
||||||
|
- [Authentication key](#authentication-key)
|
||||||
|
- [Check your work](#check-your-work)
|
||||||
|
- [Export subkeys](#export-subkeys)
|
||||||
|
- [Back up everything](#back-up-everything)
|
||||||
|
- [Configure YubiKey](#configure-yubikey)
|
||||||
|
- [Configure smartcard](#configure-smartcard)
|
||||||
|
- [Change PINs](#change-pins)
|
||||||
|
- [Set optional card information](#set-optional-card-information)
|
||||||
|
- [Transfer keys](#transfer-keys)
|
||||||
|
- [Signature key](#signature-key)
|
||||||
|
- [Encryption key](#encryption-key-1)
|
||||||
|
- [Authentication key](#authentication-key-1)
|
||||||
|
- [Check your work](#check-your-work-1)
|
||||||
|
- [Export public key](#export-public-key)
|
||||||
|
- [Using keys](#using-keys)
|
||||||
|
- [Insert YubiKey](#insert-yubikey)
|
||||||
|
- [Import public key](#import-public-key)
|
||||||
|
- [Trust master key](#trust-master-key)
|
||||||
|
- [GnuPG](#gnupg)
|
||||||
|
- [Encryption/decryption](#encryptiondecryption)
|
||||||
|
- [Signing](#signing)
|
||||||
|
- [SSH](#ssh)
|
||||||
|
- [Create configuration](#create-configuration-1)
|
||||||
|
- [Replace ssh-agent with gpg-agent](#replace-ssh-agent-with-gpg-agent)
|
||||||
|
- [Copy public key to server](#copy-public-key-to-server)
|
||||||
|
- [Connect with public key authentication](#connect-with-public-key-authentication)
|
||||||
|
- [Notes](#notes)
|
||||||
|
- [References](#references)
|
||||||
|
|
||||||
|
# Purchase YubiKey
|
||||||
|
|
||||||
|
https://www.yubico.com/products/yubikey-hardware/
|
||||||
|
|
||||||
|
https://www.yubico.com/store/
|
||||||
|
|
||||||
|
https://www.amazon.com/Yubico/b/ref=bl_dp_s_web_10358012011?ie=UTF8&node=10358012011
|
||||||
|
|
||||||
|
Consider purchasing a pair and programming both in case of loss or damage.
|
||||||
|
|
||||||
|
# Install required software
|
||||||
|
|
||||||
|
$ sudo apt-get install gnupg-agent pinentry-curses scdaemon pcscd yubikey-personalization
|
||||||
|
|
||||||
|
# Creating keys
|
||||||
|
|
||||||
|
## Create temporary working directory for GPG
|
||||||
|
|
||||||
|
$ export GNUPGHOME=$(mktemp -d) ; echo $GNUPGHOME
|
||||||
|
/tmp/tmp.EBbMfyVDDt
|
||||||
|
|
||||||
|
## Create configuration
|
||||||
|
|
||||||
|
$ cat > $GNUPGHOME/gpg.conf
|
||||||
|
use-agent
|
||||||
|
personal-cipher-preferences AES256 AES192 AES CAST5
|
||||||
|
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
|
||||||
|
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
|
||||||
|
cert-digest-algo SHA512
|
||||||
|
s2k-digest-algo SHA512
|
||||||
|
charset utf-8
|
||||||
|
fixed-list-mode
|
||||||
|
no-comments
|
||||||
|
no-emit-version
|
||||||
|
keyid-format 0xlong
|
||||||
|
list-options show-uid-validity
|
||||||
|
verify-options show-uid-validity
|
||||||
|
with-fingerprint
|
||||||
|
^D (Press Control-D)
|
||||||
|
|
||||||
|
## Create master key
|
||||||
|
|
||||||
|
$ gpg --gen-key
|
||||||
|
gpg (GnuPG) 1.4.18; Copyright (C) 2014 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)
|
||||||
|
Your selection? 4
|
||||||
|
RSA keys may be between 1024 and 4096 bits long.
|
||||||
|
What keysize do you want? (2048) 4096
|
||||||
|
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) 0
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
|
||||||
|
You need a user ID to identify your key; the software constructs the user ID
|
||||||
|
from the Real Name, Comment and Email Address in this form:
|
||||||
|
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
|
||||||
|
|
||||||
|
Real name: Doctor Duh
|
||||||
|
Email address: drduh@users.noreply.github.com
|
||||||
|
Comment:
|
||||||
|
You selected this USER-ID:
|
||||||
|
"Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
|
||||||
|
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
|
||||||
|
You need a Passphrase to protect your secret key.
|
||||||
|
|
||||||
|
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: /tmp/tmp.eBbMfyVDDt/trustdb.gpg: trustdb created
|
||||||
|
gpg: key 0x47FE984F98EE7407 marked as ultimately trusted
|
||||||
|
public and secret key created and signed.
|
||||||
|
|
||||||
|
gpg: checking the trustdb
|
||||||
|
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
|
||||||
|
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
|
||||||
|
pub 4096R/0x47FE984F98EE7407 2016-01-30
|
||||||
|
Key fingerprint = 044C ABD0 9043 F1E0 3785 3979 47FE 984F 98EE 7407
|
||||||
|
uid [ultimate] Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
Note that this key cannot be used for encryption. You may want to use
|
||||||
|
the command "--edit-key" to generate a subkey for this purpose.
|
||||||
|
|
||||||
|
## Create revocation certificate
|
||||||
|
|
||||||
|
$ gpg --gen-revoke 0x47FE984F98EE7407 --output $GNUPGHOME/revoke.txt
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 2016-01-30 Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
Create a revocation certificate for this key? (y/N) y
|
||||||
|
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? 1
|
||||||
|
Enter an optional description; end it with an empty line:
|
||||||
|
>
|
||||||
|
Reason for revocation: Key has been compromised
|
||||||
|
(No description given)
|
||||||
|
Is this okay? (y/N) y
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x47FE984F98EE7407, created 2016-01-30
|
||||||
|
|
||||||
|
ASCII armored output forced.
|
||||||
|
Revocation certificate created.
|
||||||
|
|
||||||
|
Please move it to a medium which you can hide away; if Mallory gets
|
||||||
|
access to this certificate he can use it to make your key unusable.
|
||||||
|
It is smart to print this certificate and store it away, just in case
|
||||||
|
your media become unreadable. But have some caution: The print system of
|
||||||
|
your machine might store the data and make it available to others!
|
||||||
|
|
||||||
|
## Back up master key
|
||||||
|
|
||||||
|
$ gpg --armor --export-secret-keys 0x47FE984F98EE7407 > $GNUPGHOME/master.key
|
||||||
|
|
||||||
|
## Create subkeys
|
||||||
|
|
||||||
|
$ gpg --expert --edit-key 0x47FE984F98EE7407
|
||||||
|
|
||||||
|
gpg (GnuPG) 1.4.18; Copyright (C) 2014 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.
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: ultimate
|
||||||
|
[ultimate] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Signing key
|
||||||
|
|
||||||
|
gpg> addkey
|
||||||
|
Key is protected.
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x47FE984F98EE7407, created 2016-01-30
|
||||||
|
|
||||||
|
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? 4
|
||||||
|
RSA keys may be between 1024 and 4096 bits long.
|
||||||
|
What keysize do you want? (2048) 4096
|
||||||
|
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) 0
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
Really create? (y/N) 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.
|
||||||
|
.....+++++
|
||||||
|
.+++++
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: ultimate
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
[ultimate] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Encryption key
|
||||||
|
|
||||||
|
gpg> addkey
|
||||||
|
Key is protected.
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x47FE984F98EE7407, created 2016-01-30
|
||||||
|
|
||||||
|
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? 6
|
||||||
|
RSA keys may be between 1024 and 4096 bits long.
|
||||||
|
What keysize do you want? (2048) 4096
|
||||||
|
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) 0
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
Really create? (y/N) 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.
|
||||||
|
|
||||||
|
.+++++
|
||||||
|
...........+++++
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: ultimate
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
[ultimate] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Authentication key
|
||||||
|
|
||||||
|
gpg> addkey
|
||||||
|
Key is protected.
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x47FE984F98EE7407, created 2016-01-30
|
||||||
|
|
||||||
|
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? e
|
||||||
|
|
||||||
|
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||||
|
Current allowed actions:
|
||||||
|
|
||||||
|
(S) Toggle the sign capability
|
||||||
|
(E) Toggle the encrypt capability
|
||||||
|
(A) Toggle the authenticate capability
|
||||||
|
(Q) Finished
|
||||||
|
|
||||||
|
Your selection? a
|
||||||
|
|
||||||
|
Possible actions for a RSA key: Sign Encrypt Authenticate
|
||||||
|
Current allowed actions: Authenticate
|
||||||
|
|
||||||
|
(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) 4096
|
||||||
|
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) 0
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
Really create? (y/N) 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.
|
||||||
|
|
||||||
|
+++++
|
||||||
|
.....+++++
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: ultimate
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
sub 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never usage: A
|
||||||
|
|
||||||
|
[ultimate] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> save
|
||||||
|
|
||||||
|
## Check your work
|
||||||
|
|
||||||
|
$ gpg --list-secret-keys
|
||||||
|
/tmp/tmp.eBbMfyVDDt/secring.gpg
|
||||||
|
-------------------------------
|
||||||
|
sec 4096R/0x47FE984F98EE7407 2016-01-30
|
||||||
|
Key fingerprint = 044C ABD0 9043 F1E0 3785 3979 47FE 984F 98EE 7407
|
||||||
|
uid Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 2016-01-30
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C 2016-01-30
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 2016-01-30
|
||||||
|
|
||||||
|
## Export subkeys
|
||||||
|
|
||||||
|
$ gpg --armor --export-secret-keys 0x47FE984F98EE7407 > $GNUPGHOME/mastersub.key
|
||||||
|
|
||||||
|
$ gpg --armor --export-secret-subkeys 0x47FE984F98EE7407 > $GNUPGHOME/sub.key
|
||||||
|
|
||||||
|
## Back up everything
|
||||||
|
|
||||||
|
Once keys are moved to hardware, they cannot be extracted again (otherwise, what would be the point?), so make sure you have made a backup before proceeding.
|
||||||
|
|
||||||
|
$ cp -avi $GNUPGHOME /mnt/offline-encrypted-usb/backup/
|
||||||
|
|
||||||
|
## Configure YubiKey
|
||||||
|
|
||||||
|
$ ykpersonalize -m82
|
||||||
|
Firmware version 4.2.7 Touch level 527 Program sequence 4
|
||||||
|
|
||||||
|
The USB mode will be set to: 0x82
|
||||||
|
|
||||||
|
Commit? (y/n) [n]: y
|
||||||
|
|
||||||
|
>The -m option is the mode command. To see the different modes, enter ykpersonalize –help. Mode 82 (in hex) enables the YubiKey NEO as a composite USB device (HID + CCID) and allows OTPs to be emitted while in use as a smart card. Once you have changed the mode, you need to re-boot the YubiKey – so remove and re-insert it.
|
||||||
|
|
||||||
|
https://www.yubico.com/2012/12/yubikey-neo-openpgp/
|
||||||
|
|
||||||
|
## Configure smartcard
|
||||||
|
|
||||||
|
$ gpg --card-edit
|
||||||
|
|
||||||
|
Application ID ...: D2760001240102010006055532110000
|
||||||
|
Version ..........: 2.1
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: 05553211
|
||||||
|
Name of cardholder: [not set]
|
||||||
|
Language prefs ...: [not set]
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: [not set]
|
||||||
|
Private DO 1 .....: [not set]
|
||||||
|
Private DO 2 .....: [not set]
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: 2048R 2048R 2048R
|
||||||
|
Max. PIN lengths .: 127 127 127
|
||||||
|
PIN retry counter : 3 3 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: [none]
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
General key info..: [none]
|
||||||
|
|
||||||
|
### Change PINs
|
||||||
|
|
||||||
|
The default PIN codes are `12345678` and `123456`.
|
||||||
|
|
||||||
|
gpg/card> admin
|
||||||
|
Admin commands are allowed
|
||||||
|
|
||||||
|
gpg/card> passwd
|
||||||
|
gpg: OpenPGP card no. D2760001240102010006055532110000 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### Set optional card information
|
||||||
|
|
||||||
|
gpg/card> name
|
||||||
|
Cardholder's surname: Duh
|
||||||
|
Cardholder's given name: Dr
|
||||||
|
|
||||||
|
gpg/card> lang
|
||||||
|
Language preferences: en
|
||||||
|
|
||||||
|
gpg/card> login
|
||||||
|
Login data (account name): drduh@users.noreply.github.com
|
||||||
|
|
||||||
|
gpg/card>
|
||||||
|
|
||||||
|
Application ID ...: D2760001240102010006055532110000
|
||||||
|
Version ..........: 2.1
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: 05553211
|
||||||
|
Name of cardholder: Dr Duh
|
||||||
|
Language prefs ...: en
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: drduh@users.noreply.github.com
|
||||||
|
Private DO 4 .....: [not set]
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: 2048R 2048R 2048R
|
||||||
|
Max. PIN lengths .: 127 127 127
|
||||||
|
PIN retry counter : 3 3 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: [none]
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
General key info..: [none]
|
||||||
|
|
||||||
|
gpg/card> quit
|
||||||
|
|
||||||
|
## Transfer keys
|
||||||
|
|
||||||
|
This is a one-way operation only. Make sure you've made a backup before proceeding!
|
||||||
|
|
||||||
|
$ gpg --edit-key 0x47FE984F98EE7407
|
||||||
|
gpg (GnuPG) 1.4.18; Copyright (C) 2014 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.
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: ultimate
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
sub 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never usage: A
|
||||||
|
|
||||||
|
[ultimate] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> toggle
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> key 1
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb* 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Signature key
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0xE8E7855AA5AE79A7, created 2016-01-30
|
||||||
|
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb* 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Encryption key
|
||||||
|
|
||||||
|
Type `key 1` again to deselect and switch to the next key.
|
||||||
|
|
||||||
|
gpg> key 1
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> key 2
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb* 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> keytocard
|
||||||
|
Signature key ....: 04CB BB4B 1D99 3398 A0B1 4C4B E8E7 855A A5AE 79A7
|
||||||
|
Encryption key....: [none]
|
||||||
|
Authentication key: [none]
|
||||||
|
|
||||||
|
Please select where to store the key:
|
||||||
|
(2) Encryption key
|
||||||
|
Your selection? 2
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x39988E0390CB4B0C, created 2016-01-30
|
||||||
|
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb* 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
### Authentication key
|
||||||
|
|
||||||
|
gpg> key 2
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> key 3
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb* 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> keytocard
|
||||||
|
Signature key ....: 04CB BB4B 1D99 3398 A0B1 4C4B E8E7 855A A5AE 79A7
|
||||||
|
Encryption key....: 8AB0 607B A1C1 0F19 2627 6EA6 3998 8E03 90CB 4B0C
|
||||||
|
Authentication key: [none]
|
||||||
|
|
||||||
|
Please select where to store the key:
|
||||||
|
(3) Authentication key
|
||||||
|
Your selection? 3
|
||||||
|
|
||||||
|
You need a passphrase to unlock the secret key for
|
||||||
|
user: "Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
4096-bit RSA key, ID 0x218BCF996C7A6E31, created 2016-01-30
|
||||||
|
|
||||||
|
|
||||||
|
sec 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb* 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
(1) Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> save
|
||||||
|
|
||||||
|
## Check your work
|
||||||
|
|
||||||
|
gpg --list-secret-keys
|
||||||
|
/tmp/tmp.eBbMfyVDDt/secring.gpg
|
||||||
|
-------------------------------
|
||||||
|
sec 4096R/0x47FE984F98EE7407 2016-01-30
|
||||||
|
Key fingerprint = 044C ABD0 9043 F1E0 3785 3979 47FE 984F 98EE 7407
|
||||||
|
uid Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
ssb> 4096R/0xE8E7855AA5AE79A7 2016-01-30
|
||||||
|
ssb> 4096R/0x39988E0390CB4B0C 2016-01-30
|
||||||
|
ssb> 4096R/0x218BCF996C7A6E31 2016-01-30
|
||||||
|
|
||||||
|
`ssb>` indicates a stub to the private key on smartcard.
|
||||||
|
|
||||||
|
## Export public key
|
||||||
|
|
||||||
|
$ gpg --armor --export 0x47FE984F98EE7407 > /mnt/public-usb-key/
|
||||||
|
|
||||||
|
# Using keys
|
||||||
|
|
||||||
|
## Insert YubiKey
|
||||||
|
|
||||||
|
$ gpg --card-status
|
||||||
|
Application ID ...: D2760001240102010006055532110000
|
||||||
|
Version ..........: 2.1
|
||||||
|
Manufacturer .....: unknown
|
||||||
|
Serial number ....: 05553211
|
||||||
|
Name of cardholder: Dr Duh
|
||||||
|
Language prefs ...: en
|
||||||
|
Sex ..............: unspecified
|
||||||
|
URL of public key : [not set]
|
||||||
|
Login data .......: drduh@users.noreply.github.com
|
||||||
|
Signature PIN ....: not forced
|
||||||
|
Key attributes ...: 4096R 4096R 4096R
|
||||||
|
Max. PIN lengths .: 127 127 127
|
||||||
|
PIN retry counter : 3 3 3
|
||||||
|
Signature counter : 0
|
||||||
|
Signature key ....: 04CB BB4B 1D99 3398 A0B1 4C4B E8E7 855A A5AE 79A7
|
||||||
|
created ....: 2016-01-30 16:36:40
|
||||||
|
Encryption key....: 8AB0 607B A1C1 0F19 2627 6EA6 3998 8E03 90CB 4B0C
|
||||||
|
created ....: 2016-01-30 16:42:29
|
||||||
|
Authentication key: 3B81 E129 B7C3 26F4 2EA1 2F19 218B CF99 6C7A 6E31
|
||||||
|
created ....: 2016-01-30 16:44:48
|
||||||
|
General key info..: pub 4096R/0xE8E7855AA5AE79A7 2016-01-30 Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
sec# 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never
|
||||||
|
ssb> 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb> 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
ssb> 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never
|
||||||
|
card-no: 0006 05553211
|
||||||
|
|
||||||
|
`sec#` indicates master key is not available (as it should be stored encrypted and offline).
|
||||||
|
|
||||||
|
## Import public key
|
||||||
|
|
||||||
|
$ gpg --import < /mnt/public-usb-key/pubkey.txt
|
||||||
|
|
||||||
|
## Trust master key
|
||||||
|
|
||||||
|
$ gpg --edit-key 0x47FE984F98EE7407
|
||||||
|
gpg (GnuPG) 1.4.18; Copyright (C) 2014 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.
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: unknown validity: unknown
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
sub 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never usage: A
|
||||||
|
|
||||||
|
[ unknown] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
gpg> trust
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: unknown validity: unknown
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
sub 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never usage: A
|
||||||
|
|
||||||
|
[ unknown] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
|
||||||
|
Please decide how far you trust this user to correctly verify other users' keys
|
||||||
|
(by looking at passports, checking fingerprints from different sources, etc.)
|
||||||
|
|
||||||
|
1 = I don't know or won't say
|
||||||
|
2 = I do NOT trust
|
||||||
|
3 = I trust marginally
|
||||||
|
4 = I trust fully
|
||||||
|
5 = I trust ultimately
|
||||||
|
m = back to the main menu
|
||||||
|
|
||||||
|
Your decision? 5
|
||||||
|
Do you really want to set this key to ultimate trust? (y/N) y
|
||||||
|
|
||||||
|
pub 4096R/0x47FE984F98EE7407 created: 2016-01-30 expires: never usage: SC
|
||||||
|
|
||||||
|
trust: ultimate validity: unknown
|
||||||
|
sub 4096R/0xE8E7855AA5AE79A7 created: 2016-01-30 expires: never usage: S
|
||||||
|
|
||||||
|
sub 4096R/0x39988E0390CB4B0C created: 2016-01-30 expires: never usage: E
|
||||||
|
|
||||||
|
sub 4096R/0x218BCF996C7A6E31 created: 2016-01-30 expires: never usage: A
|
||||||
|
|
||||||
|
[ unknown] (1). Doctor Duh <drduh@users.noreply.github.com>
|
||||||
|
Please note that the shown key validity is not necessarily correct
|
||||||
|
unless you restart the program.
|
||||||
|
|
||||||
|
gpg> quit
|
||||||
|
|
||||||
|
## GnuPG
|
||||||
|
|
||||||
|
### Encryption/decryption
|
||||||
|
|
||||||
|
$ echo "$(uname -a)" | gpg --encrypt --armor -r 0x47FE984F98EE7407 | gpg --debug --decrypt --armor
|
||||||
|
|
||||||
|
Please enter the PIN
|
||||||
|
gpg: encrypted with 4096-bit RSA key, ID 0x39988E0390CB4B0C, created 2016-01-30
|
||||||
|
"Doctor Duh <drduh@users.noreply.github.com>"
|
||||||
|
Linux workstation 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17) x86_64 GNU/Linux
|
||||||
|
|
||||||
|
### Signing
|
||||||
|
|
||||||
|
$ echo "$(uname -a)" | gpg --encrypt --armor --sign -r 0x47FE984F98EE7407
|
||||||
|
gpg: signatures created so far: 0
|
||||||
|
|
||||||
|
Please enter the PIN
|
||||||
|
[sigs done: 0]
|
||||||
|
-----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
hQIMAzmYjgOQy0sMAQ//bG8YyEinTOFzL/aL/BN54/PAFzBZj6B//dEFXYu5NlHJ
|
||||||
|
[...]
|
||||||
|
sjLN5ZhJkQKJeUWIVdGeuZN+pIeIRWQHeKD7xRUgij6/nC7qCfPPkHFYxQ==
|
||||||
|
=jztu
|
||||||
|
-----END PGP MESSAGE-----
|
||||||
|
|
||||||
|
## SSH
|
||||||
|
|
||||||
|
### Create configuration
|
||||||
|
|
||||||
|
$ cat > ~/.gnupg/gpg-agent.conf
|
||||||
|
pinentry-program /usr/bin/pinentry-curses
|
||||||
|
default-cache-ttl 60
|
||||||
|
max-cache-ttl 120
|
||||||
|
enable-ssh-support
|
||||||
|
write-env-file
|
||||||
|
use-standard-socket
|
||||||
|
^D (Press Control-D)
|
||||||
|
|
||||||
|
### Replace ssh-agent with gpg-agent
|
||||||
|
|
||||||
|
$ pkill ssh-agent && \
|
||||||
|
eval $(gpg-agent --daemon --enable-ssh-support --use-standard-socket \
|
||||||
|
--log-file ~/.gnupg/gpg-agent.log --write-env-file)
|
||||||
|
|
||||||
|
### Copy public key to server
|
||||||
|
|
||||||
|
$ ssh-add -L
|
||||||
|
ssh-rsa AAAAB4NzaC1yc2EAAAADAQABAAACAz[...]zreOKM+HwpkHzcy9DQcVG2Nw== cardno:000605553211
|
||||||
|
|
||||||
|
### Connect with public key authentication
|
||||||
|
|
||||||
|
$ ssh git@github.com -vvv
|
||||||
|
[...]
|
||||||
|
debug2: key: cardno:000605553211 (0x1234567890),
|
||||||
|
debug1: Authentications that can continue: publickey
|
||||||
|
debug3: start over, passed a different list publickey
|
||||||
|
debug3: preferred gssapi-keyex,gssapi-with-mic,publickey,keyboard-interactive,password
|
||||||
|
debug3: authmethod_lookup publickey
|
||||||
|
debug3: remaining preferred: keyboard-interactive,password
|
||||||
|
debug3: authmethod_is_enabled publickey
|
||||||
|
debug1: Next authentication method: publickey
|
||||||
|
debug1: Offering RSA public key: cardno:000605553211
|
||||||
|
debug3: send_pubkey_test
|
||||||
|
debug2: we sent a publickey packet, wait for reply
|
||||||
|
debug1: Server accepts key: pkalg ssh-rsa blen 535
|
||||||
|
debug2: input_userauth_pk_ok: fp e5:de:a5:74:b1:3e:96:9b:85:46:e7:28:53:b4:82:c3
|
||||||
|
debug3: sign_and_send_pubkey: RSA e5:de:a5:74:b1:3e:96:9b:85:46:e7:28:53:b4:82:c3
|
||||||
|
debug1: Authentication succeeded (publickey).
|
||||||
|
[...]
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
- Don't write to drduh@users.noreply.github.com, open an issue on GitHub instead.
|
||||||
|
- Programming YubiKey for GPG keys still lets you use its two slots - OTP and static password modes, for example.
|
||||||
|
- ECC may be preferred to RSA 4096, but the 1.4.x branch of GnuPG does not support it.
|
||||||
|
- If you encounter problems, try unplugging and re-inserting your YubiKey. Also try installing and using GnuPG 2.x (`sudo apt-get install gnupg2` and `gpg2`)
|
||||||
|
|
||||||
|
# References
|
||||||
|
|
||||||
|
<https://developers.yubico.com/yubikey-personalization/>
|
||||||
|
|
||||||
|
<https://developers.yubico.com/PGP/Card_edit.html>
|
||||||
|
|
||||||
|
<https://blog.josefsson.org/2014/06/23/offline-gnupg-master-key-and-subkeys-on-yubikey-neo-smartcard/>
|
||||||
|
|
||||||
|
<https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/>
|
||||||
|
|
||||||
|
<https://blog.habets.se/2013/02/GPG-and-SSH-with-Yubikey-NEO>
|
||||||
|
|
||||||
|
<https://trmm.net/Yubikey>
|
||||||
|
|
||||||
|
<https://rnorth.org/8/gpg-and-ssh-with-yubikey-for-mac>
|
||||||
|
|
||||||
|
<https://jclement.ca/articles/2015/gpg-smartcard/>
|
||||||
|
|
||||||
|
<https://github.com/herlo/ssh-gpg-smartcard-config>
|
||||||
|
|
||||||
|
<http://www.bootc.net/archives/2013/06/09/my-perfect-gnupg-ssh-agent-setup/>
|
||||||
|
|
||||||
|
<https://help.riseup.net/en/security/message-security/openpgp/best-practices>
|
Loading…
Reference in New Issue