* gpgsm.c (main): Set the prefixes for assuan logging.
[gnupg.git] / sm / keylist.c
index 6c57897..7b7402f 100644 (file)
@@ -1,5 +1,5 @@
 /* keylist.c
- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <time.h>
 #include <assert.h>
 
+#include "gpgsm.h"
+
 #include <gcrypt.h>
 #include <ksba.h>
 
-#include "gpgsm.h"
 #include "keydb.h"
+#include "i18n.h"
 
+struct list_external_parm_s {
+  FILE *fp;
+  int print_header;
+  int with_colons;
+  int with_chain;
+};
 
 
 
@@ -56,25 +64,49 @@ print_key_data (KsbaCert cert, FILE *fp)
 static void
 print_capabilities (KsbaCert cert, FILE *fp)
 {
-  putc ('e', fp);
-  putc ('s', fp);
-  putc ('c', fp);
-  putc ('E', fp);
-  putc ('S', fp);
-  putc ('C', fp);
-  putc (':', fp);
+  KsbaError err;
+  unsigned int use;
+
+  err = ksba_cert_get_key_usage (cert, &use);
+  if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+    {
+      putc ('e', fp);
+      putc ('s', fp);
+      putc ('c', fp);
+      putc ('E', fp);
+      putc ('S', fp);
+      putc ('C', 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)))
+    putc ('e', fp);
+  if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
+    putc ('s', fp);
+  if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
+    putc ('c', fp);
+  if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
+    putc ('E', fp);
+  if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
+    putc ('S', fp);
+  if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
+    putc ('C', fp);
 }
 
 
 static void
-print_time (time_t t, FILE *fp)
+print_time (gnupg_isotime_t t, FILE *fp)
 {
-  if (!t)
+  if (!t || !*t)
     ;
-  else if ( t == (time_t)(-1) )
-    putc ('?', fp);
-  else
-    fprintf (fp, "%lu", (unsigned long)t);
+  else 
+    fputs (t, fp);
 }
 
 
@@ -118,6 +150,8 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
   int idx, trustletter = 0;
   char *p;
   KsbaSexp sexp;
+  char *fpr;
+  ksba_isotime_t t;
 
   fputs (have_secret? "crs:":"crt:", fp);
   trustletter = 0;
@@ -135,16 +169,20 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
       putc (trustletter, fp);
     }
 
-  fprintf (fp, ":%u:%d::",
+  fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+  fprintf (fp, ":%u:%d:%s:",
            /*keylen_of_cert (cert)*/1024,
-           /* pubkey_algo_of_cert (cert)*/'R');
+           /* pubkey_algo_of_cert (cert)*/1,
+           fpr+24);
 
   /* we assume --fixed-list-mode for gpgsm */
-  print_time ( ksba_cert_get_validity (cert, 0), fp);
-  putc (':', fp);
-  print_time ( ksba_cert_get_validity (cert, 1), fp);
+  ksba_cert_get_validity (cert, 0, t);
+  print_time (t, fp);
   putc (':', fp);
+  ksba_cert_get_validity (cert, 1, t);
+  print_time ( t, fp);
   putc (':', fp);
+  /* field 8, serial number: */
   if ((sexp = ksba_cert_get_serial (cert)))
     {
       int len;
@@ -162,19 +200,41 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
       xfree (sexp);
     }
   putc (':', fp);
+  /* field 9, ownertrust - not used here */
   putc (':', fp);
+  /* field 10, old user ID - we use it here for the issuer DN */
   if ((p = ksba_cert_get_issuer (cert,0)))
     {
       print_sanitized_string (fp, p, ':');
       xfree (p);
     }
   putc (':', fp);
+  /* field 11, signature class - not used */ 
+  putc (':', fp);
+  /* field 12, capabilities: */ 
   print_capabilities (cert, fp);
+  putc (':', fp);
   putc ('\n', fp);
 
-  p = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
-  fprintf (fp, "fpr:::::::::%s:\n", p);
-  xfree (p);
+  /* FPR record */
+  fprintf (fp, "fpr:::::::::%s:::", fpr);
+  xfree (fpr); fpr = NULL;
+  /* print chaining ID (field 13)*/
+  {
+    KsbaCert next;
+    
+    if (!gpgsm_walk_cert_chain (cert, &next))
+      {
+        p = gpgsm_get_fingerprint_hexstring (next, GCRY_MD_SHA1);
+        fputs (p, fp);
+        xfree (p);
+        ksba_cert_release (next);
+      }
+  }
+  putc (':', fp);
+  putc ('\n', fp);
+
+
   if (opt.with_key_data)
     {
       if ( (p = gpgsm_get_keygrip_hexstring (cert)))
@@ -214,17 +274,152 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
 }
 
 
+/* List one certificate in standard mode */
+static void
+list_cert_std (KsbaCert cert, FILE *fp, int have_secret)
+{
+  KsbaError kerr;
+  KsbaSexp sexp;
+  char *dn;
+  ksba_isotime_t t;
+  int idx;
+  int is_ca, chainlen;
+  unsigned int kusage;
+  char *string, *p;
+
+  sexp = ksba_cert_get_serial (cert);
+  fputs ("Serial number: ", fp);
+  gpgsm_print_serial (fp, sexp);
+  ksba_free (sexp);
+  putc ('\n', fp);
+
+  dn = ksba_cert_get_issuer (cert, 0);
+  fputs ("       Issuer: ", fp);
+  gpgsm_print_name (fp, dn);
+  ksba_free (dn);
+  putc ('\n', fp);
+  for (idx=1; (dn = ksba_cert_get_issuer (cert, idx)); idx++)
+    {
+      fputs ("          aka: ", fp);
+      gpgsm_print_name (fp, dn);
+      ksba_free (dn);
+      putc ('\n', fp);
+    }
+
+  dn = ksba_cert_get_subject (cert, 0);
+  fputs ("      Subject: ", fp);
+  gpgsm_print_name (fp, dn);
+  ksba_free (dn);
+  putc ('\n', fp);
+  for (idx=1; (dn = ksba_cert_get_subject (cert, idx)); idx++)
+    {
+      fputs ("          aka: ", fp);
+      gpgsm_print_name (fp, dn);
+      ksba_free (dn);
+      putc ('\n', fp);
+    }
+
+  ksba_cert_get_validity (cert, 0, t);
+  fputs ("     validity: ", fp);
+  gpgsm_print_time (fp, t);
+  fputs (" through ", fp);
+  ksba_cert_get_validity (cert, 1, t);
+  gpgsm_print_time (fp, t);
+  putc ('\n', fp);
+
+  kerr = ksba_cert_get_key_usage (cert, &kusage);
+  if (gpg_err_code (kerr) != GPG_ERR_NO_DATA)
+    {
+      fputs ("    key usage:", fp);
+      if (kerr)
+        fprintf (fp, " [error: %s]", gpg_strerror (kerr));
+      else
+        {
+          if ( (kusage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
+            fputs (" digitalSignature", fp);
+          if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION))  
+            fputs (" nonRepudiation", fp);
+          if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) 
+            fputs (" keyEncipherment", fp);
+          if ( (kusage & KSBA_KEYUSAGE_DATA_ENCIPHERMENT))
+            fputs (" dataEncipherment", fp);
+          if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT))    
+            fputs (" keyAgreement", fp);
+          if ( (kusage & KSBA_KEYUSAGE_KEY_CERT_SIGN))
+            fputs (" certSign", fp);
+          if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN))  
+            fputs (" crlSign", fp);
+          if ( (kusage & KSBA_KEYUSAGE_ENCIPHER_ONLY))
+            fputs (" encipherOnly", fp);
+          if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY))  
+            fputs (" decipherOnly", fp);
+        }
+      putc ('\n', fp);
+    }
+
+  kerr = ksba_cert_get_cert_policies (cert, &string);
+  if (gpg_err_code (kerr) != GPG_ERR_NO_DATA)
+    {
+      fputs ("     policies: ", fp);
+      if (kerr)
+        fprintf (fp, "[error: %s]", gpg_strerror (kerr));
+      else
+        {
+          for (p=string; *p; p++)
+            {
+              if (*p == '\n')
+                *p = ',';
+            }
+          print_sanitized_string (fp, string, 0);
+          xfree (string);
+        }
+      putc ('\n', fp);
+    }
+
+  kerr = ksba_cert_is_ca (cert, &is_ca, &chainlen);
+  if (kerr || is_ca)
+    {
+      fputs (" chain length: ", fp);
+      if (kerr)
+        fprintf (fp, "[error: %s]", gpg_strerror (kerr));
+      else if (chainlen == -1)
+        fputs ("unlimited", fp);
+      else
+        fprintf (fp, "%d", chainlen);
+      putc ('\n', fp);
+    }
+
+
+  dn = gpgsm_get_fingerprint_string (cert, 0);
+  fprintf (fp, "  fingerprint: %s\n", dn?dn:"error");
+  xfree (dn);
+}
+
+/* Same as standard mode mode list all certifying certts too */
+static void
+list_cert_chain (KsbaCert cert, FILE *fp)
+{
+  KsbaCert next = NULL;
+
+  list_cert_std (cert, fp, 0);
+  ksba_cert_ref (cert);
+  while (!gpgsm_walk_cert_chain (cert, &next))
+    {
+      ksba_cert_release (cert);
+      fputs ("Certified by\n", fp);
+      list_cert_std (next, fp, 0);
+      cert = next;
+    }
+  ksba_cert_release (cert);
+  putc ('\n', fp);
+}
+
 
 \f
-/* List all keys or just the key given as NAMES.
-   MODE controls the operation mode: 
-      0 = list all public keys but don't flag secret ones
-      1 = list only public keys
-      2 = list only secret keys
-      3 = list secret and public keys
+/* List all internal keys or just the key given as NAMES.
  */
-void
-gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
+static void
+list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
 {
   KEYDB_HANDLE hd;
   KEYDB_SEARCH_DESC *desc = NULL;
@@ -267,7 +462,7 @@ gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
           if (rc)
             {
               log_error ("key `%s' not found: %s\n",
-                         sl->d, gnupg_strerror (rc));
+                         sl->d, gpg_strerror (rc));
               rc = 0;
             }
           else
@@ -292,7 +487,7 @@ gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
       rc = keydb_get_cert (hd, &cert);
       if (rc) 
         {
-          log_error ("keydb_get_cert failed: %s\n", gnupg_strerror (rc));
+          log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
       
@@ -330,14 +525,19 @@ gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
         {
           if (ctrl->with_colons)
             list_cert_colon (cert, fp, have_secret);
+          else if (ctrl->with_chain)
+            list_cert_chain (cert, fp);
           else
-            list_cert_colon (cert, fp, have_secret);
+            {
+              list_cert_std (cert, fp, have_secret);
+              putc ('\n', fp);
+            }
         }
       ksba_cert_release (cert); 
       cert = NULL;
     }
   if (rc && rc != -1)
-    log_error ("keydb_search failed: %s\n", gnupg_strerror (rc));
+    log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
   
  leave:
   ksba_cert_release (cert);
@@ -347,3 +547,72 @@ gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
 
 
 
+static void
+list_external_cb (void *cb_value, KsbaCert cert)
+{
+  struct list_external_parm_s *parm = cb_value;
+
+  if (keydb_store_cert (cert, 1, NULL))
+    log_error ("error storing certificate as ephemeral\n");
+
+  if (parm->print_header)
+    {
+      const char *resname = "[external keys]";
+      int i;
+
+      fprintf (parm->fp, "%s\n", resname );
+      for (i=strlen(resname); i; i-- )
+        putchar('-');
+      putc ('\n', parm->fp);
+      parm->print_header = 0;
+    }
+
+  if (parm->with_colons)
+    list_cert_colon (cert, parm->fp, 0);
+  else if (parm->with_chain)
+    list_cert_chain (cert, parm->fp);
+  else
+    {
+      list_cert_std (cert, parm->fp, 0);
+      putc ('\n', parm->fp);
+    }
+}
+
+
+/* List external keys similar to internal one.  Note: mode does not
+   make sense here because it would be unwise to list external secret
+   keys */
+static void
+list_external_keys (CTRL ctrl, STRLIST names, FILE *fp)
+{
+  int rc;
+  struct list_external_parm_s parm;
+
+  parm.fp = fp;
+  parm.print_header = ctrl->no_server;
+  parm.with_colons = ctrl->with_colons;
+  parm.with_chain = ctrl->with_chain;
+
+  rc = gpgsm_dirmngr_lookup (ctrl, names, list_external_cb, &parm);
+  if (rc)
+    log_error ("listing external keys failed: %s\n", gpg_strerror (rc));
+}
+
+/* List all keys or just the key given as NAMES.
+   MODE controls the operation mode: 
+    Bit 0-2:
+      0 = list all public keys but don't flag secret ones
+      1 = list only public keys
+      2 = list only secret keys
+      3 = list secret and public keys
+    Bit 6: list internal keys
+    Bit 7: list external keys
+ */
+void
+gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
+{
+  if ((mode & (1<<6)))
+      list_internal_keys (ctrl, names, fp, (mode & 3));
+  if ((mode & (1<<7)))
+      list_external_keys (ctrl, names, fp); 
+}