* gpgsm.c (main): Set the prefixes for assuan logging.
[gnupg.git] / sm / keylist.c
index 18d570e..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;
+};
+
 
 
 static void
@@ -60,7 +68,7 @@ print_capabilities (KsbaCert cert, FILE *fp)
   unsigned int use;
 
   err = ksba_cert_get_key_usage (cert, &use);
-  if (err == KSBA_No_Data)
+  if (gpg_err_code (err) == GPG_ERR_NO_DATA)
     {
       putc ('e', fp);
       putc ('s', fp);
@@ -73,19 +81,19 @@ print_capabilities (KsbaCert cert, FILE *fp)
   if (err)
     { 
       log_error (_("error getting key usage information: %s\n"),
-                 ksba_strerror (err));
+                 gpg_strerror (err));
       return;
     } 
 
-  if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
+  if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
     putc ('e', fp);
-  if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
+  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))
+  if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
     putc ('E', fp);
-  if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
+  if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
     putc ('S', fp);
   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
     putc ('C', fp);
@@ -93,14 +101,12 @@ print_capabilities (KsbaCert cert, FILE *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);
 }
 
 
@@ -144,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;
@@ -161,14 +169,18 @@ 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)*/1);
+           /* pubkey_algo_of_cert (cert)*/1,
+           fpr+24);
 
   /* we assume --fixed-list-mode for gpgsm */
-  print_time ( ksba_cert_get_validity (cert, 0), fp);
+  ksba_cert_get_validity (cert, 0, t);
+  print_time (t, fp);
   putc (':', fp);
-  print_time ( ksba_cert_get_validity (cert, 1), 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)))
@@ -205,9 +217,8 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret)
   putc ('\n', fp);
 
   /* FPR record */
-  p = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
-  fprintf (fp, "fpr:::::::::%s:::", p);
-  xfree (p);
+  fprintf (fp, "fpr:::::::::%s:::", fpr);
+  xfree (fpr); fpr = NULL;
   /* print chaining ID (field 13)*/
   {
     KsbaCert next;
@@ -263,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;
@@ -316,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
@@ -341,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;
         }
       
@@ -379,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);
@@ -396,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); 
+}