Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / sm / keylist.c
index feb117d..ea2a220 100644 (file)
@@ -1,6 +1,6 @@
 /* keylist.c - Print certificates in various formats.
- * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- *               2004, 2005, 2008, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2008, 2009,
+ *               2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
+#include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 
 #include "keydb.h"
 #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
-#include "i18n.h"
-#include "tlv.h"
+#include "../common/i18n.h"
+#include "../common/tlv.h"
+#include "../common/compliance.h"
+#include "../common/pkscreening.h"
 
-struct list_external_parm_s 
+struct list_external_parm_s
 {
   ctrl_t ctrl;
   estream_t fp;
@@ -56,18 +58,18 @@ struct
   const char *name;
 } key_purpose_map[] = {
   { "1.3.6.1.5.5.7.3.1",  "serverAuth" },
-  { "1.3.6.1.5.5.7.3.2",  "clientAuth" },          
-  { "1.3.6.1.5.5.7.3.3",  "codeSigning" },      
-  { "1.3.6.1.5.5.7.3.4",  "emailProtection" },     
-  { "1.3.6.1.5.5.7.3.5",  "ipsecEndSystem" }, 
-  { "1.3.6.1.5.5.7.3.6",  "ipsecTunnel" },  
-  { "1.3.6.1.5.5.7.3.7",  "ipsecUser" },     
-  { "1.3.6.1.5.5.7.3.8",  "timeStamping" },       
-  { "1.3.6.1.5.5.7.3.9",  "ocspSigning" },    
-  { "1.3.6.1.5.5.7.3.10", "dvcs" },      
+  { "1.3.6.1.5.5.7.3.2",  "clientAuth" },
+  { "1.3.6.1.5.5.7.3.3",  "codeSigning" },
+  { "1.3.6.1.5.5.7.3.4",  "emailProtection" },
+  { "1.3.6.1.5.5.7.3.5",  "ipsecEndSystem" },
+  { "1.3.6.1.5.5.7.3.6",  "ipsecTunnel" },
+  { "1.3.6.1.5.5.7.3.7",  "ipsecUser" },
+  { "1.3.6.1.5.5.7.3.8",  "timeStamping" },
+  { "1.3.6.1.5.5.7.3.9",  "ocspSigning" },
+  { "1.3.6.1.5.5.7.3.10", "dvcs" },
   { "1.3.6.1.5.5.7.3.11", "sbgpCertAAServerAuth" },
   { "1.3.6.1.5.5.7.3.13", "eapOverPPP" },
-  { "1.3.6.1.5.5.7.3.14", "wlanSSID" },       
+  { "1.3.6.1.5.5.7.3.14", "wlanSSID" },
 
   { "2.16.840.1.113730.4.1", "serverGatedCrypto.ns" }, /* Netscape. */
   { "1.3.6.1.4.1.311.10.3.3", "serverGatedCrypto.ms"}, /* Microsoft. */
@@ -79,13 +81,13 @@ struct
 
 
 /* Do not print this extension in the list of extensions.  This is set
-   for oids which are already available via ksba fucntions. */
+   for oids which are already available via ksba functions. */
 #define OID_FLAG_SKIP 1
 /* The extension is a simple UTF8String and should be printed.  */
-#define OID_FLAG_UTF8 2 
+#define OID_FLAG_UTF8 2
 
 /* A table mapping OIDs to a descriptive string. */
-static struct 
+static struct
 {
   char *oid;
   char *name;
@@ -155,7 +157,7 @@ static struct
   { "2.5.29.20", "cRLNumber" },
   { "2.5.29.21", "cRLReason" },
   { "2.5.29.22", "expirationDate" },
-  { "2.5.29.23", "instructionCode" }, 
+  { "2.5.29.23", "instructionCode" },
   { "2.5.29.24", "invalidityDate" },
   { "2.5.29.27", "deltaCRLIndicator" },
   { "2.5.29.28", "issuingDistributionPoint" },
@@ -186,6 +188,8 @@ static struct
 
   /* GnuPG extensions */
   { "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
+  { "1.3.6.1.4.1.11591.2.2.1", "standaloneCertificate" },
+  { "1.3.6.1.4.1.11591.2.2.2", "wellKnownPrivateKey" },
 
   /* Extensions used by the Bundesnetzagentur.  */
   { "1.3.6.1.4.1.8301.3.5", "validityModel" },
@@ -194,7 +198,7 @@ static struct
 };
 
 
-/* Return the description for OID; if no description is available 
+/* Return the description for OID; if no description is available
    NULL is returned. */
 static const char *
 get_oid_desc (const char *oid, unsigned int *flag)
@@ -218,11 +222,11 @@ get_oid_desc (const char *oid, unsigned int *flag)
 static void
 print_key_data (ksba_cert_t cert, estream_t fp)
 {
-#if 0  
+#if 0
   int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
   int i;
 
-  for(i=0; i < n; i++ ) 
+  for(i=0; i < n; i++ )
     {
       es_fprintf (fp, "pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
       mpi_print(stdout, pk->pkey[i], 1 );
@@ -235,6 +239,38 @@ print_key_data (ksba_cert_t cert, estream_t fp)
 #endif
 }
 
+
+/* Various public key screenings.  (Right now just ROCA).  With
+ * COLON_MODE set the output is formatted for use in the compliance
+ * field of a colon listing.  */
+static void
+print_pk_screening (ksba_cert_t cert, int colon_mode, estream_t fp)
+{
+  gpg_error_t err;
+  gcry_mpi_t modulus;
+
+  modulus = gpgsm_get_rsa_modulus (cert);
+  if (modulus)
+    {
+      err = screen_key_for_roca (modulus);
+      if (!err)
+        ;
+      else if (gpg_err_code (err) == GPG_ERR_TRUE)
+        {
+          if (colon_mode)
+            es_fprintf (fp, colon_mode > 1? " %d":"%d", 6001);
+          else
+            es_fprintf (fp, "    screening: ROCA vulnerability detected\n");
+        }
+      else if (!colon_mode)
+        es_fprintf (fp, "    screening: [ROCA check failed: %s]\n",
+                    gpg_strerror (err));
+      gcry_mpi_release (modulus);
+    }
+
+}
+
+
 static void
 print_capabilities (ksba_cert_t cert, estream_t fp)
 {
@@ -243,18 +279,18 @@ print_capabilities (ksba_cert_t cert, estream_t fp)
   size_t buflen;
   char buffer[1];
 
-  err = ksba_cert_get_user_data (cert, "is_qualified", 
+  err = ksba_cert_get_user_data (cert, "is_qualified",
                                  &buffer, sizeof (buffer), &buflen);
   if (!err && buflen)
     {
       if (*buffer)
         es_putc ('q', fp);
-    }    
+    }
   else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
     ; /* Don't know - will not get marked as 'q' */
   else
     log_debug ("get_user_data(is_qualified) failed: %s\n",
-               gpg_strerror (err)); 
+               gpg_strerror (err));
 
   err = ksba_cert_get_key_usage (cert, &use);
   if (gpg_err_code (err) == GPG_ERR_NO_DATA)
@@ -268,11 +304,11 @@ print_capabilities (ksba_cert_t cert, estream_t fp)
       return;
     }
   if (err)
-    { 
+    {
       log_error (_("error getting key usage information: %s\n"),
                  gpg_strerror (err));
       return;
-    } 
+    }
 
   if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
     es_putc ('e', fp);
@@ -286,8 +322,6 @@ print_capabilities (ksba_cert_t cert, estream_t fp)
     es_putc ('S', fp);
   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
     es_putc ('C', fp);
-
-  es_putc (':', fp);
 }
 
 
@@ -296,7 +330,7 @@ print_time (gnupg_isotime_t t, estream_t fp)
 {
   if (!t || !*t)
     ;
-  else 
+  else
     es_fputs (t, fp);
 }
 
@@ -344,6 +378,23 @@ email_kludge (const char *name)
 }
 
 
+/* Print the compliance flags to field 18.  ALGO is the gcrypt algo
+ * number.  NBITS is the length of the key in bits.  */
+static void
+print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
+                        estream_t fp)
+{
+  int any = 0;
+
+  if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL))
+    {
+      es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp);
+      any++;
+    }
+
+  if (opt.with_key_screening)
+    print_pk_screening (cert, 1+any, fp);
+}
 
 
 /* List one certificate in colon mode */
@@ -406,20 +457,25 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
     *truststring = 'r';
   else if (gpg_err_code (valerr) == GPG_ERR_CERT_EXPIRED)
     *truststring = 'e';
-  else 
+  else
     {
       /* Lets also check whether the certificate under question
          expired.  This is merely a hack until we found a proper way
          to store the expiration flag in the keybox. */
       ksba_isotime_t current_time, not_after;
-  
+
       gnupg_get_isotime (current_time);
       if (!opt.ignore_expiration
           && !ksba_cert_get_validity (cert, 1, not_after)
           && *not_after && strcmp (current_time, not_after) > 0 )
         *truststring = 'e';
       else if (valerr)
-        *truststring = 'i';
+        {
+          if (gpgsm_cert_has_well_known_private_key (cert))
+            *truststring = 'w';  /* Well, this is dummy CA.  */
+          else
+            *truststring = 'i';
+        }
       else if (ctrl->with_validation && !is_root)
         *truststring = 'f';
     }
@@ -431,21 +487,25 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
     {
       struct rootca_flags_s dummy_flags;
 
-      rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
-      if (!rc)
-        *truststring = 'u';  /* Yes, we trust this one (ultimately). */
-      else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
-        *truststring = 'n';  /* No, we do not trust this one. */
-      /* (in case of an error we can't tell anything.) */
+      if (gpgsm_cert_has_well_known_private_key (cert))
+        *truststring = 'w';  /* Well, this is dummy CA.  */
+      else
+        {
+          rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
+          if (!rc)
+            *truststring = 'u';  /* Yes, we trust this one (ultimately). */
+          else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
+            *truststring = 'n';  /* No, we do not trust this one. */
+          /* (in case of an error we can't tell anything.) */
+        }
     }
-  
+
   if (*truststring)
     es_fputs (truststring, fp);
 
   algo = gpgsm_get_key_algo_info (cert, &nbits);
   es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
 
-  /* We assume --fixed-list-mode for gpgsm */
   ksba_cert_get_validity (cert, 0, t);
   print_time (t, fp);
   es_putc (':', fp);
@@ -457,7 +517,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
     {
       int len;
       const unsigned char *s = sexp;
-      
+
       if (*s == '(')
         {
           s++;
@@ -479,28 +539,37 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
       xfree (p);
     }
   es_putc (':', fp);
-  /* Field 11, signature class - not used */ 
+  /* Field 11, signature class - not used */
   es_putc (':', fp);
-  /* Field 12, capabilities: */ 
+  /* Field 12, capabilities: */
   print_capabilities (cert, fp);
+  es_putc (':', fp);
   /* Field 13, not used: */
   es_putc (':', fp);
-  if (have_secret)
+  /* Field 14, not used: */
+  es_putc (':', fp);
+  if (have_secret || ctrl->with_secret)
     {
       char *cardsn;
 
       p = gpgsm_get_keygrip_hexstring (cert);
-      if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn) && cardsn)
+      if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn)
+          && (cardsn || ctrl->with_secret))
         {
-          /* Field 14, not used: */
-          es_putc (':', fp);
-          /* Field 15:  Token serial number.  */
-          es_fputs (cardsn, fp);
-          es_putc (':', fp);
+          /* Field 15:  Token serial number or secret key indicator.  */
+          if (cardsn)
+            es_fputs (cardsn, fp);
+          else if (ctrl->with_secret)
+            es_putc ('+', fp);
         }
       xfree (cardsn);
       xfree (p);
     }
+  es_putc (':', fp);  /* End of field 15. */
+  es_putc (':', fp);  /* End of field 16. */
+  es_putc (':', fp);  /* End of field 17. */
+  print_compliance_flags (cert, algo, nbits, fp);
+  es_putc (':', fp);  /* End of field 18. */
   es_putc ('\n', fp);
 
   /* FPR record */
@@ -513,16 +582,16 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   xfree (fpr); fpr = NULL; chain_id = NULL;
   xfree (chain_id_buffer); chain_id_buffer = NULL;
 
-  if (opt.with_key_data)
+  /* Always print the keygrip.  */
+  if ( (p = gpgsm_get_keygrip_hexstring (cert)))
     {
-      if ( (p = gpgsm_get_keygrip_hexstring (cert)))
-        {
-          es_fprintf (fp, "grp:::::::::%s:\n", p);
-          xfree (p);
-        }
-      print_key_data (cert, fp);
+      es_fprintf (fp, "grp:::::::::%s:\n", p);
+      xfree (p);
     }
 
+  if (opt.with_key_data)
+    print_key_data (cert, fp);
+
   kludge_uid = NULL;
   for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++)
     {
@@ -584,7 +653,7 @@ print_names_raw (estream_t fp, int indent, ksba_name_t name)
       es_fputs ("none\n", fp);
       return;
     }
-  
+
   for (idx=0; (s = ksba_name_enum (name, idx)); idx++)
     {
       char *p = ksba_name_get_uri (name, idx);
@@ -597,7 +666,7 @@ print_names_raw (estream_t fp, int indent, ksba_name_t name)
 
 
 static void
-print_utf8_extn_raw (estream_t fp, int indent, 
+print_utf8_extn_raw (estream_t fp, int indent,
                      const unsigned char *der, size_t derlen)
 {
   gpg_error_t err;
@@ -621,7 +690,7 @@ print_utf8_extn_raw (estream_t fp, int indent,
 
 
 static void
-print_utf8_extn (estream_t fp, int indent, 
+print_utf8_extn (estream_t fp, int indent,
                  const unsigned char *der, size_t derlen)
 {
   gpg_error_t err;
@@ -800,21 +869,21 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
         {
           if ( (kusage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
             es_fputs (" digitalSignature", fp);
-          if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION))  
+          if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION))
             es_fputs (" nonRepudiation", fp);
-          if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) 
+          if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
             es_fputs (" keyEncipherment", fp);
           if ( (kusage & KSBA_KEYUSAGE_DATA_ENCIPHERMENT))
             es_fputs (" dataEncipherment", fp);
-          if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT))    
+          if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT))
             es_fputs (" keyAgreement", fp);
           if ( (kusage & KSBA_KEYUSAGE_KEY_CERT_SIGN))
             es_fputs (" certSign", fp);
-          if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN))  
+          if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN))
             es_fputs (" crlSign", fp);
           if ( (kusage & KSBA_KEYUSAGE_ENCIPHER_ONLY))
             es_fputs (" encipherOnly", fp);
-          if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY))  
+          if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY))
             es_fputs (" decipherOnly", fp);
         }
       es_putc ('\n', fp);
@@ -825,7 +894,7 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
   es_fputs ("  extKeyUsage: ", fp);
   err = ksba_cert_get_ext_key_usages (cert, &string);
   if (gpg_err_code (err) != GPG_ERR_NO_DATA)
-    { 
+    {
       if (err)
         es_fprintf (fp, "[error: %s]", gpg_strerror (err));
       else
@@ -1106,21 +1175,21 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
         {
           if ( (kusage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
             es_fputs (" digitalSignature", fp);
-          if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION))  
+          if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION))
             es_fputs (" nonRepudiation", fp);
-          if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) 
+          if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
             es_fputs (" keyEncipherment", fp);
           if ( (kusage & KSBA_KEYUSAGE_DATA_ENCIPHERMENT))
             es_fputs (" dataEncipherment", fp);
-          if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT))    
+          if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT))
             es_fputs (" keyAgreement", fp);
           if ( (kusage & KSBA_KEYUSAGE_KEY_CERT_SIGN))
             es_fputs (" certSign", fp);
-          if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN))  
+          if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN))
             es_fputs (" crlSign", fp);
           if ( (kusage & KSBA_KEYUSAGE_ENCIPHER_ONLY))
             es_fputs (" encipherOnly", fp);
-          if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY))  
+          if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY))
             es_fputs (" decipherOnly", fp);
         }
       es_putc ('\n', fp);
@@ -1128,7 +1197,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
 
   err = ksba_cert_get_ext_key_usages (cert, &string);
   if (gpg_err_code (err) != GPG_ERR_NO_DATA)
-    { 
+    {
       es_fputs ("ext key usage: ", fp);
       if (err)
         es_fprintf (fp, "[error: %s]", gpg_strerror (err));
@@ -1216,6 +1285,19 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
   es_fprintf (fp, "  fingerprint: %s\n", dn?dn:"error");
   xfree (dn);
 
+  if (opt.with_keygrip)
+    {
+      dn = gpgsm_get_keygrip_hexstring (cert);
+      if (dn)
+        {
+          es_fprintf (fp, "      keygrip: %s\n", dn);
+          xfree (dn);
+        }
+    }
+
+  if (opt.with_key_screening)
+    print_pk_screening (cert, 0, fp);
+
   if (have_secret)
     {
       char *cardsn;
@@ -1232,20 +1314,20 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
       gpg_error_t tmperr;
       size_t buflen;
       char buffer[1];
-      
+
       err = gpgsm_validate_chain (ctrl, cert, "", NULL, 1, fp, 0, NULL);
-      tmperr = ksba_cert_get_user_data (cert, "is_qualified", 
+      tmperr = ksba_cert_get_user_data (cert, "is_qualified",
                                         &buffer, sizeof (buffer), &buflen);
       if (!tmperr && buflen)
         {
           if (*buffer)
             es_fputs ("  [qualified]\n", fp);
-        }    
+        }
       else if (gpg_err_code (tmperr) == GPG_ERR_NOT_FOUND)
         ; /* Don't know - will not get marked as 'q' */
       else
         log_debug ("get_user_data(is_qualified) failed: %s\n",
-                   gpg_strerror (tmperr)); 
+                   gpg_strerror (tmperr));
 
       if (!err)
         es_fprintf (fp, "  [certificate is good]\n");
@@ -1255,7 +1337,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
 }
 
 
-/* Same as standard mode mode list all certifying certs too. */
+/* Same as standard mode list all certifying certs too. */
 static void
 list_cert_chain (ctrl_t ctrl, KEYDB_HANDLE hd,
                  ksba_cert_t cert, int raw_mode,
@@ -1304,7 +1386,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
   int have_secret;
   int want_ephemeral = ctrl->with_ephemeral_keys;
 
-  hd = keydb_new (0);
+  hd = keydb_new ();
   if (!hd)
     {
       log_error ("keydb_new failed\n");
@@ -1316,7 +1398,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
     ndesc = 1;
   else
     {
-      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++) 
+      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
         ;
     }
 
@@ -1330,21 +1412,21 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
 
   if (!names)
     desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
-  else 
+  else
     {
-      for (ndesc=0, sl=names; sl; sl = sl->next) 
+      for (ndesc=0, sl=names; sl; sl = sl->next)
         {
-          rc = classify_user_id (sl->d, desc+ndesc);
+          rc = classify_user_id (sl->d, desc+ndesc, 0);
           if (rc)
             {
-              log_error ("key `%s' not found: %s\n",
+              log_error ("key '%s' not found: %s\n",
                          sl->d, gpg_strerror (rc));
               rc = 0;
             }
           else
             ndesc++;
         }
-      
+
     }
 
   /* If all specifications are done by fingerprint or keygrip, we
@@ -1376,11 +1458,11 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
 
   /* Suppress duplicates at least when they follow each other.  */
   lastresname = NULL;
-  while (!(rc = keydb_search (hd, desc, ndesc)))
+  while (!(rc = keydb_search (ctrl, hd, desc, ndesc)))
     {
       unsigned int validity;
 
-      if (!names) 
+      if (!names)
         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
       rc = keydb_get_flags (hd, KEYBOX_FLAG_VALIDITY, 0, &validity);
@@ -1390,7 +1472,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
           goto leave;
         }
       rc = keydb_get_cert (hd, &cert);
-      if (rc) 
+      if (rc)
         {
           log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
           goto leave;
@@ -1406,11 +1488,11 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
        }
 
       resname = keydb_get_resource_name (hd);
-      
-      if (lastresname != resname ) 
+
+      if (lastresname != resname )
         {
           int i;
-          
+
           if (ctrl->no_server)
             {
               es_fprintf (fp, "%s\n", resname );
@@ -1427,7 +1509,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
           char *p = gpgsm_get_keygrip_hexstring (cert);
           if (p)
             {
-              rc = gpgsm_agent_havekey (ctrl, p); 
+              rc = gpgsm_agent_havekey (ctrl, p);
               if (!rc)
                 have_secret = 1;
               else if ( gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
@@ -1437,8 +1519,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
             }
         }
 
-      if (!mode
-          || ((mode & 1) && !have_secret)
+      if (!mode          || ((mode & 1) && !have_secret)
           || ((mode & 2) && have_secret)  )
         {
           if (ctrl->with_colons)
@@ -1458,7 +1539,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
             }
         }
 
-      ksba_cert_release (lastcert); 
+      ksba_cert_release (lastcert);
       lastcert = cert;
       cert = NULL;
     }
@@ -1466,10 +1547,10 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
     rc = 0;
   if (rc)
     log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
-  
+
  leave:
   ksba_cert_release (cert);
-  ksba_cert_release (lastcert); 
+  ksba_cert_release (lastcert);
   xfree (desc);
   keydb_release (hd);
   return rc;
@@ -1482,7 +1563,7 @@ list_external_cb (void *cb_value, ksba_cert_t cert)
 {
   struct list_external_parm_s *parm = cb_value;
 
-  if (keydb_store_cert (cert, 1, NULL))
+  if (keydb_store_cert (parm->ctrl, cert, 1, NULL))
     log_error ("error storing certificate as ephemeral\n");
 
   if (parm->print_header)
@@ -1529,7 +1610,7 @@ list_external_keys (ctrl_t ctrl, strlist_t names, estream_t fp, int raw_mode)
   parm.raw_mode  = raw_mode;
 
   rc = gpgsm_dirmngr_lookup (ctrl, names, 0, list_external_cb, &parm);
-  if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1 
+  if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1
       || gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = 0; /* "Not found" is not an error here. */
   if (rc)
@@ -1538,7 +1619,7 @@ list_external_keys (ctrl_t ctrl, strlist_t names, estream_t fp, int raw_mode)
 }
 
 /* List all keys or just the key given as NAMES.
-   MODE controls the operation mode: 
+   MODE controls the operation mode:
     Bit 0-2:
       0 = list all public keys but don't flag secret ones
       1 = list only public keys
@@ -1557,6 +1638,6 @@ gpgsm_list_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
   if ((mode & (1<<6)))
     err = list_internal_keys (ctrl, names, fp, (mode & 3), (mode&256));
   if (!err && (mode & (1<<7)))
-    err = list_external_keys (ctrl, names, fp, (mode&256)); 
+    err = list_external_keys (ctrl, names, fp, (mode&256));
   return err;
 }