GPG Smart Card Mini-How-To
Short Answer
It seems the secret keys are properly copied to the Yubikey smart card. However, the public key is missing from the local keyring. In order for gpg to work properly, the public key must be available locally.
There are several methods to import the public key. However, there is a handy field on the smart card for storing a URL where the public key can be found. So, if the public key is placed in a publicly accessible location on the Internet, the public key can be retrieved and added to the local keyring by using the fetch
option in either the gpg/card
menu or the --fetch-keys URL
option on the gpg command line.
Once the local keyring knows about the public key, the private keys stored on the smart card should operate normally using the set user pin to unlock the keys.
Mini-How-To
This tutorial will run through the creation of a passphraseless PGP key set, loading the secret keys on a smart card, posting the public key on the Internet, and basic use of the card.
Please note that the key included on this post is a test and demonstration key only. It has no passphrase and can be imported locally via copy and paste if so desired. However, please do not use this test key for any purpose except testing.
GPG Version
gpg --version
gpg (GnuPG) 2.2.12
libgcrypt 1.8.4
Key generation
Let's generate a key to play with:
$ cat << EOF | gpg --gen-key --batch -
> Key-Type: rsa
> Key-Length: 2048
> Key-Usage: sign
> Subkey-Type: rsa
> Subkey-Length: 2048
> Name-Real: demo card
> Name-Comment: DeleteMe
> Name-Email: demo.card@domain.tld
> %no-protection
> %commit
> EOF
Here's the secret key
gpg --armor --export-secret-key demo.card@domain.tld
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
NQSlYESEFuIGA3+WuBy2
=V4D1
-----END PGP PRIVATE KEY BLOCK-----
Key Listing
gpg --edit-key F1663A6A94793987
Secret key is available.
sec rsa2048/F1663A6A94793987
created: 2019-04-15 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/B4559AAA0624A9CF
created: 2019-04-15 expires: never usage: SEA
[ultimate] (1). demo card (DeleteMe) <demo.card@domain.tld>
Placing the Public Key online somewhere
gpg -a --export F1663A6A94793987
https://pastebin.com/raw/y8gCBFmH
Add keys and URL to card
gpg --edit-card
gpg/card> url
URL to retrieve public key: https://pastebin.com/raw/y8gCBFmH
gpg --edit-key F1663A6A94793987
gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
gpg> key 1
sec rsa2048/F1663A6A94793987
created: 2019-04-15 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* rsa2048/B4559AAA0624A9CF
created: 2019-04-15 expires: never usage: SEA
[ultimate] (1). demo card (DeleteMe) <demo.card@domain.tld>
gpg> keytocard
Please select where to store the key:
(1) Signature key
(2) Encryption key
(3) Authentication key
Your selection? 2
gpg> save
Delete the keys from the keyring
gpg --delete-secret-keys F1663A6A94793987
sec rsa2048/F1663A6A94793987 2019-04-15 demo card (DeleteMe) <demo.card@domain.tld>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
gpg --delete-keys F1663A6A94793987
pub rsa2048/F1663A6A94793987 2019-04-15 demo card (DeleteMe) <demo.card@domain.tld>
Delete this key from the keyring? (y/N) y
Similar state as the OP
gpg --edit-card
Reader ...........: 04E6:xx:0
Application ID ...: D27600xxxx0190000
Version ..........: 2.1
Manufacturer .....: unknown
Serial number ....: 00000019
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : https://pastebin.com/raw/y8gCBFmH
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: F44A 6EA6 5E82 1743 6E83 E2C2 F166 3A6A 9479 3987
created ....: 2019-04-15 17:49:25
Encryption key....: EB75 66CA 07FF 9C4F 94ED 9246 B455 9AAA 0624 A9CF
created ....: 2019-04-15 17:49:25
Authentication key: [none]
General key info..: [none]
Use Keys on Card
Retrieve Public Key
gpg/card> fetch
gpg: requesting key from 'https://pastebin.com/raw/y8gCBFmH'
gpg: key F1663A6A94793987: public key "demo card (DeleteMe) <demo.card@domain.tld>" imported
gpg: Total number processed: 1
gpg: imported: 1
gpg/card> list
Reader ...........: 04E6:xx:0
Application ID ...: D27600xxxx0190000
Version ..........: 2.1
Manufacturer .....: unknown
Serial number ....: 00000019
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : https://pastebin.com/raw/y8gCBFmH
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: F44A 6EA6 5E82 1743 6E83 E2C2 F166 3A6A 9479 3987
created ....: 2019-04-15 17:49:25
Encryption key....: EB75 66CA 07FF 9C4F 94ED 9246 B455 9AAA 0624 A9CF
created ....: 2019-04-15 17:49:25
Authentication key: [none]
General key info..:
pub rsa2048/F1663A6A94793987 2019-04-15 demo card (DeleteMe) <demo.card@domain.tld>
sec> rsa2048/F1663A6A94793987 created: 2019-04-15 expires: never
card-no: 7615 00000019
ssb> rsa2048/B4559AAA0624A9CF created: 2019-04-15 expires: never
card-no: 7615 00000019
Almost Ready for Use
gpg --edit-key F1663A6A94793987
Secret key is available.
sec rsa2048/F1663A6A94793987
created: 2019-04-15 expires: never usage: SC
card-no: 7615 00000019
trust: unknown validity: unknown
ssb rsa2048/B4559AAA0624A9CF
created: 2019-04-15 expires: never usage: SEA
card-no: 7615 00000019
[ unknown] (1). demo card (DeleteMe) <demo.card@domain.tld>
What happened to the Trust of the key?
GPG stores trust separately from the key material. This trust setting is what enables the Web of Trust. So, when a given key is imported into a local keyring, that key is not assigned a trust level. However, this is easy to change interactively.
gpg --edit-key F1663A6A94793987
gpg> trust
sec rsa2048/F1663A6A94793987
created: 2019-04-15 expires: never usage: SC
card-no: 7615 00000019
trust: unknown validity: unknown
ssb rsa2048/B4559AAA0624A9CF
created: 2019-04-15 expires: never usage: SEA
card-no: 7615 00000019
[ unknown] (1). demo card (DeleteMe) <demo.card@domain.tld>
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
Now the key is fully ready
gpg --list-key F1663A6A94793987
pub rsa2048 2019-04-15 [SC]
F44A6EA65E8217436E83E2C2F1663A6A94793987
uid [ultimate] demo card (DeleteMe) <demo.card@domain.tld>
sub rsa2048 2019-04-15 [SEA]
Let's try it out
gpg -ear F1663A6A94793987
Hello there!
-----BEGIN PGP MESSAGE-----
hQEMA7RVmqoGJKnPAQf/V5CAzRCQ8gmAczy5i66e6w93CRYDiJ/1fNfL6ey2lYx2
cu/I3I12455Z8YjnLk3q66LW0gkhaxVX1uhtBXgjglz2RX6wMAYSDMvVs4cfIgq4
VLbW8T2y8ThdXvpGfwtgBgfFV5M2QS46RipXeF5rOCOnGeI8IUuzAC2147/qjcHG
+/wWDaker7NfY8GSgJ8OXd6kTmpZ//1zOTYvJVsE80viByv2Hx42Zu0r6e3KqgeR
qQlNA/zevYYjm4S0tkmxYoDb42gTPClNiHkJa3IXYlwYPzLCSszBsaTfHZdHl7yx
8PshF7fmE/NOO0dhHq2cV+fqPq8uT/VlNcPm3TYNxtJIAfnuTuHcorOuQNh0koML
8WWTIlLbj9OfBsZVsy5cp5ggpSLrCdPYd1g7RzEwRxu8QrWNO+pj2VRTtEZMafXq
XsKGJIgxsbJQ
=nwdE
-----END PGP MESSAGE-----
gpg -d
Please unlock the card
Number: 7615 00000019
Holder:
PIN:
gpg: encrypted with 2048-bit RSA key, ID B4559AAA0624A9CF, created 2019-04-15
"demo card (DeleteMe) <demo.card@domain.tld>"
Hello there!
Use with pass
pass init F1663A6A94793987
mkdir: created directory '/home/user/.password-store/'
Password store initialized for F1663A6A94793987
pass insert password1
Enter password for password1: <qwerty>
Retype password for password1: <qwerty>
pass show password1
Please unlock the card
Number: 7615 00000019
Holder:
PIN:
qwerty
Usage notes
If a given password store is initialized with a key that is not located on a card. The pass script will not be able to locate the secret key if it is then moved to a smart card.