Outils pour utilisateurs

Outils du site


Panneau latéral

Tips

Divers

Projets

Ham Radio

Machines

Research

Privé

Études

tips:openpgpsmartcard

Using an OpenPGP SmartCard

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).

Hardware

Reader

SCM SCR335 SmartCard reader

$ dmesg | tail -n 2
usb 6-2: new full speed USB device using uhci_hcd and address 3
usb 6-2: configuration #1 chosen from 1 choice
$ lsusb -v -d 04e6:5115
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)

Card

OpenPGP SmartCard 2.0

$ gpg  --card-status
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]

Card Initialisation

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…

$ gpg --change-pin
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? 3
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
PIN changed.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 4
Reset Code set.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? q

Then, the card can be personnalised by setting its metadata.

$ gpg --card-edit
[...]
gpg/card> admin
Admin commands are allowed

gpg/card> name
Cardholder's surname: SURNAME
Cardholder's given name: NAME

gpg/card> url
URL to retrieve public key: http://URL/OF/PUBLIC.KEY.asc

gpg/card> login
Login data (account name): LOGIN

gpg/card> sex
Sex ((M)ale, (F)emale or space): S

gpg/card> quit

Transferring PGP Subkeys

Primer on Subkeys

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.

Signature and Authentication Subkeys

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!

$ gpg --edit-key KEYID
gpg> addcardkey
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? 1

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) 2y
Key expires at Fri 26 Oct 2012 11:17:20 PM EST
Is this correct? (y/N) y
Really create? (y/N) y

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> addcardkey
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? 3
[...]

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> save

Encryption Subkey

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.

  1. Generate the encryption subkey on the machine
  2. Back it up
  3. Transfer it to the card

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.

Local Generation

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.

$ gpg --edit-key KEYID
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> addkey
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? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 2048
Requested keysize is 2048 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 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  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> save
Backup

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.

$ gpg -a --export-secret-keys KEYID > KEYID.key.`date +%Y%m%d_%H%M`.asc

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.

$ mkdir .gnupg-backup-test
$ chmod 700 .gnupg-backup-test/
$ gpg --homedir ~/.gnupg-backup-test --import KEYID.key.full.20130912_1456.asc
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
$ gpg --homedir ~/.gnupg-backup-test -evr EMAIL | gpg --homedir ~/.gnupg-backup-test -d
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) y
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
blituri
gpg: encrypted with 2048-bit RSA key, ID ENCID, created 2013-09-12
      "NAME SURNAME <EMAIL>"
blituri
$ rm -rf .gnupg-backup-test

This backup file has to be securely stored and looked after!

Copy to the Card

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.

$ mkdir .gnupg-keytocard
$ chmod 700 .gnupg-keytocard/
$ gpg --homedir ~/.gnupg-keytocard --import KEYID.key.full.20130912_1456.asc
[...]
$ gpg --homedir ~/.gnupg-keytocard --card-status
[...]
$ gpg --homedir ~/.gnupg-keytocard --edit-key KEYID
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> toggle

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> key 2 # 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> keytocard
Signature key ....: FP-SSKID
Encryption key....: FP-ENCID
Authentication key: FP-AUTHID

Please select where to store the key:
   (2) Encryption key
Your selection? 2

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
$ rm -rf .gnupg-keytocard
$ gpg --card-status # To update the normal keyring

Testing

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
$ cat > sign.txt
this is signed
^D
$ cat > encrypt.txt
this is encrypted
^D
$ gpg -r EMAIL -ae encrypt.txt
$ gpg -s sign.txt
gpg: selecting openpgp failed: ec=6.112
gpg: signing failed: general error
gpg: signing failed: general error
$ gpg -d encrypt.txt.asc
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
$ gpg -d encrypt.txt.asc
gpg: encrypted with 2048-bit RSA key, ID NESKID, created 2010-10-27
      "NAME SURNAME <EMAIL>"
this is encrypted
$ gpg -s sign.txt
$ gpg --verify sign.txt.gpg
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!

Forwarding GPG and SSH keys through the Agent

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.

$ gpgconf --list-dirs
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

TLDR;

Configure the GPG Agent to emulate the SSH agent and create a restricted GPG Agent socket for forwarding.

LOCALMACHINE:~/.gnupg/gpg-agent.conf
enable-ssh-support
extra-socket ~/.gnupg/S.gpg-agent.extra

Tell SSH to forward the restricted GPG Agent socket.

LOCALMACHINE:~/.ssh/config
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

SERVER:/etc/ssh/sshd_config
StreamLocalBindUnlink yes

Configure interactive shell sessions so they use the right agents whether local or forwarded.

GnuPG Agent as SSH Agent

For gpg-agent to also act as an SSH agent, the following needs to be added to its configuration file.

~/.gnupg/gpg-agent.conf
enable-ssh-support

gpgconf can tell us what socket to use as SSH_AUTH_SOCK.

$ gpgconf --list-dirs agent-ssh-socket
/run/user/1000/gnupg/S.gpg-agent.ssh
$ export SSH_AUTH_SOCK=`gpgconf --list-dirs agent-ssh-socket`
$ echo $SSH_AUTH_SOCK
/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.

$ ssh-add -L
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).

$ ssh-copy-id SERVER
USER@SERVER's password:
$ ssh -A SERVER
SERVER$ echo $SSH_AUTH_SOCK
SERVER$ ssh-add -L
ssh-rsa CARDKEYGPGFP cardno:00050000075E

And after entering the card's PIN into GPG's pinentry dialog, that's it!

Configuring the GPG Agent on the Client for SSH Forwarding (GnuPG<2.1)

:!: 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.

$ 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
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;
$ 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;

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

$ 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`

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.

$ ssh-add -l
2048 CARDKEYFP cardno:00050000075C (RSA)
2048 SSHKEYFP /home/USER/.ssh/id_rsa (RSA)
[...]

Forwarding GPG keys

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.

~/.gnupg/gpg-agent.conf
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).

~/.ssh/config
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

$ ssh -A SERVER
SERVER$ echo $SSH_AUTH_SOCK
SERVER$ <in gpg-connect-agent /bye
gpg-connect-agent: connection to agent is in restricted mode
SERVER$ gpg --list-secret-keys
/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]


And signatures and decryption work
<code consoleio>
$ echo test | gpg -q -s -e -r shtrom@ssji.net | gpg  -q -v -d
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$ gpg --card-status
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$ ^D
$ ssh SERVER
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.

/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
$ ssh SERVER
SERVER$ ^D
$ ssh SERVER
SERVER$ ^D

Finishing Touches: Login Script

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.

~/bin/init-agent.sh
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.

~/.bashrc
. ~/bin/init-agent.sh

Local User Authentication

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.

$ poldi-ctrl -d
Serial number: D27600012401020000050000075C0000
Signing key fingerprint: AUTHFP
Key:
(public-key
 (rsa
  (n #00A729E88A0D3E25368CDA39E08B6A51116457E3598176F2ECBD514585CF2BBA4FC265F68886FC7C41C9EC81C7EDEC4874F40040BCBFC07EF9C2B9BA0F9628C2FD4C171E71542E0C1C7F9630CDAB437763EC8C9FC2BF43D167E84A9E0F1EE48EE131561FB6077B2200827356ABFC75B5A5A08522FEDCBF16E4C283354EEE3E15FACE8BF2C4FA981FB72CB998863CF80CB605DA83599531D8470CB5579B5FBCC5F554E56728F8D5712DB13231F8C9735CC6ED24DF018628ABE7FDAA7C7E1A424F1C8C7AA16E0D7883FAA26EE55A34CF93324001A774462FD39003FF6A0F4822F5A7D41167EE823F91808CDD73F410287547B8FBFC25A06C390AD6D8D84CFB5DA51B#)
  (e #00010001#)
  )
 )

Configure Poldi

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).

/etc/poldi/poldi.conf
(...)
auth-method localdb
(...)

Bind Card and User

An administrator can then associate the card with a local account.

$ sudo mkdir -p /etc/poldi/localdb/keys
$ echo "`poldi-ctrl --print-serialno` $USER" | sudo tee -a /etc/poldi/localdb/users
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.

$ poldi-ctrl --print-key| sudo tee -a /etc/poldi/localdb/keys/`poldi-ctrl --print-serialno`
(public-key
 (rsa
  (n #00A729E88A0D3E25368CDA39E08B6A51116457E3598176F2ECBD514585CF2BBA4FC265F68886FC7C41C9EC81C7EDEC4874F40040BCBFC07EF9C2B9BA0F9628C2FD4C171E71542E0C1C7F9630CDAB437763EC8C9FC2BF43D167E84A9E0F1EE48EE131561FB6077B2200827356ABFC75B5A5A08522FEDCBF16E4C283354EEE3E15FACE8BF2C4FA981FB72CB998863CF80CB605DA83599531D8470CB5579B5FBCC5F554E56728F8D5712DB13231F8C9735CC6ED24DF018628ABE7FDAA7C7E1A424F1C8C7AA16E0D7883FAA26EE55A34CF93324001A774462FD39003FF6A0F4822F5A7D41167EE823F91808CDD73F410287547B8FBFC25A06C390AD6D8D84CFB5DA51B#)
  (e #00010001#)
  )
 )

This file can be chowned to the user if they are allowed to change their key.

PAM Setup

A new PAM service called poldi can be created.

/etc/pam.d/poldi
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$ ./tests/pam-test poldi
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.

/etc/pam.d/gdm
auth    include    poldi

A final check confirms that all seems to be working.

poldi-0.4.1$ ./tests/pam-test gdm
Waiting for card...
Trying authentication as user `USER'...
Authentication succeeded
Authenticated as user `USER'

Gentoo

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.

ArchLinux

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.

Lock Screen on Card Removal

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.

scd-event
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.

gnupg-2.0.18/scd/apdu.h
/* 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.  */
gnupg-2.0.18/scd/apdu.c
/* 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;
gnupg-2.0.18/scd/command.c
              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.

Doing the same with OpenBSD (4.8)

GnuPG 2.0.15 is available as a precompiled package.

$ sudo pkg_add gnupg-2.0.15

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).

$ gpg2 --card-status
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
$ sudo gpg2 --card-status
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.

$ eval `gpg-agent --daemon --scdaemon-program /usr/local/bin/scdaemon \
>     --write-env-file --use-standard-socket \
>     --default-cache-ttl 43200 \
>     --enable-ssh-support --default-cache-ttl-ssh 43200`
$ gpg2 --card-status
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.

$ gpg2 --card-edit
[...]

gpg/card> fetch
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> quit
$ echo sign > sign.txt
$ echo encrypt > encrypt.txt
$ gpg2 -r EMAIL -ae encrypt.txt
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) y

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).

$ gpg2 -sa sign.txt

                +----------------------------------------------+
                | Please enter the PIN                         |
                | [sigs done: 45]                              |
                |                                              |
                | PIN ********________________________________ |
                |                                              |
                |      <OK>                        <Cancel>    |
                +----------------------------------------------+

$ gpg2 --verify sign.txt.asc
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
$ gpg2 -d encrypt.txt.asc # 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.

$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnKeiKDT4lNozaOeCLalERZFfjWYF28uy9UUWFzyu6T8Jl9oiG/HxByeyBx+3sSHT0AEC8v8B++cK5ug+WKML9TBcecVQuDBx/ljDNq0N3Y+yMn8K/Q9Fn6EqeDx7kjuExVh+2B3siAIJzVqv8dbWloIUi/ty/FuTCgzVO7j4V+s6L8sT6mB+3LLmYhjz4DLYF2oNZlTHYRwy1V5tfvMX1VOVnKPjVcS2xMjH4yXNcxu0k3wGGKKvn/ap8fhpCTxyMeqFuDXiD+qJu5Vo0z5MyQAGndEYv05AD/2oPSCL1p9QRZ+6CP5GAjN1z9BAodUe4+/wloGw5CtbY2Ez7XaUb cardno:00050000075C
$ ssh SERVER
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)? yes
'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!

YubiKey Neo

First, enable CCID support in neoman (from, e.g., AUR). Then, reset the %%OpenPGP%% applet.

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

Storing other passwords in the agent

FIXME work in progress, but using pass seems wiser.

$ gpg-connect-agent "GET_PASSPHRASE --data ssji %20 Password Enter%20password%20for%20Ssji" /bye | sed -n s/^D\\s\\+//p # This will use pinentry to query the passphrase
correcthorsebatterystaple
$ gpg-connect-agent "CLEAR_PASSPHRASE ssji" /bye
OK

SSL keys on the card

FIXME Work in progress.

Start off there.

$ openssl x509 -inform PEM -in file.crt -outform DER -out file.der
$ gpg --card-edit
gpg/card> admin
gpg/card> writecert 3 < file.der

Two-factor encryption with LUKS

FIXME Work in progress.

Start off there.

Troubleshooting

Errors Signing

Currently, the card doesn't support SHA-256 digests, which may be set as a preference in ~/.gnupg/gpg.conf.

~/.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…

Error Accessing the Card Reader after Unplug/Replug

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.

GDM Fails to Access the Card

This may happen if an instance of gpg-agent or scdaemon are already running as another user. It appears to be a known bug.

Using the Card on Multiple Computers

To let GnuPG on additional computers/accounts use the secret material of the card, it simply needs to be read.

$ gpg --card-edit
> fetch
> quit
$ gpg --card-status

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).

$ gpg --edit-key KEYID
gpg> trust
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
gpg> save

Missing key chosen for signing

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.

$ gpg -s
gpg: secret key parts are not available
gpg: no default secret key: Unusable secret key
gpg: signing failed: Unusable secret key
$ gpg -sv
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.

$ gpg --edit-key 98c66655
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> key 10
[...]
sub* 2048R/0xF9EB425E6D1886A7  created: 2014-11-03  expires: 2016-11-02  usage: S
[...]
gpg> kelkey
Do you really want to delete this key? (y/N) y
gpg> save
$ gpg -sv
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.

Permissions problems

Symptom: gpg –card-status works as root, but not as an unpriviledged user.

$ gpg --card-status
gpg: selecting openpgp failed: unknown command
gpg: OpenPGP card not available: general error
$ sudo gpg --card-status
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.

$ lsusb
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
$ sudo chown shtrom /dev/bus/usb/003/002

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.

$ gpg2 --card-status
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

Git fails to sign tags

If git-tag fails with as follows,

$ git tag -as test -m "test" 
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.

$ git config --global user.signingKey 0xE9566B9D0957D2D3!
$ git tag -as test -m "test"
gpg: skipped "0xE9566B9D0957D2D3!": duplicated
$ git tag -v test
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).

References

tips/openpgpsmartcard.txt · Dernière modification: 2016-12-29 09:31 par shtrom