gpg: Improve the code to decrypt using PIV cards.
authorWerner Koch <wk@gnupg.org>
Wed, 3 Apr 2019 15:45:35 +0000 (17:45 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 3 Apr 2019 15:45:35 +0000 (17:45 +0200)
* g10/call-agent.c (agent_scd_keypairinfo): Add arg 'keyref'.
* g10/keygen.c (ask_algo): Adjust.
* g10/skclist.c (enum_secret_keys): Request the keyref directly.
--

This improves commit ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4 to avoid
looping over all keypairinfos.  This way scdaemon does not need to
compute all the keypairinfos for all keys of a card.  This patch is
possible due the enhanced READKEY command in scdaemon.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/call-agent.c
g10/call-agent.h
g10/keygen.c
g10/skclist.c

index f603d49..f6c7d39 100644 (file)
@@ -824,13 +824,15 @@ scd_keypairinfo_status_cb (void *opaque, const char *line)
 /* Read the keypairinfo lines of the current card directly from
  * scdaemon.  The list is returned as a string made up of the keygrip,
  * a space and the keyref.  The flags of the string carry the usage
- * bits. */
+ * bits.  If KEYREF is not NULL, only a single string is returned
+ * which matches the given keyref. */
 gpg_error_t
-agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
+agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list)
 {
   gpg_error_t err;
   strlist_t list = NULL;
   struct default_inq_parm_s inq_parm;
+  char line[ASSUAN_LINELENGTH];
 
   *r_list = NULL;
   err= start_agent (ctrl, 1);
@@ -839,7 +841,12 @@ agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
   memset (&inq_parm, 0, sizeof inq_parm);
   inq_parm.ctx = agent_ctx;
 
-  err = assuan_transact (agent_ctx, "SCD LEARN --keypairinfo",
+  if (keyref)
+    snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref);
+  else
+    snprintf (line, DIM(line), "SCD LEARN --keypairinfo");
+
+  err = assuan_transact (agent_ctx, line,
                          NULL, NULL,
                          default_inq_cb, &inq_parm,
                          scd_keypairinfo_status_cb, &list);
index c0018a5..c4d0a9d 100644 (file)
@@ -85,7 +85,8 @@ void agent_release_card_info (struct agent_card_info_s *info);
 int agent_scd_learn (struct agent_card_info_s *info, int force);
 
 /* Get the keypariinfo directly from scdaemon.  */
-gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list);
+gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref,
+                                   strlist_t *r_list);
 
 /* Return list of cards.  */
 int agent_scd_cardlist (strlist_t *result);
index 6ea4e72..22ac6f0 100644 (file)
@@ -2254,7 +2254,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           tty_printf (_("Serial number of the card: %s\n"), serialno);
           xfree (serialno);
 
-          err = agent_scd_keypairinfo (ctrl, &keypairlist);
+          err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist);
           if (err)
             {
               tty_printf (_("error reading the card: %s\n"),
index b4f83ea..c13566e 100644 (file)
@@ -450,38 +450,31 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
                           /* KEY-FPR not supported by the card - get
                            * the key using the keygrip.  */
                           char *keyref;
-                          strlist_t kplist, sl;
+                          strlist_t kplist;
                           const char *s;
                           int i;
 
                           err = agent_scd_getattr_one ("$ENCRKEYID", &keyref);
                           if (!err)
                             {
-                              err = agent_scd_keypairinfo (ctrl, &kplist);
+                              err = agent_scd_keypairinfo (ctrl, keyref,
+                                                           &kplist);
                               if (!err)
                                 {
-                                  for (sl = kplist; sl; sl = sl->next)
-                                    if ((s = strchr (sl->d, ' '))
-                                        && !strcmp (s+1, keyref))
-                                      break;
-                                  if (sl)
-                                    {
-                                      c->fpr2[0] = '&';
-                                      for (i=1, s=sl->d;
-                                           (*s && *s != ' '
-                                            && i < sizeof c->fpr2 - 3);
-                                           s++, i++)
-                                        c->fpr2[i] = *s;
-                                      c->fpr2[i] = 0;
-                                      name = c->fpr2;
-                                    }
-                                  else /* Restore error.  */
-                                    err = gpg_error (GPG_ERR_INV_NAME);
+                                  c->fpr2[0] = '&';
+                                  for (i=1, s=kplist->d;
+                                       (*s && *s != ' '
+                                        && i < sizeof c->fpr2 - 3);
+                                       s++, i++)
+                                    c->fpr2[i] = *s;
+                                  c->fpr2[i] = 0;
+                                  name = c->fpr2;
                                   free_strlist (kplist);
                                 }
+                              xfree (keyref);
                             }
-                          xfree (keyref);
                         }
+
                       if (err)
                         log_error ("error retrieving key from card: %s\n",
                                    gpg_strerror (err));