This document quickly describes how to configure and use an OpenPGP Smart Card to store cryptographic material for signature, encryption and authentication, both local (PAM) and remote (SSH).
$ <in>dmesg | tail -n 2</in> usb 6-2: new full speed USB device using uhci_hcd and address 3 usb 6-2: configuration #1 chosen from 1 choice $ <in>lsusb -v -d 04e6:5115</in> Bus 006 Device 003: ID 04e6:5115 SCM Microsystems, Inc. SCR335 SmartCard Reader Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 16 idVendor 0x04e6 SCM Microsystems, Inc. idProduct 0x5115 SCR335 SmartCard Reader bcdDevice 5.18 iManufacturer 1 SCM Microsystems Inc. iProduct 2 SCR33x USB Smart Card Reader iSerial 5 21120811308181 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 93 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 3 CCID Class bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 11 Chip/SmartCard bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 4 CCID Interface ChipCard Interface Descriptor: bLength 54 bDescriptorType 33 bcdCCID 1.00 nMaxSlotIndex 0 bVoltageSupport 1 5.0V dwProtocols 3 T=0 T=1 dwDefaultClock 4000 dwMaxiumumClock 12000 bNumClockSupported 0 dwDataRate 9600 bps dwMaxDataRate 307200 bps bNumDataRatesSupp. 0 dwMaxIFSD 252 dwSyncProtocols 00000000 dwMechanical 00000000 dwFeatures 000100BA Auto configuration based on ATR Auto voltage selection Auto clock change Auto baud rate change Auto PPS made by CCID TPDU level exchange dwMaxCCIDMsgLen 263 bClassGetResponse echo bClassEnvelope echo wlcdLayout none bPINSupport 0 bMaxCCIDBusySlots 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 16 Device Status: 0x0000 (Bus Powered)
$ <in>gpg --card-status</in> Application ID ...: D27600012401020000050000075C0000 Version ..........: 2.0 Manufacturer .....: ZeitControl Serial number ....: 0000075C Name of cardholder: [not set] Language prefs ...: de Sex ..............: [not set] URL of public key : [not set] Login data .......: [not set] Signature PIN ....: not forced Max. PIN lengths .: 32 32 32 PIN retry counter : 3 0 3 Signature counter : 0 Signature key ....: [not set] Encryption key....: [not set] Authentication key: [not set] General key info..: [none]
All throughout this section and the following, I'm using a GPG agent which propagates all passphrase and PIN request to my X session. More secrets may be asked by the diretly CLI if no Agent is used. Also, it seems better to make sure to use GnuPG >= 2, though most of the following should work fine with earlier version.
The default PIN code is 123456 while the admin's is 12345678. It's not clear what the “reset code” is…
$ <in>gpg --change-pin</in> gpg: OpenPGP card no. D27600012401020000050000075C0000 detected 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? <in>3</in> PIN changed. 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? <in>1</in> PIN changed. 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? <in>4</in> Reset Code set. 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? <in>q</in>
Then, the card can be personnalised by setting its metadata.
$ <in>gpg --card-edit</in> [...] gpg/card> <in>admin</in> Admin commands are allowed gpg/card> <in>name</in> Cardholder's surname: <in>SURNAME</in> Cardholder's given name: <in>NAME</in> gpg/card> <in>url</in> URL to retrieve public key: <in>http://URL/OF/PUBLIC.KEY.asc</in> gpg/card> <in>login</in> Login data (account name): <in>LOGIN</in> gpg/card> <in>sex</in> Sex ((M)ale, (F)emale or space): <in>S</in> gpg/card> <in>quit</in>
Subkeys are keys signed by the primary key. They can be used for everything but key signing. Using subkeys allows not to need the primary key at all for daily operations. It can then be stored offline in a safe location.
Time-limited subkeys allows for a healthy renewal of the keys before they have been overused. As it is the primary key, not the subkeys, which get signed by other users, new subkeys do not need to be undergo the process again.
It is generally good to have one signature subkey per device/purpose/…, as they can all be signed or revoked separately. Unfortunately, the same doesn't hold for encryption keys, as this would force senders to decide which of the keys to use, and might result in one device (the current one being use) not being able to decrypt a message (which is very important and urgent). It's a trade-off to consider.
We now create two subkeys for signature and authentication. This procedure uses the card's PRNG to generate the subkeys directly on the card. The cryptographic material will never be allowed out!
$ <in>gpg --edit-key KEYID</in> gpg> <in>addcardkey</in> Signature key ....: SIGFP Encryption key....: [none] Authentication key: AUTHFP Please select the type of key to generate: (1) Signature key (2) Encryption key (3) Authentication key Your selection? <in>1</in> What keysize do you want for the Signature key? (2048) Key is protected. You need a passphrase to unlock the secret key for user: "KEYID NAME SURNAME <EMAIL>" 2048-bit RSA key, ID KEYID, created 2009-05-11 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) <in>2y</in> Key expires at Fri 26 Oct 2012 11:17:20 PM EST Is this correct? (y/N) <in>y</in> Really create? (y/N) <in>y</in> pub 2048R/KEYID created: 2009-05-11 expires: never usage: SC trust:ultimate validity:ultimate sub 2048R/ENCID created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/SSKID created: 2010-10-27 expires: 2012-10-26 usage: S [ultimate] (1). NAME SURNAME <EMAIL> gpg> <in>addcardkey</in> Signature key ....: FP-ESKID Encryption key....: ENCFP Authentication key: FP-AUTHID Please select the type of key to generate: (1) Signature key (2) Encryption key (3) Authentication key Your selection? <in>3</in> [...] pub 2048R/KEYID created: 2009-05-11 expires: never usage: SC trust:ultimate validity:ultimate sub 2048R/ENCID created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/SSKID created: 2010-10-27 expires: 2012-10-26 usage: S sub 2048R/AUTHID created: 2010-10-27 expires: 2012-10-26 usage: A [ultimate] (1). NAME SURNAME <EMAIL> gpg> <in>save</in>
The encryption subkey requires a bit more thought, particularly if several cards are going to be used. Unlike the signature or authentication keys of which several (presumably one per card) can be active and valid at the same time, the encryption key (that is the one with which messages are decrypted) is better kept unique. Otherwise, a mad juggle of cards will be required to handle to decrypt messages as senders randomly choose one of the encryption keys, not knowing better.
Another question is that of the expiry of that key. After some reading, it doesn't appear to be really necessary (to me; YKMV) to have a time-limited encryption subkey. It would not limit the ability of an attacker to decrypt messages after that date. The only advantage would be to force going away from a corrupted key, thus forcing the attacker to obtain the new one before being able to decrypt new correspondence.
To handle this case, we need to do the following.
As transferring to the card will replace the local subkey by a stub, the backup needs to be restored everytime a new card needs to be initialised.
This should be done by default when creating a new key pair. However, in my case, after fiddling back and forth, I ended up revoking it (see the history of this page for details). A new ones therefore needs to be created.
$ <in>gpg --edit-key KEYID</in> gpg (GnuPG) 2.0.16; Copyright (C) 2009 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 2048R/KEYID created: 2009-05-11 expires: never usage: SC trust:ultimate validity:ultimate This key was revoked on 2010-10-27 by RSA key KEYID NAME SURNAME <EMAIL> sub 2048R/ENCID created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/SSKID created: 2013-01-24 expires: 2015-01-24 usage: S sub 2048R/AUTHID created: 2013-01-24 expires: 2015-01-24 usage: A [ultimate] (1). NAME SURNAME <EMAIL> gpg> <in>addkey</in> Key is protected. You need a passphrase to unlock the secret key for user: "NAME SURNAME <EMAIL>" 2048-bit RSA key, ID KEID, created 2009-05-11 Please select what kind of key you want: (3) DSA (sign only) (4) RSA (sign only) (5) Elgamal (encrypt only) (6) RSA (encrypt only) Your selection? <in>6</in> RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) <in>2048</in> 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) <in>0</in> Key does not expire at all Is this correct? (y/N) <in>y</in> Really create? (y/N) <in>y</in> 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 2048R/KEYID created: 2009-05-11 expires: never usage: SC trust: unknown validity: unknown This key was revoked on 2010-10-27 by RSA key KEYID NAME SURNAME <EMAIL> sub 2048R/OENCID created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/ENCID created: 2013-09-12 expires: never usage: E sub 2048R/SSKID created: 2013-01-24 expires: 2015-01-24 usage: S sub 2048R/AUTHID created: 2013-01-24 expires: 2015-01-24 usage: A [ultimate] (1). NAME SURNAME <EMAIL> gpg> <in>save</in>
Copying the encryption to the key will render it unusable (replacing it with a stub) on the local system. This will also prevent copying it over to another card when needed. To prevent being that, making a backup is necessary.
$ <in>gpg -a --export-secret-keys KEYID > KEYID.key.`date +%Y%m%d_%H%M`.asc</in>
Testing the backup is always a good idea. We do this by importing the backup into a brand new keyring, and exercising the encryption/decryption with it.
$ <in>mkdir .gnupg-backup-test</in> $ <in>chmod 700 .gnupg-backup-test/</in> $ <in>gpg --homedir ~/.gnupg-backup-test --import KEYID.key.full.20130912_1456.asc</in> gpg: keyring `/home/USER/.gnupg-backup-test/secring.gpg' created gpg: keyring `/home/USER/.gnupg-backup-test/pubring.gpg' created gpg: key KEYID: secret key imported gpg: /home/USER/.gnupg-backup-test/trustdb.gpg: trustdb created gpg: key KEYID: public key "NAME SURNAME <EMAIL>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) gpg: secret keys read: 1 gpg: secret keys imported: 1 $ <in>gpg --homedir ~/.gnupg-backup-test -evr EMAIL | gpg --homedir ~/.gnupg-backup-test -d</in> gpg: using PGP trust model gpg: using subkey ENCID instead of primary key KEYID gpg: ENCID: There is no assurance this key belongs to the named user pub 2048R/ENCID 2013-09-12 NAME SURNAME <EMAIL> Primary key fingerprint: FP-KEYID Subkey fingerprint: ENCFP It is NOT certain that the key belongs to the person named in the user ID. If you *really* know what you are doing, you may answer the next question with yes. Use this key anyway? (y/N) <in>y</in> gpg: reading from `[stdin]' gpg: writing to stdout gpg: RSA/AES256 encrypted for: "ENCID NAME SURNAME <EMAIL>" You need a passphrase to unlock the secret key for user: "NAME SURNAME <EMAIL>" 2048-bit RSA key, ID ENCID, created 2013-09-12 (main key ID KEYID) gpg: can't connect to the agent - trying fall back <in>blituri</in> gpg: encrypted with 2048-bit RSA key, ID ENCID, created 2013-09-12 "NAME SURNAME <EMAIL>" blituri $ <in>rm -rf .gnupg-backup-test</in>
This backup file has to be securely stored and looked after!
It is possible to copy a (sub)key generated locally to the card. This is done with the keytocard
command. That key can either be put in the encryption or authentication slot of the card. Otherwise, the –homedir
gymnastic can be skipped, along with the creation/deletion of said homedir.
In case the local subkey was already stubbed by, e.g., a copy to a prior card, it can first be retrieved from the backup, much in the same way as the previous test.
$ <in>mkdir .gnupg-keytocard</in> $ <in>chmod 700 .gnupg-keytocard/</in> $ <in>gpg --homedir ~/.gnupg-keytocard --import KEYID.key.full.20130912_1456.asc</in> [...] $ <in>gpg --homedir ~/.gnupg-keytocard --card-status</in> [...] $ <in>gpg --homedir ~/.gnupg-keytocard --edit-key KEYID</in> gpg (GnuPG) 2.0.21; Copyright (C) 2013 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 2048R/KEYID created: 2009-05-11 expires: never usage: SC trust: unknown validity: unknown The following key was revoked on 2010-10-27 by RSA key KEYID NAME SURNAME <EMAIL> sub 2048R/OENCID created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/ENCID created: 2013-09-12 expires: never usage: E sub 2048R/SSKID created: 2013-01-24 expires: 2015-01-24 usage: S sub 2048R/AUTHID created: 2013-01-24 expires: 2015-01-24 usage: A [ultimate] (1). NAME SURNAME <EMAIL> gpg> <in>toggle</in> sec 2048R/KEYID created: 2009-05-11 expires: never ssb 2048R/OENCID created: 2009-05-11 expires: never ssb 2048R/ENCID created: 2013-09-12 expires: never (1) NAME SURNAME <EMAIL> gpg> <in>key 2</in> # In my case, as I want the non-revoked key sec 2048R/KEYID created: 2009-05-11 expires: never ssb 2048R/OENCID created: 2009-05-11 expires: never ssb* 2048R/ENCID created: 2013-09-12 expires: never (1) NAME SURNAME <EMAIL> gpg> <in>keytocard</in> Signature key ....: FP-SSKID Encryption key....: FP-ENCID Authentication key: FP-AUTHID Please select where to store the key: (2) Encryption key Your selection? <in>2</in> You need a passphrase to unlock the secret key for user: "NAME SURNAME <EMAIL>" 2048-bit RSA key, ID ENCID, created 2013-09-12 Please enter the Admin PIN sec 2048R/KEYID created: 2009-05-11 expires: never ssb 2048R/OENCID created: 2009-05-11 expires: never ssb* 2048R/ENCID created: 2013-09-12 expires: never (1) NAME SURNAME <EMAIL> gpg> save $ <in>rm -rf .gnupg-keytocard</in> $ <in>gpg --card-status</in> # To update the normal keyring
We test that everything works as desired, and nothing more. More precisely, we confirm that we can only sign and decrypt messages when the card is inserted.
$ # The card is not in the reader $ <in>cat > sign.txt this is signed ^D</in> $ <in>cat > encrypt.txt this is encrypted ^D</in> $ <in>gpg -r EMAIL -ae encrypt.txt</in> $ <in>gpg -s sign.txt</in> gpg: selecting openpgp failed: ec=6.112 gpg: signing failed: general error gpg: signing failed: general error $ <in>gpg -d encrypt.txt.asc</in> gpg: selecting openpgp failed: ec=6.112 gpg: encrypted with 2048-bit RSA key, ID NESKID, created 2010-10-27 "NAME SURNAME <EMAIL>" gpg: public key decryption failed: general error gpg: decryption failed: secret key not available $ # Now we insert the card in the reader $ <in>gpg -d encrypt.txt.asc</in> gpg: encrypted with 2048-bit RSA key, ID NESKID, created 2010-10-27 "NAME SURNAME <EMAIL>" this is encrypted $ <in>gpg -s sign.txt</in> $ <in>gpg --verify sign.txt.gpg</in> gpg: Signature made Wed 27 Oct 2010 11:37:25 PM EST using RSA key ID SSKID gpg: Good signature from "NAME SURNAME <EMAIL>"
Everything works!
GnuPG 2.1 has had a lot of work done on the way the agent handles the keys. One major feature is the ability to forward the GPG Agent's socket so the PGP keys can be used remotely, just like the SSH Agent does for SSH keys. As before, the agent can also work as an SSH agent, both local and forwarded.
The GPG agent starts automatically when one of the GPG utilities need it (a handy way to start it manually is through gpg-connect-agent /bye
, which will start the agent). It uses file ~/.gnupg/gpg-agent.conf
as its configuration file, and will use well-known paths for its sockets, making it easier to forward (no dynamic configuration needed on either side). The gpgconf
utility can be used to list those well-known paths.
$ <in>gpgconf --list-dirs</in> sysconfdir:/etc/gnupg bindir:/usr/bin libexecdir:/usr/lib/gnupg libdir:/usr/lib/gnupg datadir:/usr/share/gnupg localedir:/usr/share/locale socketdir:/run/user/1000/gnupg dirmngr-socket:/run/user/1000/gnupg/S.dirmngr agent-ssh-socket:/run/user/1000/gnupg/S.gpg-agent.ssh agent-extra-socket:/run/user/1000/gnupg/S.gpg-agent.extra agent-browser-socket:/run/user/1000/gnupg/S.gpg-agent.browser agent-socket:/run/user/1000/gnupg/S.gpg-agent homedir:/home/shtrom/.gnupg
Configure the GPG Agent to emulate the SSH agent and create a restricted GPG Agent socket for forwarding.
enable-ssh-support extra-socket ~/.gnupg/S.gpg-agent.extra
Tell SSH to forward the restricted GPG Agent socket.
Host SERVER user USER RemoteForward SERVERHOME/.gnupg/S.gpg-agent LOCALHOME/.gnupg/S.gpg-agent.extra
Tell the SSH _server_ to delete forwarded sockets when the session terminates
StreamLocalBindUnlink yes
Configure interactive shell sessions so they use the right agents whether local or forwarded.
For gpg-agent
to also act as an SSH agent, the following needs to be added to its configuration file.
enable-ssh-support
gpgconf
can tell us what socket to use as SSH_AUTH_SOCK
.
$ <in>gpgconf --list-dirs agent-ssh-socket</in> /run/user/1000/gnupg/S.gpg-agent.ssh $ <in>export SSH_AUTH_SOCK=`gpgconf --list-dirs agent-ssh-socket`</in> $ <in>echo $SSH_AUTH_SOCK</in> /run/user/1000/gnupg/S.gpg-agent.ssh
This is sufficient to make the OpenSSH tools find their marks. The following assumes only the SSH key on the card is present in the output (or that all registered keys should be added which may or may not be desirable). This can be done by deleting the SSH keys (usually id_rsa*
) from the .ssh
directory. However, the GPG Agent appears to be keeping a cache of other SSH keys in .gnupg/sshcontrol
, which may need to be deleted if the old SSH key still appears in the output of ssh-add -l
after restarting the agent.
$ <in>ssh-add -L</in> ssh-rsa CARDKEYGPGFP cardno:00050000075E
The key has to be added to the .ssh/authorized_keys
of the servers. The output from ssh-add -L
is what should be copied there.
Forwarding of this SSH agent is straightforward with the ForwardAgent
directive, or -A
on the command line: as it behaves as a stock-standard SSH agent, SSH already knows what to do. It simply sets the $SSH_AUTH_SOCK
environment variable to point to the endpoint of its forwarded socket, and all SSH tools can work as if the forwarded keys were local (including SSHing into yet another server, and forwarding that socket again).
$ <in>ssh-copy-id SERVER</in> USER@SERVER's password: $ <in>ssh -A SERVER</in> SERVER$ <in>echo $SSH_AUTH_SOCK</in> SERVER$ <in>ssh-add -L</in> ssh-rsa CARDKEYGPGFP cardno:00050000075E
And after entering the card's PIN into GPG's pinentry dialog, that's it!
This section is old and probably outdated, you're better off upgrading to GnuPG>2.1, and skipping it
SSH authentication using the OpenPGP card is done using the authentication (third) key on the card. All interaction is done through gpg-agent
. It must be started to fill in for ssh-agent
.
$ <in>gpg-agent --daemon --scdaemon-program /usr/bin/scdaemon \ --write-env-file --use-standard-socket \ --default-cache-ttl 43200 \ --enable-ssh-support --default-cache-ttl-ssh 43200</in> GPG_AGENT_INFO=/home/USER/.gnupg/S.gpg-agent:18845:1; export GPG_AGENT_INFO; SSH_AUTH_SOCK=/home/USER/.gnupg/S.gpg-agent.ssh; export SSH_AUTH_SOCK; SSH_AGENT_PID=18845; export SSH_AGENT_PID; $ <in>GPG_AGENT_INFO=/home/USER/.gnupg/S.gpg-agent:18845:1; export GPG_AGENT_INFO;</in> $ <in>SSH_AUTH_SOCK=/home/USER/.gnupg/S.gpg-agent.ssh; export SSH_AUTH_SOCK;</in> $ <in>SSH_AGENT_PID=18845; export SSH_AGENT_PID;</in>
Argument –enable-ssh-support
instructs the agent to also declare SSH_*
variables for use by SSH clients looking for an agent, –write-env-file
tells the agent to write file .gpg-agent-info
. This file contains what gpg-agent
output to stdout
and can be used to replicate the environment from other sessions (e.g. using this script). As usual, the commands above can be handily shortened to
$ <in>eval `gpg-agent --daemon --scdaemon-program /usr/bin/scdaemon \ --write-env-file --use-standard-socket \ --default-cache-ttl 43200 \ --enable-ssh-support --default-cache-ttl-ssh 43200`</in>
to export start the agent and export the variables to the shell (Bash) in one operation.
The new key is then shown by ssh-add
along with the standard ones (which will soon no longer be needed). Of course, it is only available when the card is inserted.
$ <in>ssh-add -l</in> 2048 CARDKEYFP cardno:00050000075C (RSA) 2048 SSHKEYFP /home/USER/.ssh/id_rsa (RSA) [...]
SSH can forward arbitrary sockets, so it should be possible to just forward the socket from `gpgconf –list-dirs agent-socket`
. However, this comes with the same caveat as mentioned in ''ssh''(1) about agent forwarding, namely
-A Enables forwarding of the authentication agent connection. This can also be specified on a per-host basis in a configuration file.
Agent forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the agent's UNIX-domain socket) can access the local agent through the forwarded connection. An attacker cannot obtain key material from the agent, however they can perform operations on the keys that enable them to authenticate using the identities loaded into the agent.
In the case of GnuPG, this also means total control over the keys on and off card.
To be safe, gpg-agent
can be configured to offer and additional, restricted, socket which only supports signing and decryption, without exposing the private keys. It can be enabled in the agent's configuration file with the extra-socket
directive.
extra-socket ~/.gnupg/S.gpg-agent.extra
The SSH client can then be instructed to forward a Unix-domain socket with the RemoteForward
configuration directive (or -R
command line argument). The local restricted socket can be forwarded to the remote server. The remote socket should be placed at the location where other tools would expect the socket (as given by `gpgconf –list-dirs agent-socket`
on the remote server), or symlinked from wherever the SSH client creates it (more on this in the next section).
Host SERVER user USER RemoteForward SERVERHOME/.gnupg/S.gpg-agent LOCALHOME/.gnupg/S.gpg-agent.extra
Unfortunately, ssh_config
does not support tilde expansion, so both local and remote home paths must be hardcoded in this configuration file.
This is sufficient, and works nicely to gen
$ <in>ssh -A SERVER</in> SERVER$ <in>echo $SSH_AUTH_SOCK</in> SERVER$ <in gpg-connect-agent /bye</in> gpg-connect-agent: connection to agent is in restricted mode SERVER$ <in>gpg --list-secret-keys</in> /home/shtrom/.gnupg/pubring.gpg ------------------------------- sec# rsa2048/0xF012A6E298C66655 2009-05-11 [SC] [expires: 2026-01-22] 4435CF6A7C8DDD9BE2DEF5F9F012A6E298C66655 uid [ultimate] Olivier Mehani <shtrom@ssji.net> uid [ultimate] [jpeg image of size 13819] uid [ultimate] Olivier Mehani <olivier@mehani.name> uid [ultimate] Olivier Mehani (Nicta) <olivier.mehani@nicta.com.au> uid [ultimate] Olivier Mehani (UNSW Alumni) <olivier.mehani@unswalumni.com> uid [ultimate] Olivier Mehani (Mines ParisTech Alumni) <olivier.mehani@mines-paris.org> ssb rsa2048/0xE9566B9D0957D2D3 2013-01-24 [S] [expires: 2017-09-16] ssb rsa2048/0xF12C167116C243A9 2013-01-24 [A] [expires: 2017-09-16] ssb rsa2048/0xADCF72E06DBC3057 2013-09-11 [S] [expires: 2018-09-10] ssb rsa2048/0x9BE324A0B8F3EFDB 2013-09-11 [A] [expires: 2018-09-10] ssb rsa2048/0xB3B251E0CCFEA0EF 2013-09-12 [E] ssb rsa2048/0x2349101368E456BD 2016-01-19 [S] [expires: 2018-01-18] ssb rsa2048/0xE94657C0DFC635A7 2016-01-19 [A] [expires: 2018-01-18] </in> And signatures and decryption work <code consoleio> $ <in>echo test | gpg -q -s -e -r shtrom@ssji.net | gpg -q -v -d</in> gpg: public key is 0xB3B251E0CCFEA0EF gpg: connection to agent is in restricted mode gpg: Note: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: Note: signature key 0x6CDA813213912971 has been revoked gpg: Note: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: Note: signature key 0x9CA49F44ABCF4EFA has been revoked gpg: Note: signature key 0xF9EB425E6D1886A7 expired Wed 02 Nov 2016 22:02:08 AEDT gpg: using subkey 0xB3B251E0CCFEA0EF instead of primary key 0xF012A6E298C66655 gpg: Note: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: Note: signature key 0x6CDA813213912971 has been revoked gpg: Note: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: Note: signature key 0x9CA49F44ABCF4EFA has been revoked gpg: Note: signature key 0xF9EB425E6D1886A7 expired Wed 02 Nov 2016 22:02:08 AEDT gpg: AES256 encrypted data gpg: original file name='' test gpg: Signature made Thu 29 Dec 2016 19:50:53 AEDT gpg: using RSA key 2BD1FE02C987D438A336FD2AADCF72E06DBC3057 gpg: Note: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: Note: signature key 0x6CDA813213912971 has been revoked gpg: Note: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: Note: signature key 0x9CA49F44ABCF4EFA has been revoked gpg: Note: signature key 0xF9EB425E6D1886A7 expired Wed 02 Nov 2016 22:02:08 AEDT gpg: using subkey 0xADCF72E06DBC3057 instead of primary key 0xF012A6E298C66655 gpg: Note: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: Note: signature key 0x6CDA813213912971 has been revoked gpg: Note: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: Note: signature key 0x9CA49F44ABCF4EFA has been revoked gpg: Note: signature key 0xF9EB425E6D1886A7 expired Wed 02 Nov 2016 22:02:08 AEDT gpg: using pgp trust model gpg: Good signature from "Olivier Mehani <shtrom@ssji.net>" [ultimate] gpg: aka "Olivier Mehani <olivier@mehani.name>" [ultimate] gpg: aka "Olivier Mehani (Nicta) <olivier.mehani@nicta.com.au>" [ultimate] gpg: aka "Olivier Mehani (UNSW Alumni) <olivier.mehani@unswalumni.com>" [ultimate] gpg: aka "Olivier Mehani (Mines ParisTech Alumni) <olivier.mehani@mines-paris.org>" [ultimate] gpg: aka "[jpeg image of size 13819]" [ultimate] gpg: Note: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: Note: signature key 0x6CDA813213912971 has been revoked gpg: Note: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: Note: signature key 0x9CA49F44ABCF4EFA has been revoked gpg: Note: signature key 0xF9EB425E6D1886A7 expired Wed 02 Nov 2016 22:02:08 AEDT gpg: binary signature, digest algorithm SHA512, key algorithm rsa2048
Access to the card, however, is denied.
SERVER$ <in>gpg --card-status</in> gpg: error getting version from 'scdaemon': Forbidden gpg: selecting openpgp failed: Forbidden gpg: OpenPGP card not available: Forbidden
Everything is pretty good, until one tries a second time.
SERVER$ <in>^D</in> $ <in>ssh SERVER</in> Warning: remote port forwarding failed for listen path SERVERHOME/.gnupg/S.gpg-agent SERVER$
This problem is due to the previous SSH session not having cleaned up its forwarded socket, and the new session refusing to overwrite an existing file. To fix the problem, the SSH _daemon_, on the remote machine, needs to be instructed to clean up local forwarding socket when the sessions exist. This is done by adding the following to /etc/ssh/sshd_config
.
StreamLocalBindUnlink yes
After having instructed the SSH server to reload its configuration, and remove the stale socket, it now works well
SERVER$ sudo kill -HUP `ps ax | grep [b]in.sshd | awk '{print $1}'` SERVER$ rm ~/.gnupg/S.gpg-agent $ <in>ssh SERVER</in> SERVER$ <in>^D</in> $ <in>ssh SERVER</in> SERVER$ <in>^D</in>
For machines which can both be accessed from the local console and remotely, some smarts are needed to be able to use the right sockets seamlessly. The best option is to write a small script, and load it at the start of interactive sessions.
export GPG_TTY=$(tty) if [ -n "$SSH_CONNECTION" ]; then GPG_AGENT_SOCK="$(gpgconf --list-dirs agent-socket)" GPG_AGENT_SOCK_FWD=${HOME}/.gnupg/S.gpg-agent if [ ! -e $GPG_AGENT_SOCK -a -S ${GPG_AGENT_SOCK_FWD} ]; then mkdir -p `basename $GPG_AGENT_SOCK` # The link might be present but point to nothing, ln -sf $GPG_AGENT_SOCK_FWD $GPG_AGENT_SOCK fi else unset SSH_AGENT_PID export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" gpg-connect-agent /bye fi
Essentially, if it's an SSH connection, and there is no GPG agent socket present, link the file forwarded by SSH to the location expected by the system. Otherwise, make sure the local SSH uses the local GPG agent as agent. The script can be _sourced_ (not executed, as it set some environment variables that need retaining) from, e.g., ~/.bashrc
.
. ~/bin/init-agent.sh
It is also possible to use the card to authenticate local users using Poldi.
Once installed, the poldi-ctrl
tool is the interface to configure the module. Checking that the reader and the card are properly detected can be done as follows.
$ <in>poldi-ctrl -d</in> Serial number: D27600012401020000050000075C0000 Signing key fingerprint: AUTHFP Key: (public-key (rsa (n #00A729E88A0D3E25368CDA39E08B6A51116457E3598176F2ECBD514585CF2BBA4FC265F68886FC7C41C9EC81C7EDEC4874F40040BCBFC07EF9C2B9BA0F9628C2FD4C171E71542E0C1C7F9630CDAB437763EC8C9FC2BF43D167E84A9E0F1EE48EE131561FB6077B2200827356ABFC75B5A5A08522FEDCBF16E4C283354EEE3E15FACE8BF2C4FA981FB72CB998863CF80CB605DA83599531D8470CB5579B5FBCC5F554E56728F8D5712DB13231F8C9735CC6ED24DF018628ABE7FDAA7C7E1A424F1C8C7AA16E0D7883FAA26EE55A34CF93324001A774462FD39003FF6A0F4822F5A7D41167EE823F91808CDD73F410287547B8FBFC25A06C390AD6D8D84CFB5DA51B#) (e #00010001#) ) )
Poldi's configuration file resides in /etc/poldi
. For now, users are authenticated using a local database. They could also be authenticated based on X.509 certificates (which is what the card's cafpr
seems to be used with).
(...) auth-method localdb (...)
An administrator can then associate the card with a local account.
$ <in>sudo mkdir -p /etc/poldi/localdb/keys</in> $ <in>echo "`poldi-ctrl --print-serialno` $USER" | sudo tee -a /etc/poldi/localdb/users</in> D27600012401020000050000075C0000 USER
The public key has to be available on the system. It can be obtained in the proper format using poldi-ctrl
, and should be placed in a file named after the card's serial number.
$ <in>poldi-ctrl --print-key| sudo tee -a /etc/poldi/localdb/keys/`poldi-ctrl --print-serialno`</in> (public-key (rsa (n #00A729E88A0D3E25368CDA39E08B6A51116457E3598176F2ECBD514585CF2BBA4FC265F68886FC7C41C9EC81C7EDEC4874F40040BCBFC07EF9C2B9BA0F9628C2FD4C171E71542E0C1C7F9630CDAB437763EC8C9FC2BF43D167E84A9E0F1EE48EE131561FB6077B2200827356ABFC75B5A5A08522FEDCBF16E4C283354EEE3E15FACE8BF2C4FA981FB72CB998863CF80CB605DA83599531D8470CB5579B5FBCC5F554E56728F8D5712DB13231F8C9735CC6ED24DF018628ABE7FDAA7C7E1A424F1C8C7AA16E0D7883FAA26EE55A34CF93324001A774462FD39003FF6A0F4822F5A7D41167EE823F91808CDD73F410287547B8FBFC25A06C390AD6D8D84CFB5DA51B#) (e #00010001#) ) )
This file can be chown
ed to the user if they are allowed to change their key.
A new PAM service called poldi
can be created.
auth sufficient pam_poldi.so
Before changing the PAM configuration at large, it may be wise to check that everything went fine so far. Poldi comes with a small test progam (in the sources' tests
directory), pam-test
. It can be used to check the newly created service.
poldi-0.4.1$ <in>./tests/pam-test poldi</in> Waiting for card... Trying authentication as user `USER'... Please enter the PIN Authentication succeeded Authenticated as user `USER'
In the relevant files for graphical authentication (e.g. /etc/pam.d/{gdm,gnome-screensaver}
), the PAM library has to be configure to use Poldi first, and revert to password authentication otherwise: poldi
must be included before pam_unix
, or the inclusion of the file containing this part.
auth include poldi
A final check confirms that all seems to be working.
poldi-0.4.1$ <in>./tests/pam-test gdm</in> Waiting for card... Trying authentication as user `USER'... Authentication succeeded Authenticated as user `USER'
GDM and Gnome Screensaver's PAM configuration files are modified to include poldi
in their auth
section before the system-{login,auth}
.
It works fine with gnome-base/gdm-2.20.11
(even with the themed greeter) and gnome-extra/gnome-screensaver-2.30.0
.
GDM and Gnome Screensaver's PAM configuration files need to include poldi
at the beginning of their auth
section requiring pam_unix{,_auth}
.
It's good for extra/gnome-screensaver 2.30.2-1
, but one'd be better taking the card with them as its PIN cache bypasses the PIN query. As for extra/gdm 2.32.0-1
, it still requires a username, but then uses the card for authentication.
If an executable named scd-event
is available in ~/.gnupg/
, scdaemon
runs it on any card status change. An example of such script comes with GnuPG's documentation.
The end of the script can be modified to lock the display on card removal, and prompt the user for their PIN when the card is reinserted.
if [ x$status = xNOCARD -a x$prev != xNOCARD ]; then gnome-screensaver-command --lock elif [ x$status = xPRESENT -a x$prev != xPRESENT ]; then gnome-screensaver-command --poke fi
Other neat things can be done at the same time like pausing/resuming the music. A more complete version of this script is here.
The status code–reader status relation seem to be a bit random depending on the reader. Browsing the GnuPG source clarifies somewhat what to expect, and how to handle it in a generic way.
/* Bit flags for the card status. */ #define APDU_CARD_USABLE (1) /* Card is present and ready for use. */ #define APDU_CARD_PRESENT (2) /* Card is just present. */ #define APDU_CARD_ACTIVE (4) /* Card is active. */
/* Bit flags for the card status. */ if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)) == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE) && !(rdrstates[0].event_state & PCSC_STATE_INUSE) ) *status |= APDU_CARD_USABLE;
fprintf (fp, "%s\n", (status & 1)? "USABLE": (status & 4)? "ACTIVE": (status & 2)? "PRESENT": "NOCARD");
The reader of the Dell E6320 only seems to report ACTIVE
when no card is present, and USABLE
otherwise. The above script snippet needs to be adapted accordingly.
GnuPG 2.0.15 is available as a precompiled package.
$ <in>sudo pkg_add gnupg-2.0.15</in>
The reader is promptly detected.
ugen0 at uhub2 port 2 "SCM Microsystems Inc. SCR33x USB Smart Card Reader" rev 2.00/5.18 addr 2
But the card isn't, though properly inserted (I checked).
$ <in>gpg2 --card-status</in> scdaemon[16167]: updating slot 0 status: 0x0000->0x0007 (0->1) scdaemon[16167]: sending signal 31 to client 16167 gpg: OpenPGP card not available: End of file $ <in>sudo gpg2 --card-status</in> gpg: WARNING: unsafe ownership on configuration file `/home/ipv6/.gnupg/gpg.conf' scdaemon[31154]: updating slot 0 status: 0x0000->0x0007 (0->1) scdaemon[31154]: sending signal 31 to client 31154 gpg: OpenPGP card not available: End of file
The trick, again, seems to be to start the GPG agent, which will then take care of starting scdaemon
.
$ <in>eval `gpg-agent --daemon --scdaemon-program /usr/local/bin/scdaemon \</in> > <in>--write-env-file --use-standard-socket \</in> > <in>--default-cache-ttl 43200 \</in> > <in>--enable-ssh-support --default-cache-ttl-ssh 43200`</in> $ <in>gpg2 --card-status</in> Application ID ...: D27600012401020000050000075C0000 Version ..........: 2.0 Manufacturer .....: ZeitControl Serial number ....: 0000075C Name of cardholder: NAME SURNAME Language prefs ...: en Sex ..............: SEX URL of public key : http://URL/OF/PUBLIC.KEY.asc Login data .......: LOGIN Signature PIN ....: not forced Key attributes ...: 2048R 2048R 2048R Max. PIN lengths .: 32 32 32 PIN retry counter : 3 3 3 Signature counter : 45 Signature key ....: FP-SSKID created ....: 2010-10-27 12:17:20 Encryption key....: FP-NESKID created ....: 2010-10-27 12:19:22 Authentication key: FP-AUTHID created ....: 2010-10-27 12:20:53 General key info..: [none]
So far so good. Let's try using the keys. Getting the public key is the first step, then the creation of dummy files to decrypt or sign.
$ <in>gpg2 --card-edit</in> [...] gpg/card> <in>fetch</in> gpg: requesting key SSKID from http server URL gpg: /home/ipv6/.gnupg/trustdb.gpg: trustdb created gpg: key KEYID: public key "NAME SURNAME <EMAIL>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) gpg/card> <in>quit</in> $ <in>echo sign > sign.txt</in> $ <in>echo encrypt > encrypt.txt</in> $ <in>gpg2 -r EMAIL -ae encrypt.txt</in> gpg: NESKID: There is no assurance this key belongs to the named user pub 2048R/NESKID 2010-10-27 NAME SURNAME <EMAIL> Primary key fingerprint: FP-KEYID Subkey fingerprint: FP-NESKID It is NOT certain that the key belongs to the person named in the user ID. If you *really* know what you are doing, you may answer the next question with yes. Use this key anyway? (y/N) <in>y</in>
Nothing new when checking the usability of the keys on the card, except a nice console-driven password getter (no X11 pinentry was installed AFAIK).
$ <in>gpg2 -sa sign.txt</in> +----------------------------------------------+ | Please enter the PIN | | [sigs done: 45] | | | | PIN <in>********</in>________________________________ | | | | <OK> <Cancel> | +----------------------------------------------+ $ <in>gpg2 --verify sign.txt.asc</in> gpg: Signature made Sun Nov 07 20:07:25 2010 EST using RSA key ID SSKID gpg: Good signature from "NAME SURNAME <EMAIL>" gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: FP-KEYID Subkey fingerprint: FP-SSKID $ <in>gpg2 -d encrypt.txt.asc</in> # This will ask for the PIN again gpg: encrypted with 2048-bit RSA key, ID NESKID, created 2010-10-27 "NAME SURNAME <EMAIL>" encrypt
All good!
Now on to SSH authentication. As the GPG agent was started to act as an SSH agent, the key fron the card is already there.
$ <in>ssh-add -L</in> ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnKeiKDT4lNozaOeCLalERZFfjWYF28uy9UUWFzyu6T8Jl9oiG/HxByeyBx+3sSHT0AEC8v8B++cK5ug+WKML9TBcecVQuDBx/ljDNq0N3Y+yMn8K/Q9Fn6EqeDx7kjuExVh+2B3siAIJzVqv8dbWloIUi/ty/FuTCgzVO7j4V+s6L8sT6mB+3LLmYhjz4DLYF2oNZlTHYRwy1V5tfvMX1VOVnKPjVcS2xMjH4yXNcxu0k3wGGKKvn/ap8fhpCTxyMeqFuDXiD+qJu5Vo0z5MyQAGndEYv05AD/2oPSCL1p9QRZ+6CP5GAjN1z9BAodUe4+/wloGw5CtbY2Ez7XaUb cardno:00050000075C $ <in>ssh SERVER</in> The authenticity of host 'SERVER (SERVERIP)' can't be established. RSA key fingerprint is SERVERSSHFP. Are you sure you want to continue connecting (yes/no)? <in>yes</in> 'Warning: Permanently added 'SERVER,SERVERIP' (RSA) to the list of known hosts. Last login: Sun Nov 7 08:43:38 2010 from CLIENTIP OpenBSD 4.7 (GENERIC) #112: Wed Mar 17 20:43:49 MDT 2010 Welcome to OpenBSD: The proactively secure Unix-like operating system. Please use the sendbug(1) utility to report bugs in the system. Before reporting a bug, please try to reproduce it with the latest version of the code. With bug reports, please try to ensure that enough information to reproduce the problem is enclosed, and if a known fix for it exists, include that as well. USER@SERVER:~$
Not even is the PIN required as it's cached by the agent!
First, enable CCID support in neoman
(from, e.g., AUR). Then, reset the %%OpenPGP%% applet. This can also be done with ''ykman'', enabling automatic card removal after 30 minutes (just need to touch for re-insertion).
ykman config usb --enable-all --autoeject-timeout 1800 --force
The default User and Admin PINs are 123456
/12345678
(management key is 010203040506070801020304050607080102030405060708
).
The OpenPGP applet can then be initialised in the same way as SmartCards (same default PINs), and the subkeys created or transferred.
Remember to export/publish the public parts of the newly-generated keys and to update the public key at the URL registered in the card.
The YubiKey can then be used with OpenKeyChain on Android, for things such as password management, email and IM (though this one is probably a bit impractical as it would require to tap the key constantly).
work in progress, but using pass seems wiser.
$ <in>gpg-connect-agent "GET_PASSPHRASE --data ssji %20 Password Enter%20password%20for%20Ssji" /bye | sed -n s/^D\\s\\+//p</in> # This will use pinentry to query the passphrase correcthorsebatterystaple $ <in>gpg-connect-agent "CLEAR_PASSPHRASE ssji" /bye</in> OK
Work in progress.
Start off there.
$ <in>openssl x509 -inform PEM -in file.crt -outform DER -out file.der</in> $ <in>gpg --card-edit</in> gpg/card> <in>admin</in> gpg/card> <in>writecert 3 < file.der</in>
Work in progress.
Start off there.
Currently, the card doesn't support SHA-256 digests, which may be set as a preference in ~/.gnupg/gpg.conf
.
personal-digest-preferences SHA256 cert-digest-algo SHA256
This may lead to the following error while generating subkeys with addcardkey
.
gpg: Note that the key does not use the suggested creation date gpg: checking created signature failed: bad signature gpg: signing failed: bad signature gpg: make_keysig_packet failed for backsig: bad signature gpg: Key generation failed: bad signature
In this case, gpg
has to be invoked with additional parameters –digest-algo SHA1 –cert-digest-algo SHA1
to override the preferences.
The same issue may later arise from trying to sign other things than subkeys
gpg: checking created signature failed: Bad signature gpg: signing failed: Bad signature gpg: signing failed: Bad signature
Unfortunately, there seems to be no other option but to comment out personal-digest-preferences SHA256
to revert to using SHA-1…
Sometimes (usually when messing with GnuPG 2), after unplugging and replugging a USB reader, it is no longer possible to access the card, and GnuPG gives error
gpg: selecting openpgp failed: No such device gpg: OpenPGP card not available: No such device
or
gpg: selecting openpgp failed: ec=6.32848 gpg: OpenPGP card not available: general error
or
gpg: selecting openpgp failed: ec=6.32848 gpg: signing failed: general error gpg: signing failed: general error
depending on the version and the requested action.
This appears to be a problem with scdaemon
which comes with GnuPG 2. Simply killing the daemon and letting GPG restart it works fine.
This may happen if an instance of gpg-agent
or scdaemon
are already running as another user. It appears to be a known bug.
To let GnuPG on additional computers/accounts use the secret material of the card, it simply needs to be read.
$ <in>gpg --card-edit</in> > <in>fetch</in> > <in>quit</in> $ <in>gpg --card-status</in>
However, if said account already has local private keys, it will not choose to use the card. Therefore, prior to issuing that command, it might be necessary to move .gnupg/secring.gpg
out of the way.
A bug in GnuPG-2.1 seems to prevent the creation of stub keys.
It might also help to trust the key ultimately (for –batch
operations).
$ <in>gpg --edit-key KEYID</in> gpg> trust Your decision?<in> 5</in> Do you really want to set this key to ultimate trust? (y/N) <in>y</in> gpg> <in>save</in>
When multiple signing keys are defined and valid (e.g., multiple OpenPGP cards), GnuPG sometimes picks the wrong one (i.e., one which is not on the currently inserted card). This leads to the following error, where the (invalid) chosen key can be checked by adding the -v
flag to the invokation.
$ <in>gpg -s</in> gpg: secret key parts are not available gpg: no default secret key: Unusable secret key gpg: signing failed: Unusable secret key $ <in>gpg -sv</in> gpg: using subkey 0xF9EB425E6D1886A7 instead of primary key 0xF012A6E298C66655 gpg: secret key parts are not available gpg: no default secret key: Unusable secret key gpg: signing failed: Unusable secret key
This is where the default-key
or, better, the local-user
, argument or config file parameter comes into play: set it to the ID of the signature key on the card.
Another quick and dirty way to deal with this problem is simply to delete the mention of the missing key's public part in the local keyring.
$ <in>gpg --edit-key 98c66655</in> gpg (GnuPG) 2.0.26; Copyright (C) 2013 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 2048R/0xF012A6E298C66655 created: 2009-05-11 expires: never usage: SC trust: ultimate validity: ultimate sub 2048R/0x26F8982D72DDD6F1 created: 2009-05-11 revoked: 2010-10-27 usage: E sub 2048R/0x6CDA813213912971 created: 2010-10-27 expired: 2012-10-26 usage: S [...] sub 2048R/0x9CA49F44ABCF4EFA created: 2011-01-22 expired: 2013-01-21 usage: S [...] sub 2048R/0xE9566B9D0957D2D3 created: 2013-01-24 expires: 2015-01-24 usage: S [...] sub 2048R/0xADCF72E06DBC3057 created: 2013-09-11 expires: 2015-09-11 usage: S [...] sub 2048R/0xF9EB425E6D1886A7 created: 2014-11-03 expires: 2016-11-02 usage: S [ultimate] (1). Olivier Mehani <shtrom@ssji.net> [...] gpg> <in>key 10</in> [...] sub* 2048R/0xF9EB425E6D1886A7 created: 2014-11-03 expires: 2016-11-02 usage: S [...] gpg> <in>kelkey</in> Do you really want to delete this key? (y/N) <in>y</in> gpg> <in>save</in> $ <in>gpg -sv</in> gpg: NOTE: signature key 0x6CDA813213912971 expired Fri 26 Oct 2012 23:17:20 AEDT gpg: NOTE: signature key 0x9CA49F44ABCF4EFA expired Mon 21 Jan 2013 14:11:29 AEDT gpg: no secret subkey for public subkey 0x6CDA813213912971 - ignoring gpg: no secret subkey for public subkey 0x9CA49F44ABCF4EFA - ignoring gpg: no secret subkey for public subkey 0xADCF72E06DBC3057 - ignoring gpg: no secret subkey for public subkey 0xF9EB425E6D1886A7 - ignoring gpg: using subkey 0xE9566B9D0957D2D3 instead of primary key 0xF012A6E298C66655 gpg: writing to stdout
I am still looking for a better solution.
Symptom: gpg –card-status
works as root, but not as an unpriviledged user.
$ <in>gpg --card-status</in> gpg: selecting openpgp failed: unknown command gpg: OpenPGP card not available: general error $ <in>sudo gpg --card-status</in> gpg: detected reader `SCM Microsystems Inc. SCR 335 [CCID Interface] (21120811308566) 00 00' Application ID ...: D27600012401020000050000075E0000 [...]
This happens just after installing libpcsclite
; trying to log in and out to see if this fixes the problem.
$ <in>lsusb</in> Bus 007 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 003 Device 002: ID 04e6:5115 SCM Microsystems, Inc. SCR335 SmartCard Reader Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 006 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 002: ID 413c:8140 Dell Computer Corp. Wireless 360 Bluetooth Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub $ <in>sudo chown shtrom /dev/bus/usb/003/002</in>
This doesn't work for long, as the root cause appears to be gnome-keyring-daemon
hijacking the GPG agent, as gpg2
kindly points out.
$ <in>gpg2 --card-status</in> gpg: WARNING: The GNOME keyring manager hijacked the GnuPG agent. gpg: WARNING: GnuPG will not work properly - please configure that tool to not interfere with the GnuPG system! gpg: selecting openpgp failed: Unsupported certificate gpg: OpenPGP card not available: Unsupported certificate
If git-tag fails with as follows,
$ <in>git tag -as test -m "test" </in> gpg: skipped "Olivier Mehani <olivier.mehani@example.net>": No secret key error: gpg failed to sign the data error: unable to sign the tag
it is because git overrules the local-user
to match the user.name
and user.email
.
This can be fixed by, in turn, overrulling git's default configuration for the signingKey
.
$ <in>git config --global user.signingKey 0xE9566B9D0957D2D3!</in> $ <in>git tag -as test -m "test"</in> gpg: skipped "0xE9566B9D0957D2D3!": duplicated $ <in>git tag -v test</in> object b6a62b330435d1d3363265836607ba1c56f9e2ab type commit tag test tagger Olivier Mehani <olivier.mehani@example.net> 1457409860 +1100 test gpg: Signature made Tue 08 Mar 2016 15:04:20 AEDT gpg: using RSA key 0xE9566B9D0957D2D3 gpg: Good signature from "Olivier Mehani <shtrom@ssji.net>" [ultimate] [...
I am uncertain, however, as to why it complains that the key ID is duplicated. This could be due to it being passed twice (once by gpg.conf
, and one by git).
gpg> key 4 ... gpg> keytocard Please select where to store the key: (2) Encryption key Your selection? 2 gpg: WARNING: such a key has already been stored on the card! Replace existing key? (y/N) y gpg: KEYTOCARD failed: Unusable secret key
This one is silly. Make sure the key is actually present in your local keyring, and not just a stub (say, from a previous keytocard
).