Fixed aegypten bug 299
[gnupg.git] / sm / keylist.c
index 07cddb3..39c4e50 100644 (file)
@@ -1,6 +1,6 @@
-/* keylist.c
+/* keylist.c - Print certificates in various formats.
  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- *               2004 Free Software Foundation, Inc.
+ *               2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -66,6 +67,12 @@ struct {
   { "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" },       
+
+  { "2.16.840.1.113730.4.1", "serverGatedCrypto.ns" }, /* Netscape. */
+  { "1.3.6.1.4.1.311.10.3.3", "serverGatedCrypto.ms"}, /* Microsoft. */
+
+  { "1.3.6.1.5.5.7.48.1.5", "ocspNoCheck" },
+
   { NULL, NULL }
 };
 
@@ -121,8 +128,13 @@ static struct {
   { "1.3.6.1.5.5.7.1.10", "acProxying" },
   { "1.3.6.1.5.5.7.1.11", "subjectInfoAccess" },
 
+  { "1.3.6.1.5.5.7.48.1", "ocsp" },
+  { "1.3.6.1.5.5.7.48.2", "caIssuers" },
+  { "1.3.6.1.5.5.7.48.3", "timeStamping" },
+  { "1.3.6.1.5.5.7.48.5", "caRepository" },
+
   /* X.509 id-ce */
-  { "2.5.29.14", "subjectKeyIdentifier"},
+  { "2.5.29.14", "subjectKeyIdentifier", 1},
   { "2.5.29.15", "keyUsage", 1 },
   { "2.5.29.16", "privateKeyUsagePeriod" },
   { "2.5.29.17", "subjectAltName", 1 },
@@ -160,6 +172,9 @@ static struct {
   { "2.16.840.1.113730.1.12", "netscape-ssl-server-name" },
   { "2.16.840.1.113730.1.13", "netscape-comment" },
 
+  /* GnuPG extensions */
+  { "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
+
   { NULL }
 };
 
@@ -207,6 +222,21 @@ print_capabilities (ksba_cert_t cert, FILE *fp)
 {
   gpg_error_t err;
   unsigned int use;
+  size_t buflen;
+  char buffer[1];
+
+  err = ksba_cert_get_user_data (cert, "is_qualified", 
+                                 &buffer, sizeof (buffer), &buflen);
+  if (!err && buflen)
+    {
+      if (*buffer)
+        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)); 
 
   err = ksba_cert_get_key_usage (cert, &use);
   if (gpg_err_code (err) == GPG_ERR_NO_DATA)
@@ -251,34 +281,46 @@ print_time (gnupg_isotime_t t, FILE *fp)
 }
 
 
-/* return an allocated string with the email address extracted from a
+/* Return an allocated string with the email address extracted from a
    DN */
 static char *
 email_kludge (const char *name)
 {
-  const unsigned char *p;
+  const char *p, *string;
   unsigned char *buf;
   int n;
 
-  if (strncmp (name, "1.2.840.113549.1.9.1=#", 22))
-    return NULL;
+  string = name;
+  for (;;)
+    {
+      p = strstr (string, "1.2.840.113549.1.9.1=#");
+      if (!p)
+        return NULL;
+      if (p == name || (p > string+1 && p[-1] == ',' && p[-2] != '\\'))
+        {
+          name = p + 22;
+          break;
+        }
+      string = p + 22;
+    }
+
+
   /* This looks pretty much like an email address in the subject's DN
      we use this to add an additional user ID entry.  This way,
      openSSL generated keys get a nicer and usable listing */
-  name += 22;    
   for (n=0, p=name; hexdigitp (p) && hexdigitp (p+1); p +=2, n++)
     ;
-  if (*p != '#' || !n)
+  if (!n)
     return NULL;
   buf = xtrymalloc (n+3);
   if (!buf)
     return NULL; /* oops, out of core */
   *buf = '<';
-  for (n=1, p=name; *p != '#'; p +=2, n++)
+  for (n=1, p=name; hexdigitp (p); p +=2, n++)
     buf[n] = xtoi_2 (p);
   buf[n++] = '>';
   buf[n] = 0;
-  return buf;
+  return (char*)buf;
 }
 
 
@@ -289,6 +331,7 @@ static void
 list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
                  FILE *fp, int have_secret)
 {
+  int rc;
   int idx;
   char truststring[2];
   char *p;
@@ -296,13 +339,45 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   char *fpr;
   ksba_isotime_t t;
   gpg_error_t valerr;
+  int algo;
+  unsigned int nbits;
+  const char *chain_id;
+  char *chain_id_buffer = NULL;
+  int is_root = 0;
 
   if (ctrl->with_validation)
     valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL, 0);
   else
     valerr = 0;
 
+
+  /* We need to get the fingerprint and the chaining ID in advance. */
+  fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+  {
+    ksba_cert_t next;
+
+    rc = gpgsm_walk_cert_chain (cert, &next);
+    if (!rc) /* We known the issuer's certificate. */
+      {
+        p = gpgsm_get_fingerprint_hexstring (next, GCRY_MD_SHA1);
+        chain_id_buffer = p;
+        chain_id = chain_id_buffer;
+        ksba_cert_release (next);
+      }
+    else if (rc == -1)  /* We have reached the root certificate. */
+      {
+        chain_id = fpr;
+        is_root = 1;
+      }
+    else
+      chain_id = NULL;
+  }
+
+
   fputs (have_secret? "crs:":"crt:", fp);
+
+  /* Note: We can't use multiple flags, like "ei", because the
+     validation check does only return one error.  */
   truststring[0] = 0;
   truststring[1] = 0;
   if ((validity & VALIDITY_REVOKED)
@@ -310,8 +385,6 @@ 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 if (valerr)
-    *truststring = 'i';
   else 
     {
       /* Lets also check whether the certificate under question
@@ -324,16 +397,30 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
           && !ksba_cert_get_validity (cert, 1, not_after)
           && *not_after && strcmp (current_time, not_after) > 0 )
         *truststring = 'e';
+      else if (valerr)
+        *truststring = 'i';
+    }
+
+  /* If we have no truststring yet (i.e. the certificate might be
+     good) and this is a root certificate, we ask the agent whether
+     this is a trusted root certificate. */
+  if (!*truststring && is_root)
+    {
+      struct rootca_flags_s dummy_flags;
+
+      rc = gpgsm_agent_istrusted (ctrl, cert, &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)
     fputs (truststring, fp);
 
-  fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
-  fprintf (fp, ":%u:%d:%s:",
-           /*keylen_of_cert (cert)*/1024,
-           /* pubkey_algo_of_cert (cert)*/1,
-           fpr+24);
+  algo = gpgsm_get_key_algo_info (cert, &nbits);
+  fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
 
   /* We assume --fixed-list-mode for gpgsm */
   ksba_cert_get_validity (cert, 0, t);
@@ -379,27 +466,12 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   /* FPR record */
   fprintf (fp, "fpr:::::::::%s:::", fpr);
   /* Print chaining ID (field 13)*/
-  {
-    ksba_cert_t next;
-    int rc;
-    
-    rc = gpgsm_walk_cert_chain (cert, &next);
-    if (!rc) /* We known the issuer's certificate. */
-      {
-        p = gpgsm_get_fingerprint_hexstring (next, GCRY_MD_SHA1);
-        fputs (p, fp);
-        xfree (p);
-        ksba_cert_release (next);
-      }
-    else if (rc == -1)  /* We reached the root certificate. */
-      {
-        fputs (fpr, fp);
-      }
-  }
+  if (chain_id)
+    fputs (chain_id, fp);
   putc (':', fp);
   putc ('\n', fp);
-  xfree (fpr); fpr = NULL;
-
+  xfree (fpr); fpr = NULL; chain_id = NULL;
+  xfree (chain_id_buffer); chain_id_buffer = NULL;
 
   if (opt.with_key_data)
     {
@@ -468,22 +540,25 @@ print_names_raw (FILE *fp, int indent, ksba_name_t name)
   for (idx=0; (s = ksba_name_enum (name, idx)); idx++)
     {
       char *p = ksba_name_get_uri (name, idx);
-      printf ("%*s%s\n", idx||indent_all?indent:0, "", p?p:s);
+      printf ("%*s", idx||indent_all?indent:0, "");
+      print_sanitized_string (fp, p?p:s, 0);
+      putc ('\n', fp);
       xfree (p);
     }
 }
 
 
 /* List one certificate in raw mode useful to have a closer look at
-   the certificate.  This one does not beautification and only minimal
+   the certificate.  This one does no beautification and only minimal
    output sanitation.  It is mainly useful for debugging. */
 static void
-list_cert_raw (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
+list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
+               ksba_cert_t cert, FILE *fp, int have_secret,
                int with_validation)
 {
   gpg_error_t err;
   size_t off, len;
-  ksba_sexp_t sexp;
+  ksba_sexp_t sexp, keyid;
   char *dn;
   ksba_isotime_t t;
   int idx, i;
@@ -534,6 +609,14 @@ list_cert_raw (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
   fprintf (fp, "      md5_fpr: %s\n", dn?dn:"error");
   xfree (dn);
 
+  dn = gpgsm_get_certid (cert);
+  fprintf (fp, "       certid: %s\n", dn?dn:"error");
+  xfree (dn);
+
+  dn = gpgsm_get_keygrip_hexstring (cert);
+  fprintf (fp, "      keygrip: %s\n", dn?dn:"error");
+  xfree (dn);
+
   ksba_cert_get_validity (cert, 0, t);
   fputs ("    notBefore: ", fp);
   gpgsm_print_time (fp, t);
@@ -547,9 +630,35 @@ list_cert_raw (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
   s = get_oid_desc (oid, NULL);
   fprintf (fp, "     hashAlgo: %s%s%s%s\n", oid, s?" (":"",s?s:"",s?")":"");
 
+  {
+    const char *algoname;
+    unsigned int nbits;
+
+    algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits));
+    fprintf (fp, "      keyType: %u bit %s\n",  nbits, algoname? algoname:"?");
+  }
+
+  /* subjectKeyIdentifier */
+  fputs ("    subjKeyId: ", fp);
+  err = ksba_cert_get_subj_key_id (cert, NULL, &keyid);
+  if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
+    {
+      if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+        fputs ("[none]\n", fp);
+      else
+        {
+          gpgsm_print_serial (fp, keyid);
+          ksba_free (keyid);
+          putc ('\n', fp);
+        }
+    }
+  else
+    fputs ("[?]\n", fp);
+
+
   /* authorityKeyIdentifier */
   fputs ("    authKeyId: ", fp);
-  err = ksba_cert_get_auth_key_id (cert, NULL, &name, &sexp);
+  err = ksba_cert_get_auth_key_id (cert, &keyid, &name, &sexp);
   if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
     {
       if (gpg_err_code (err) == GPG_ERR_NO_DATA || !name)
@@ -562,6 +671,13 @@ list_cert_raw (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
           print_names_raw (fp, -15, name);
           ksba_name_release (name);
         }
+      if (keyid)
+        {
+          fputs (" authKeyId.ki: ", fp);
+          gpgsm_print_serial (fp, keyid);
+          ksba_free (keyid);
+          putc ('\n', fp);
+        }
     }
   else
     fputs ("[?]\n", fp);
@@ -770,6 +886,18 @@ list_cert_raw (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
       else
         fprintf (fp, "  [certificate is bad: %s]\n", gpg_strerror (err));
     }
+
+  if (opt.with_ephemeral_keys && hd)
+    {
+      unsigned int blobflags;
+
+      err = keydb_get_flags (hd, KEYBOX_FLAG_BLOB, 0, &blobflags);
+      if (err)
+        fprintf (fp, "  [error getting keyflags: %s]\n", gpg_strerror (err));
+      else if ((blobflags & 2))
+        fprintf (fp, "  [stored as ephemeral]\n");
+    }
+
 }
 
 
@@ -829,6 +957,16 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
   gpgsm_print_time (fp, t);
   putc ('\n', fp);
 
+
+  {
+    const char *algoname;
+    unsigned int nbits;
+
+    algoname = gcry_pk_algo_name (gpgsm_get_key_algo_info (cert, &nbits));
+    fprintf (fp, "     key type: %u bit %s\n", nbits, algoname? algoname:"?");
+  }
+
+
   err = ksba_cert_get_key_usage (cert, &kusage);
   if (gpg_err_code (err) != GPG_ERR_NO_DATA)
     {
@@ -932,9 +1070,28 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
   fprintf (fp, "  fingerprint: %s\n", dn?dn:"error");
   xfree (dn);
 
+
+
   if (with_validation)
     {
+      gpg_error_t tmperr;
+      size_t buflen;
+      char buffer[1];
+      
       err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp, 0);
+      tmperr = ksba_cert_get_user_data (cert, "is_qualified", 
+                                        &buffer, sizeof (buffer), &buflen);
+      if (!tmperr && buflen)
+        {
+          if (*buffer)
+            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)); 
+
       if (!err)
         fprintf (fp, "  [certificate is good]\n");
       else
@@ -945,13 +1102,14 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
 
 /* Same as standard mode mode list all certifying certs too. */
 static void
-list_cert_chain (ctrl_t ctrl, ksba_cert_t cert, int raw_mode,
+list_cert_chain (ctrl_t ctrl, KEYDB_HANDLE hd,
+                 ksba_cert_t cert, int raw_mode,
                  FILE *fp, int with_validation)
 {
   ksba_cert_t next = NULL;
 
   if (raw_mode)
-    list_cert_raw (ctrl, cert, fp, 0, with_validation);
+    list_cert_raw (ctrl, hd, cert, fp, 0, with_validation);
   else
     list_cert_std (ctrl, cert, fp, 0, with_validation);
   ksba_cert_ref (cert);
@@ -960,7 +1118,7 @@ list_cert_chain (ctrl_t ctrl, ksba_cert_t cert, int raw_mode,
       ksba_cert_release (cert);
       fputs ("Certified by\n", fp);
       if (raw_mode)
-        list_cert_raw (ctrl, next, fp, 0, with_validation);
+        list_cert_raw (ctrl, hd, next, fp, 0, with_validation);
       else
         list_cert_std (ctrl, next, fp, 0, with_validation);
       cert = next;
@@ -974,15 +1132,15 @@ list_cert_chain (ctrl_t ctrl, ksba_cert_t cert, int raw_mode,
 /* List all internal keys or just the keys given as NAMES.  MODE is a
    bit vector to specify what keys are to be included; see
    gpgsm_list_keys (below) for details.  If RAW_MODE is true, the raw
-   output mode will be used intead of the standard beautified one.
+   output mode will be used instead of the standard beautified one.
  */
 static gpg_error_t
-list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
+list_internal_keys (ctrl_t ctrl, strlist_t names, FILE *fp,
                     unsigned int mode, int raw_mode)
 {
   KEYDB_HANDLE hd;
   KEYDB_SEARCH_DESC *desc = NULL;
-  STRLIST sl;
+  strlist_t sl;
   int ndesc;
   ksba_cert_t cert = NULL;
   gpg_error_t rc = 0;
@@ -1008,7 +1166,7 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
   desc = xtrycalloc (ndesc, sizeof *desc);
   if (!ndesc)
     {
-      rc = gpg_error_from_errno (errno);
+      rc = gpg_error_from_syserror ();
       log_error ("out of core\n");
       goto leave;
     }
@@ -1032,6 +1190,9 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
       
     }
 
+  if (opt.with_ephemeral_keys)
+    keydb_set_ephemeral (hd, 1);
+
   /* It would be nice to see which of the given users did actually
      match one in the keyring.  To implement this we need to have a
      found flag for each entry in desc and to set this we must check
@@ -1070,7 +1231,7 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
             {
               fprintf (fp, "%s\n", resname );
               for (i=strlen(resname); i; i-- )
-                putchar('-');
+                putc ('-', fp);
               putc ('\n', fp);
               lastresname = resname;
             }
@@ -1082,8 +1243,8 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
           char *p = gpgsm_get_keygrip_hexstring (cert);
           if (p)
             {
-              rc = gpgsm_agent_havekey (ctrl, p);
-              if (!rc)
+              rc = gpgsm_agent_havekey (ctrl, p); 
+             if (!rc)
                 have_secret = 1;
               else if ( gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
                 goto leave;
@@ -1099,11 +1260,12 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
           if (ctrl->with_colons)
             list_cert_colon (ctrl, cert, validity, fp, have_secret);
           else if (ctrl->with_chain)
-            list_cert_chain (ctrl, cert, raw_mode, fp, ctrl->with_validation);
+            list_cert_chain (ctrl, hd, cert,
+                             raw_mode, fp, ctrl->with_validation);
           else
             {
               if (raw_mode)
-                list_cert_raw (ctrl, cert, fp, have_secret,
+                list_cert_raw (ctrl, hd, cert, fp, have_secret,
                                ctrl->with_validation);
               else
                 list_cert_std (ctrl, cert, fp, have_secret,
@@ -1151,11 +1313,11 @@ list_external_cb (void *cb_value, ksba_cert_t cert)
   if (parm->with_colons)
     list_cert_colon (parm->ctrl, cert, 0, parm->fp, 0);
   else if (parm->with_chain)
-    list_cert_chain (parm->ctrl, cert, parm->raw_mode, parm->fp, 0);
+    list_cert_chain (parm->ctrl, NULL, cert, parm->raw_mode, parm->fp, 0);
   else
     {
       if (parm->raw_mode)
-        list_cert_raw (parm->ctrl, cert, parm->fp, 0, 0);
+        list_cert_raw (parm->ctrl, NULL, cert, parm->fp, 0, 0);
       else
         list_cert_std (parm->ctrl, cert, parm->fp, 0, 0);
       putc ('\n', parm->fp);
@@ -1167,7 +1329,7 @@ list_external_cb (void *cb_value, ksba_cert_t cert)
    make sense here because it would be unwise to list external secret
    keys */
 static gpg_error_t
-list_external_keys (CTRL ctrl, STRLIST names, FILE *fp, int raw_mode)
+list_external_keys (ctrl_t ctrl, strlist_t names, FILE *fp, int raw_mode)
 {
   int rc;
   struct list_external_parm_s parm;
@@ -1197,7 +1359,7 @@ list_external_keys (CTRL ctrl, STRLIST names, FILE *fp, int raw_mode)
     Bit 8: Do a raw format dump.
  */
 gpg_error_t
-gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
+gpgsm_list_keys (ctrl_t ctrl, strlist_t names, FILE *fp, unsigned int mode)
 {
   gpg_error_t err = 0;