gpg: In search-keys return "Not found" instead of "No Data".
[gnupg.git] / g10 / call-agent.c
index 1606797..11011ae 100644 (file)
@@ -160,7 +160,8 @@ default_inq_cb (void *opaque, const char *line)
           char buf[32];
 
           if (parm->keyinfo.keyid)
-            emit_status_need_passphrase (parm->keyinfo.keyid,
+            emit_status_need_passphrase (parm->ctrl,
+                                         parm->keyinfo.keyid,
                                          parm->keyinfo.mainkeyid,
                                          parm->keyinfo.pubkey_algo);
 
@@ -193,8 +194,10 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
 
   err = get_assuan_server_version (ctx, mode, &serverversion);
   if (err)
-    log_error (_("error getting version from '%s': %s\n"),
-               servername, gpg_strerror (err));
+    log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
+             GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
+             _("error getting version from '%s': %s\n"),
+             servername, gpg_strerror (err));
   else if (compare_version_strings (serverversion, myversion) < 0)
     {
       char *warn;
@@ -206,6 +209,13 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
       else
         {
           log_info (_("WARNING: %s\n"), warn);
+          if (!opt.quiet)
+            {
+              log_info (_("Note: Outdated servers may lack important"
+                          " security fixes.\n"));
+              log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+                        "gpgconf --kill all");
+            }
           write_status_strings (STATUS_WARNING, "server_version_mismatch 0",
                                 " ", warn, NULL);
           xfree (warn);
@@ -216,10 +226,12 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
 }
 
 
+#define FLAG_FOR_CARD_SUPPRESS_ERRORS 2
+
 /* Try to connect to the agent via socket or fork it off and work by
    pipes.  Handle the server's initial greeting */
 static int
-start_agent (ctrl_t ctrl, int for_card)
+start_agent (ctrl_t ctrl, int flag_for_card)
 {
   int rc;
 
@@ -276,22 +288,58 @@ start_agent (ctrl_t ctrl, int for_card)
                   write_status_error ("set_pinentry_mode", rc);
                 }
             }
+
+          /* Pass on the request origin.  */
+          if (opt.request_origin)
+            {
+              char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+                                     str_request_origin (opt.request_origin));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                {
+                  log_error ("setting request origin '%s' failed: %s\n",
+                             str_request_origin (opt.request_origin),
+                             gpg_strerror (rc));
+                  write_status_error ("set_request_origin", rc);
+                }
+            }
+
+          /* In DE_VS mode under Windows we require that the JENT RNG
+           * is active.  */
+#ifdef HAVE_W32_SYSTEM
+          if (!rc && opt.compliance == CO_DE_VS)
+            {
+              if (assuan_transact (agent_ctx, "GETINFO jent_active",
+                                   NULL, NULL, NULL, NULL, NULL, NULL))
+                {
+                  rc = gpg_error (GPG_ERR_FORBIDDEN);
+                  log_error (_("%s is not compliant with %s mode\n"),
+                             GPG_AGENT_NAME,
+                             gnupg_compliance_option_string (opt.compliance));
+                  write_status_error ("random-compliance", rc);
+                }
+            }
+#endif /*HAVE_W32_SYSTEM*/
+
         }
     }
 
-  if (!rc && for_card && !did_early_card_test)
+  if (!rc && flag_for_card && !did_early_card_test)
     {
       /* Request the serial number of the card for an early test.  */
       struct agent_card_info_s info;
 
       memset (&info, 0, sizeof info);
 
-      rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
+      if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
+        rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
       if (!rc)
         rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
                               NULL, NULL, NULL, NULL,
                               learn_status_cb, &info);
-      if (rc)
+      if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
         {
           switch (gpg_err_code (rc))
             {
@@ -340,21 +388,23 @@ unescape_status_string (const unsigned char *s)
 }
 
 
-/* Take a 20 byte hexencoded string and put it into the provided
-   20 byte buffer FPR in binary format. */
-static int
-unhexify_fpr (const char *hexstr, unsigned char *fpr)
+/* Take a 20 or 32 byte hexencoded string and put it into the provided
+ * FPRLEN byte long buffer FPR in binary format.  Returns the actual
+ * used length of the FPR buffer or 0 on error.  */
+static unsigned int
+unhexify_fpr (const char *hexstr, unsigned char *fpr, unsigned int fprlen)
 {
   const char *s;
   int n;
 
   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
     ;
-  if (*s || (n != 40))
+  if ((*s && *s != ' ') || !(n == 40 || n == 64))
     return 0; /* no fingerprint (invalid or wrong length). */
-  for (s=hexstr, n=0; *s; s += 2, n++)
+  for (s=hexstr, n=0; *s && n < fprlen; s += 2, n++)
     fpr[n] = xtoi_2 (s);
-  return 1; /* okay */
+
+  return (n == 20 || n == 32)? n : 0;
 }
 
 /* Take the serial number from LINE and return it verbatim in a newly
@@ -439,8 +489,8 @@ agent_release_card_info (struct agent_card_info_s *info)
   xfree (info->disp_lang); info->disp_lang = NULL;
   xfree (info->pubkey_url); info->pubkey_url = NULL;
   xfree (info->login_data); info->login_data = NULL;
-  info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
-  info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
+  info->cafpr1len = info->cafpr2len = info->cafpr3len = 0;
+  info->fpr1len = info->fpr2len = info->fpr3len = 0;
   for (i=0; i < DIM(info->private_do); i++)
     {
       xfree (info->private_do[i]);
@@ -559,6 +609,10 @@ learn_status_cb (void *opaque, const char *line)
                     parm->extcap.ki = abool;
                   else if (!strcmp (p, "aac"))
                     parm->extcap.aac = abool;
+                  else if (!strcmp (p, "bt"))
+                    parm->extcap.bt = abool;
+                  else if (!strcmp (p, "kdf"))
+                    parm->extcap.kdf = abool;
                   else if (!strcmp (p, "si"))
                     parm->status_indicator = strtoul (p2, NULL, 10);
                 }
@@ -574,11 +628,11 @@ learn_status_cb (void *opaque, const char *line)
       while (spacep (line))
         line++;
       if (no == 1)
-        parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
+        parm->fpr1len = unhexify_fpr (line, parm->fpr1, sizeof parm->fpr1);
       else if (no == 2)
-        parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
+        parm->fpr2len = unhexify_fpr (line, parm->fpr2, sizeof parm->fpr2);
       else if (no == 3)
-        parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
+        parm->fpr3len = unhexify_fpr (line, parm->fpr3, sizeof parm->fpr3);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "KEY-TIME", keywordlen))
     {
@@ -594,6 +648,24 @@ learn_status_cb (void *opaque, const char *line)
       else if (no == 3)
         parm->fpr3time = strtoul (line, NULL, 10);
     }
+  else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
+    {
+      const char *hexgrp = line;
+      int no;
+
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+      if (strncmp (line, "OPENPGP.", 8))
+        ;
+      else if ((no = atoi (line+8)) == 1)
+        unhexify_fpr (hexgrp, parm->grp1, sizeof parm->grp1);
+      else if (no == 2)
+        unhexify_fpr (hexgrp, parm->grp2, sizeof parm->grp2);
+      else if (no == 3)
+        unhexify_fpr (hexgrp, parm->grp3, sizeof parm->grp3);
+    }
   else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
     {
       int no = atoi (line);
@@ -602,11 +674,11 @@ learn_status_cb (void *opaque, const char *line)
       while (spacep (line))
         line++;
       if (no == 1)
-        parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
+        parm->cafpr1len = unhexify_fpr (line, parm->cafpr1,sizeof parm->cafpr1);
       else if (no == 2)
-        parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
+        parm->cafpr2len = unhexify_fpr (line, parm->cafpr2,sizeof parm->cafpr2);
       else if (no == 3)
-        parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
+        parm->cafpr3len = unhexify_fpr (line, parm->cafpr3,sizeof parm->cafpr3);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", keywordlen))
     {
@@ -635,6 +707,21 @@ learn_status_cb (void *opaque, const char *line)
       xfree (parm->private_do[no]);
       parm->private_do[no] = unescape_status_string (line);
     }
+  else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
+    {
+      parm->kdf_do_enabled = 1;
+    }
+  else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4)
+           && strchr("123", keyword[4]))
+    {
+      unsigned char *data;
+      int no = keyword[4] - '1';
+
+      log_assert (no >= 0 && no <= 2);
+      data = unescape_status_string (line);
+      parm->uif[no] = (data[0] != 0xff);
+      xfree (data);
+    }
 
   return 0;
 }
@@ -656,18 +743,6 @@ agent_scd_learn (struct agent_card_info_s *info, int force)
   if (rc)
     return rc;
 
-  /* Send the serialno command to initialize the connection.  We don't
-     care about the data returned.  If the card has already been
-     initialized, this is a very fast command.  The main reason we
-     need to do this here is to handle a card removed case so that an
-     "l" command in --edit-card can be used to show ta newly inserted
-     card.  We request the openpgp card because that is what we
-     expect. */
-  rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
-                        NULL, NULL, NULL, NULL, NULL, NULL);
-  if (rc)
-    return rc;
-
   parm.ctx = agent_ctx;
   rc = assuan_transact (agent_ctx,
                         force ? "LEARN --sendinfo --force" : "LEARN --sendinfo",
@@ -766,10 +841,12 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
 
   return rc;
 }
+
+
 \f
 /* Call the agent to retrieve a data object.  This function returns
    the data in the same structure as used by the learn command.  It is
-   allowed to update such a structure using this commmand. */
+   allowed to update such a structure using this command. */
 int
 agent_scd_getattr (const char *name, struct agent_card_info_s *info)
 {
@@ -1024,9 +1101,37 @@ agent_scd_genkey (int keyno, int force, u32 *createtime)
   status_sc_op_failure (rc);
   return rc;
 }
+\f
+/* Return the serial number of the card or an appropriate error.  The
+   serial number is returned as a hexstring. */
+int
+agent_scd_serialno (char **r_serialno, const char *demand)
+{
+  int err;
+  char *serialno = NULL;
+  char line[ASSUAN_LINELENGTH];
 
+  err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
+  if (err)
+    return err;
+
+  if (!demand)
+    strcpy (line, "SCD SERIALNO");
+  else
+    snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
 
+  err = assuan_transact (agent_ctx, line,
+                         NULL, NULL, NULL, NULL,
+                         get_serialno_cb, &serialno);
+  if (err)
+    {
+      xfree (serialno);
+      return err;
+    }
 
+  *r_serialno = serialno;
+  return 0;
+}
 \f
 /* Send a READCERT command to the SCdaemon. */
 int
@@ -1066,8 +1171,72 @@ agent_scd_readcert (const char *certidstr,
 
   return 0;
 }
+\f
+struct card_cardlist_parm_s {
+  int error;
+  strlist_t list;
+};
+
+
+/* Callback function for agent_card_cardlist.  */
+static gpg_error_t
+card_cardlist_cb (void *opaque, const char *line)
+{
+  struct card_cardlist_parm_s *parm = opaque;
+  const char *keyword = line;
+  int keywordlen;
+
+  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+    ;
+  while (spacep (line))
+    line++;
+
+  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+    {
+      const char *s;
+      int n;
+
+      for (n=0,s=line; hexdigitp (s); s++, n++)
+        ;
+
+      if (!n || (n&1) || *s)
+        parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
+      else
+        add_to_strlist (&parm->list, line);
+    }
+
+  return 0;
+}
+
+/* Return cardlist.  */
+int
+agent_scd_cardlist (strlist_t *result)
+{
+  int err;
+  char line[ASSUAN_LINELENGTH];
+  struct card_cardlist_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  *result = NULL;
+  err = start_agent (NULL, 1);
+  if (err)
+    return err;
+
+  strcpy (line, "SCD GETINFO card_list");
 
+  err = assuan_transact (agent_ctx, line,
+                         NULL, NULL, NULL, NULL,
+                         card_cardlist_cb, &parm);
+  if (!err && parm.error)
+    err = parm.error;
+
+  if (!err)
+    *result = parm.list;
+  else
+    free_strlist (parm.list);
 
+  return 0;
+}
 \f
 /* Change the PIN of an OpenPGP card or reset the retry counter.
    CHVNO 1: Change the PIN
@@ -1363,7 +1532,7 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
   char *p;
   kbnode_t kbctx, node;
   int nkeys;
-  unsigned char grip[20];
+  unsigned char grip[KEYGRIP_LEN];
 
   err = start_agent (ctrl, 0);
   if (err)
@@ -1743,10 +1912,16 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
   snprintf (line, sizeof line, "PKSIGN%s%s",
             cache_nonce? " -- ":"",
             cache_nonce? cache_nonce:"");
+
+  if (DBG_CLOCK)
+    log_clock ("enter signing");
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
                          default_inq_cb, &dfltparm,
                          NULL, NULL);
+  if (DBG_CLOCK)
+    log_clock ("leave signing");
+
   if (err)
     xfree (get_membuf (&data, NULL));
   else
@@ -1992,7 +2167,8 @@ inq_import_key_parms (void *opaque, const char *line)
 /* Call the agent to import a key into the agent.  */
 gpg_error_t
 agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
-                  const void *key, size_t keylen, int unattended, int force)
+                  const void *key, size_t keylen, int unattended, int force,
+                 u32 *keyid, u32 *mainkeyid, int pubkey_algo)
 {
   gpg_error_t err;
   struct import_key_parm_s parm;
@@ -2002,6 +2178,9 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 
   memset (&dfltparm, 0, sizeof dfltparm);
   dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   err = start_agent (ctrl, 0);
   if (err)
@@ -2048,7 +2227,8 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 gpg_error_t
 agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
                   int openpgp_protected, char **cache_nonce_addr,
-                  unsigned char **r_result, size_t *r_resultlen)
+                  unsigned char **r_result, size_t *r_resultlen,
+                 u32 *keyid, u32 *mainkeyid, int pubkey_algo)
 {
   gpg_error_t err;
   struct cache_nonce_parm_s cn_parm;
@@ -2060,6 +2240,9 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 
   memset (&dfltparm, 0, sizeof dfltparm);
   dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   *r_result = NULL;