Page MenuHome GnuPG

GnuPG: Make quick-gen-key work for keys on PIV cards
Closed, ResolvedPublic

Description

To create an OpenPGP key from the keys on a PIV card in Kleopatra I need quick-gen-key to work for PIV cards. Currently,

$ gpg --quick-gen-key --yes piv@example.net card

fails with

gpg: Serial number of the card: FF020001008A7796
gpg: Serial number of the card: FF020001008A7796
Key generation failed: No such file or directory

I think that's because quick_generate_keypair() makes the assumption

/* If KEYTIME is set we know that the key has been taken from the
 * card.  Store that flag in the parameters.  */
if (keytime)
  {
    r = xmalloc_clear (sizeof *r);
    r->key = pCARDKEY;
    r->u.abool = 1;
    r->next = para;
    para = r;
  }

For keys on PIV cards this assumption is wrong because those keys do not have a keytime.

Event Timeline

After patching the above mentioned if-clause the command fails on the first try, but it succeeds on the second try

$ gpgconf --kill all

$ gpg --quick-gen-key --yes piv@example.net card
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: Serial number of the card: FF020001008A7796
gpg: Serial number of the card: FF020001008A7796
gpg: signing failed: Not implemented
gpg: make_keysig_packet failed: Not implemented
Key generation failed: Not implemented

$ gpg --quick-gen-key --yes piv@example.net card
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: Serial number of the card: FF020001008A7796
gpg: Serial number of the card: FF020001008A7796
gpg: key BF29AD0114BC3181 marked as ultimately trusted
gpg: revocation certificate stored as '.../openpgp-revocs.d/891EB64322A32591DB77A37FBF29AD0114BC3181.rev'
public and secret key created and signed.

pub   nistp256 2020-11-17 [SC] [expires: 2022-11-17]
      891EB64322A32591DB77A37FBF29AD0114BC3181
uid                      piv@example.net
sub   rsa2048 2020-11-17 [E]

The generated key is listed as

$ gpg -K --with-fingerprint --with-fingerprint --with-keygrip '&0773CFCB90C043F3A6151B3F2FBF23726F10A48A'
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   8  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 8u
gpg: next trustdb check due at 2022-08-31
sec>  nistp256 2020-11-17 [SC] [expires: 2022-11-17]
      891E B643 22A3 2591 DB77  A37F BF29 AD01 14BC 3181
      Keygrip = 0773CFCB90C043F3A6151B3F2FBF23726F10A48A
      Card serial no. = FF020001008A7796
uid           [ultimate] piv@example.net
ssb#  rsa2048 2020-11-17 [E]
      09A2 2E65 E041 66F5 3F33  F5C4 8EAF B912 17DC CA84
      Keygrip = ED6579C1360100BE92C46ECB1A1826A63614D5AB

I'm not sure, but shouldn't the encryption subkey also be listed as card key instead of as stub?

ikloecker raised the priority of this task from Normal to Needs Triage.

Yes sure. --debug ipc should give you some insight why gpg does not thing the key is on the card.

Output of (unpatched) gpg with --debug ipc:

$ GNUPGHOME=$HOME/.cache/gnupg-master-home gpg --debug ipc --quick-gen-key --yes piv@example.net card
gpg: reading options from '[cmdline]'
gpg: NOTE: THIS IS A DEVELOPMENT VERSION!
gpg: It is only intended for test purposes and should NOT be
gpg: used in a production environment or with production keys!
gpg: enabled debug flags: ipc
gpg: DBG: chan_3 <- OK Pleased to meet you, process 7588
gpg: DBG: connection to the gpg-agent established
gpg: DBG: chan_3 -> RESET
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION ttyname=/dev/pts/7
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION ttytype=xterm-256color
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION display=:0
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION xauthority=/home/ingo/.Xauthority
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION putenv=XMODIFIERS=@im=local
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION putenv=GTK_IM_MODULE=cedilla
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION putenv=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION putenv=QT_IM_MODULE=xim
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION lc-ctype=de_DE.UTF-8
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION lc-messages=de_DE.UTF-8
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> GETINFO version
gpg: DBG: chan_3 <- D 2.3.0-beta1481
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION allow-pinentry-notify
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> OPTION agent-awareness=2.1.0
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD SERIALNO
gpg: DBG: chan_3 <- S SERIALNO FF020001008A7796
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD SERIALNO
gpg: DBG: chan_3 <- S SERIALNO FF020001008A7796
gpg: DBG: chan_3 <- OK
gpg: Serial number of the card: FF020001008A7796
gpg: DBG: chan_3 -> SCD LEARN --keypairinfo
gpg: DBG: chan_3 <- S CHV-USAGE 40 00
gpg: DBG: chan_3 <- S CHV-STATUS -2 3 -2
gpg: DBG: chan_3 <- S KEYPAIRINFO EB6A99D61EF3BC7C7934173CD9833376D773E65D PIV.9A a
gpg: DBG: chan_3 <- S KEYPAIRINFO 482BD076054B6950A6FC476C356AF029A5115BBD PIV.9E a
gpg: DBG: chan_3 <- S KEYPAIRINFO 0773CFCB90C043F3A6151B3F2FBF23726F10A48A PIV.9C sc
gpg: DBG: chan_3 <- S KEYPAIRINFO ED6579C1360100BE92C46ECB1A1826A63614D5AB PIV.9D e
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD GETATTR $SIGNKEYID
gpg: DBG: chan_3 <- S $SIGNKEYID PIV.9C
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD READKEY --info -- PIV.9C
gpg: DBG: chan_3 <- S KEYPAIRINFO 0773CFCB90C043F3A6151B3F2FBF23726F10A48A PIV.9C sc - nistp256
gpg: DBG: chan_3 <- [ 44 20 28 31 30 3a 70 75 62 6c 69 63 2d 6b 65 79 ...(118 byte(s) skipped) ]
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD SERIALNO
gpg: DBG: chan_3 <- S SERIALNO FF020001008A7796
gpg: DBG: chan_3 <- OK
gpg: Serial number of the card: FF020001008A7796
gpg: DBG: chan_3 -> SCD LEARN --keypairinfo
gpg: DBG: chan_3 <- S CHV-USAGE 40 00
gpg: DBG: chan_3 <- S CHV-STATUS -2 3 -2
gpg: DBG: chan_3 <- S KEYPAIRINFO EB6A99D61EF3BC7C7934173CD9833376D773E65D PIV.9A a
gpg: DBG: chan_3 <- S KEYPAIRINFO 482BD076054B6950A6FC476C356AF029A5115BBD PIV.9E a
gpg: DBG: chan_3 <- S KEYPAIRINFO 0773CFCB90C043F3A6151B3F2FBF23726F10A48A PIV.9C sc
gpg: DBG: chan_3 <- S KEYPAIRINFO ED6579C1360100BE92C46ECB1A1826A63614D5AB PIV.9D e
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD GETATTR $ENCRKEYID
gpg: DBG: chan_3 <- S $ENCRKEYID PIV.9D
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> SCD READKEY --info -- PIV.9D
gpg: DBG: chan_3 <- S KEYPAIRINFO ED6579C1360100BE92C46ECB1A1826A63614D5AB PIV.9D e - rsa2048
gpg: DBG: chan_3 <- [ 44 20 28 31 30 3a 70 75 62 6c 69 63 2d 6b 65 79 ...(286 byte(s) skipped) ]
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> RESET
gpg: DBG: chan_3 <- OK
gpg: DBG: chan_3 -> READKEY -- 0773CFCB90C043F3A6151B3F2FBF23726F10A48A
gpg: DBG: chan_3 <- ERR 67141713 No such file or directory <GPG Agent>
Key generation failed: No such file or directory
gpg: secmem usage: 0/32768 bytes in 0 blocks

The same problem occurs for NKS (v3) cards where the keys also do not have a keytime.

The error comes form using READKEY which is processed by gpg-agent. At this time the agent does not yet know the stub key and thus returns ENOENT. At the places before we used "SCD READKEY" which works directly with scdameon and does not need a stub file. We need to review the new(?) way of creating stub files, describe that and then fix this by either making sure tha the stub key is created first or that we use SCD READKEY there too.

In general the idea is to do away with stub files - we need them only to ask the user to insert a certain card, possible using a nice label string. But wait, since some time the stub file also carries the creation date - that could be used instead of card specific hacks to store the creation time between the card key generation and the generation of the OpenPGP cert.

The following (probably not entirely correct) patch fixes the problem because it marks the PIV card key as pCARDKEY even though keytime is 0.

diff --git a/g10/keygen.c b/g10/keygen.c
index b510525e3..03c929c0b 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -4720,7 +4720,8 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
 
   /* If KEYTIME is set we know that the key has been taken from the
    * card.  Store that flag in the parameters.  */
-  if (keytime)
+  /*if (keytime)*/
+  if(!ascii_strcasecmp (algostr, "card"))
     {
       r = xmalloc_clear (sizeof *r);
       r->key = pCARDKEY;

Go ahead (but w/o the /*if (keytime*)*/ line ;-)