* gpgsm.c: New option --with-md5-fingerprint.
authorWerner Koch <wk@gnupg.org>
Tue, 17 Feb 2004 15:05:04 +0000 (15:05 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 17 Feb 2004 15:05:04 +0000 (15:05 +0000)
* keylist.c (list_cert_std): Print MD5 fpr.

* gpgsm.c: New options --with-validation.
* server.c (option_handler): New option "with-validation".
* keylist.c (list_cert_std, list_internal_keys): New args CTRL and
WITH_VALIDATION. Changed callers to set it.
(list_external_cb, list_external_keys): Pass CTRL to the callback.
(list_cert_colon): Add arg CTRL.  Check validation if requested.
* certchain.c (unknown_criticals, allowed_ca, check_cert_policy)
(gpgsm_validate_chain): New args LISTMODE and FP.
(do_list): New helper for info output.
(find_up): New arg FIND_NEXT.
(gpgsm_validate_chain): After a bad signature try again with other
CA certificates.

* import.c (print_imported_status): New arg NEW_CERT. Print
additional STATUS_IMPORT_OK becuase that is what gpgme expects.
(check_and_store): Always call above function after import.
* server.c (get_status_string): Added STATUS_IMPORT_OK.

sm/ChangeLog
sm/certchain.c
sm/certcheck.c
sm/certlist.c
sm/gpgsm.c
sm/gpgsm.h
sm/import.c
sm/keylist.c
sm/server.c
sm/sign.c
sm/verify.c

index 4af2437..aa6e46b 100644 (file)
@@ -1,3 +1,26 @@
+2004-02-17  Werner Koch  <wk@gnupg.org>
+
+       * gpgsm.c: New option --with-md5-fingerprint.
+       * keylist.c (list_cert_std): Print MD5 fpr.
+
+       * gpgsm.c: New options --with-validation.
+       * server.c (option_handler): New option "with-validation".
+       * keylist.c (list_cert_std, list_internal_keys): New args CTRL and
+       WITH_VALIDATION. Changed callers to set it.
+       (list_external_cb, list_external_keys): Pass CTRL to the callback.
+       (list_cert_colon): Add arg CTRL.  Check validation if requested.
+       * certchain.c (unknown_criticals, allowed_ca, check_cert_policy) 
+       (gpgsm_validate_chain): New args LISTMODE and FP.
+       (do_list): New helper for info output.
+       (find_up): New arg FIND_NEXT.
+       (gpgsm_validate_chain): After a bad signature try again with other
+       CA certificates.
+
+       * import.c (print_imported_status): New arg NEW_CERT. Print
+       additional STATUS_IMPORT_OK becuase that is what gpgme expects.
+       (check_and_store): Always call above function after import.
+       * server.c (get_status_string): Added STATUS_IMPORT_OK.
+
 2004-02-13  Werner Koch  <wk@gnupg.org>
 
        * certcheck.c (gpgsm_create_cms_signature): Format a description
index bcc6666..bf55825 100644 (file)
@@ -1,5 +1,5 @@
 /* certchain.c - certificate chain validation
- *     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <errno.h>
 #include <unistd.h> 
 #include <time.h>
+#include <stdarg.h>
 #include <assert.h>
 
+#define JNLIB_NEED_LOG_LOGV /* We need log_logv. */
+
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
 #include "i18n.h"
 
+
+/* If LISTMODE is true, print FORMAT in liting mode to FP.  If
+   LISTMODE is false, use the string to print an log_info or, if
+   IS_ERROR is true, an log_error. */
+static void
+do_list (int is_error, int listmode, FILE *fp, const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format) ;
+  if (listmode)
+    {
+      if (fp)
+        {
+          fputs ("  [", fp);
+          vfprintf (fp, format, arg_ptr);
+          fputs ("]\n", fp);
+        }
+    }
+  else
+    {
+      log_logv (is_error? JNLIB_LOG_ERROR: JNLIB_LOG_INFO, format, arg_ptr);
+      log_printf ("\n");
+    }
+  va_end (arg_ptr);
+}
+
+
+
 static int
-unknown_criticals (ksba_cert_t cert)
+unknown_criticals (ksba_cert_t cert, int listmode, FILE *fp)
 {
   static const char *known[] = {
     "2.5.29.15", /* keyUsage */
@@ -57,8 +89,9 @@ unknown_criticals (ksba_cert_t cert)
         ;
       if (!known[i])
         {
-          log_error (_("critical certificate extension %s is not supported\n"),
-                     oid);
+          do_list (1, listmode, fp,
+                   _("critical certificate extension %s is not supported"),
+                   oid);
           rc = gpg_error (GPG_ERR_UNSUPPORTED_CERT);
         }
     }
@@ -69,7 +102,7 @@ unknown_criticals (ksba_cert_t cert)
 }
 
 static int
-allowed_ca (ksba_cert_t cert, int *chainlen)
+allowed_ca (ksba_cert_t cert, int *chainlen, int listmode, FILE *fp)
 {
   gpg_error_t err;
   int flag;
@@ -79,7 +112,7 @@ allowed_ca (ksba_cert_t cert, int *chainlen)
     return err;
   if (!flag)
     {
-      log_error (_("issuer certificate is not marked as a CA\n"));
+      do_list (1, listmode, fp,_("issuer certificate is not marked as a CA"));
       return gpg_error (GPG_ERR_BAD_CA_CERT);
     }
   return 0;
@@ -87,7 +120,7 @@ allowed_ca (ksba_cert_t cert, int *chainlen)
 
 
 static int
-check_cert_policy (ksba_cert_t cert)
+check_cert_policy (ksba_cert_t cert, int listmode, FILE *fplist)
 {
   gpg_error_t err;
   char *policies;
@@ -105,7 +138,7 @@ check_cert_policy (ksba_cert_t cert)
      first field is the OID of the policy and the second field either
      N or C for normal or critical extension */
 
-  if (opt.verbose > 1)
+  if (opt.verbose > 1 && !listmode)
     log_info ("certificate's policy list: %s\n", policies);
 
   /* The check is very minimal but won't give false positives */
@@ -116,7 +149,8 @@ check_cert_policy (ksba_cert_t cert)
       xfree (policies);
       if (any_critical)
         {
-          log_error ("critical marked policy without configured policies\n");
+          do_list (1, listmode, fplist,
+                   _("critical marked policy without configured policies"));
           return gpg_error (GPG_ERR_NO_POLICY_MATCH);
         }
       return 0;
@@ -131,10 +165,12 @@ check_cert_policy (ksba_cert_t cert)
       /* With no critical policies this is only a warning */
       if (!any_critical)
         {
-          log_info (_("note: certificate policy not allowed\n"));
+          do_list (0, listmode, fplist,
+                   _("note: non-critical certificate policy not allowed"));
           return 0;
         }
-      log_error (_("certificate policy not allowed\n"));
+      do_list (1, listmode, fplist,
+               _("certificate policy not allowed"));
       return gpg_error (GPG_ERR_NO_POLICY_MATCH);
     }
 
@@ -158,10 +194,12 @@ check_cert_policy (ksba_cert_t cert)
                   /* With no critical policies this is only a warning */
                   if (!any_critical)
                     {
-                      log_info (_("note: certificate policy not allowed\n"));
+                      do_list (0, listmode, fplist,
+                     _("note: non-critical certificate policy not allowed"));
                       return 0;
                     }
-                  log_error (_("certificate policy not allowed\n"));
+                  do_list (1, listmode, fplist,
+                           _("certificate policy not allowed"));
                   return gpg_error (GPG_ERR_NO_POLICY_MATCH);
                 }
               fclose (fp);
@@ -222,7 +260,7 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
 
 
 static int
-find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer)
+find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
 {
   ksba_name_t authid;
   ksba_sexp_t authidno;
@@ -236,8 +274,12 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer)
           rc = keydb_search_issuer_sn (kh, s, authidno);
           if (rc)
               keydb_search_reset (kh);
-          if (rc == -1)
-            { /* And try the ephemeral DB. */
+          
+          /* In case of an error try the ephemeral DB.  We can't do
+             that in find-netx mode because we can't keep the search
+             state then. */
+          if (rc == -1 && !find_next)
+            { 
               int old = keydb_set_ephemeral (kh, 1);
               if (!old)
                 {
@@ -248,9 +290,9 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer)
               keydb_set_ephemeral (kh, old);
             }
         }
-      /* print a note so that the user does not feel too helpless when
+      /* Print a note so that the user does not feel too helpless when
          an issuer certificate was found and gpgsm prints BAD
-         signature becuase it is not the correct one. */
+         signature because it is not the correct one. */
       if (rc == -1)
         {
           log_info ("issuer certificate (#");
@@ -267,8 +309,8 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer)
     }
   
   if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */
-      rc = keydb_search_subject (kh, issuer);
-  if (rc == -1)
+    rc = keydb_search_subject (kh, issuer);
+  if (rc == -1 && !find_next)
     {
       /* Not found, lets see whether we have one in the ephemeral key DB. */
       int old = keydb_set_ephemeral (kh, 1);
@@ -280,7 +322,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer)
       keydb_set_ephemeral (kh, old);
     }
 
-  if (rc == -1 && opt.auto_issuer_key_retrieve)
+  if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
     {
       STRLIST names = NULL;
       int count = 0;
@@ -368,7 +410,7 @@ gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next)
       goto leave; 
     }
 
-  rc = find_up (kh, start, issuer);
+  rc = find_up (kh, start, issuer, 0);
   if (rc)
     {
       /* it is quite common not to have a certificate, so better don't
@@ -413,9 +455,12 @@ gpgsm_is_root_cert (ksba_cert_t cert)
 
 \f
 /* Validate a chain and optionally return the nearest expiration time
-   in R_EXPTIME */
+   in R_EXPTIME. With LISTMODE set to 1 a special listmode is
+   activated where only information about the certificate is printed
+   to FP and no outputis send to the usual log stream. */
 int
-gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
+gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
+                      int listmode, FILE *fp)
 {
   int rc = 0, depth = 0, maxdepth;
   char *issuer = NULL;
@@ -429,14 +474,14 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
   int any_no_crl = 0;
   int any_crl_too_old = 0;
   int any_no_policy_match = 0;
-
+  int lm = listmode;
 
   gnupg_get_isotime (current_time);
   if (r_exptime)
     *r_exptime = 0;
   *exptime = 0;
 
-  if (opt.no_chain_validation)
+  if (opt.no_chain_validation && !listmode)
     {
       log_info ("WARNING: bypassing certificate chain validation\n");
       return 0;
@@ -449,7 +494,7 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
       goto leave;
     }
 
-  if (DBG_X509)
+  if (DBG_X509 && !listmode)
     gpgsm_dump_cert ("subject", cert);
 
   subject_cert = cert;
@@ -464,7 +509,7 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
 
       if (!issuer)
         {
-          log_error ("no issuer found in certificate\n");
+          do_list (1, lm, fp,  _("no issuer found in certificate"));
           rc = gpg_error (GPG_ERR_BAD_CERT);
           goto leave;
         }
@@ -477,8 +522,8 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
           rc = ksba_cert_get_validity (subject_cert, 1, not_after);
         if (rc)
           {
-            log_error (_("certificate with invalid validity: %s\n"),
-                       gpg_strerror (rc));
+            do_list (1, lm, fp, _("certificate with invalid validity: %s"),
+                     gpg_strerror (rc));
             rc = gpg_error (GPG_ERR_BAD_CERT);
             goto leave;
           }
@@ -493,28 +538,36 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
 
         if (*not_before && strcmp (current_time, not_before) < 0 )
           {
-            log_error ("certificate too young; valid from ");
-            gpgsm_dump_time (not_before);
-            log_printf ("\n");
+            do_list (1, lm, fp, _("certificate not yet valid"));
+            if (!lm)
+              {
+                log_info ("(valid from ");
+                gpgsm_dump_time (not_before);
+                log_printf (")\n");
+              }
             rc = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
             goto leave;
           }            
         if (not_after && strcmp (current_time, not_after) > 0 )
           {
-            log_error ("certificate has expired at ");
-            gpgsm_dump_time (not_after);
-            log_printf ("\n");
+            do_list (1, lm, fp, _("certificate has expired"));
+            if (!lm)
+              {
+                log_error ("(expired at ");
+                gpgsm_dump_time (not_after);
+                log_printf (")\n");
+              }
             any_expired = 1;
           }            
       }
 
-      rc = unknown_criticals (subject_cert);
+      rc = unknown_criticals (subject_cert, listmode, fp);
       if (rc)
         goto leave;
 
       if (!opt.no_policy_check)
         {
-          rc = check_cert_policy (subject_cert);
+          rc = check_cert_policy (subject_cert, listmode, fp);
           if (gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH)
             {
               any_no_policy_match = 1;
@@ -534,7 +587,7 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
               switch (gpg_err_code (rc))
                 {
                 case GPG_ERR_CERT_REVOKED:
-                  log_error (_("the certificate has been revoked\n"));
+                  do_list (1, lm, fp, _("certificate has been revoked"));
                   any_revoked = 1;
                   /* Store that in the keybox so that key listings are
                      able to return the revoked flag.  We don't care
@@ -543,18 +596,19 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
                                         VALIDITY_REVOKED);
                   break;
                 case GPG_ERR_NO_CRL_KNOWN:
-                  log_error (_("no CRL found for certificate\n"));
+                  do_list (1, lm, fp, _("no CRL found for certificate"));
                   any_no_crl = 1;
                   break;
                 case GPG_ERR_CRL_TOO_OLD:
-                  log_error (_("the available CRL is too old\n"));
-                  log_info (_("please make sure that the "
-                              "\"dirmngr\" is properly installed\n"));
+                  do_list (1, lm, fp, _("the available CRL is too old"));
+                  if (!lm)
+                    log_info (_("please make sure that the "
+                                "\"dirmngr\" is properly installed\n"));
                   any_crl_too_old = 1;
                   break;
                 default:
-                  log_error (_("checking the CRL failed: %s\n"),
-                             gpg_strerror (rc));
+                  do_list (1, lm, fp, _("checking the CRL failed: %s"),
+                           gpg_strerror (rc));
                   goto leave;
                 }
               rc = 0;
@@ -565,12 +619,13 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
         {
           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
             {
-              log_error ("selfsigned certificate has a BAD signatures\n");
+              do_list (1, lm, fp,
+                       _("selfsigned certificate has a BAD signature"));
               rc = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
                                    : GPG_ERR_BAD_CERT);
               goto leave;
             }
-          rc = allowed_ca (subject_cert, NULL);
+          rc = allowed_ca (subject_cert, NULL, listmode, fp);
           if (rc)
             goto leave;
 
@@ -579,26 +634,28 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
             ;
           else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
             {
-              int rc2;
-
-              char *fpr = gpgsm_get_fingerprint_string (subject_cert,
-                                                        GCRY_MD_SHA1);
-              log_info (_("root certificate is not marked trusted\n"));
-              log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
-              xfree (fpr);
-              rc2 = gpgsm_agent_marktrusted (subject_cert);
-              if (!rc2)
-                {
-                  log_info (_("root certificate has now"
-                              " been marked as trusted\n"));
-                  rc = 0;
-                }
-              else 
+              do_list (0, lm, fp, _("root certificate is not marked trusted"));
+              if (!lm)
                 {
-                  gpgsm_dump_cert ("issuer", subject_cert);
-                  log_info ("after checking the fingerprint, you may want "
-                            "to add it manually to the list of trusted "
-                            "certificates.\n");
+                  int rc2;
+                  char *fpr = gpgsm_get_fingerprint_string (subject_cert,
+                                                            GCRY_MD_SHA1);
+                  log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
+                  xfree (fpr);
+                  rc2 = gpgsm_agent_marktrusted (subject_cert);
+                  if (!rc2)
+                    {
+                      log_info (_("root certificate has now"
+                                  " been marked as trusted\n"));
+                      rc = 0;
+                    }
+                  else 
+                    {
+                      gpgsm_dump_cert ("issuer", subject_cert);
+                      log_info ("after checking the fingerprint, you may want "
+                                "to add it manually to the list of trusted "
+                                "certificates.\n");
+                    }
                 }
             }
           else 
@@ -613,21 +670,25 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
       depth++;
       if (depth > maxdepth)
         {
-          log_error (_("certificate chain too long\n"));
+          do_list (1, lm, fp, _("certificate chain too long\n"));
           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
           goto leave;
         }
 
       /* find the next cert up the tree */
       keydb_search_reset (kh);
-      rc = find_up (kh, subject_cert, issuer);
+      rc = find_up (kh, subject_cert, issuer, 0);
       if (rc)
         {
           if (rc == -1)
             {
-              log_info ("issuer certificate (#/");
-              gpgsm_dump_string (issuer);
-              log_printf (") not found\n");
+              do_list (0, lm, fp, _("issuer certificate not found"));
+              if (!lm)
+                {
+                  log_info ("issuer certificate: #/");
+                  gpgsm_dump_string (issuer);
+                  log_printf ("\n");
+                }
             }
           else
             log_error ("failed to find issuer's certificate: rc=%d\n", rc);
@@ -635,6 +696,7 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
           goto leave;
         }
 
+    try_another_cert:
       ksba_cert_release (issuer_cert); issuer_cert = NULL;
       rc = keydb_get_cert (kh, &issuer_cert);
       if (rc)
@@ -650,38 +712,56 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
           gpgsm_dump_cert ("issuer", issuer_cert);
         }
 
-      if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
+      rc = gpgsm_check_cert_sig (issuer_cert, subject_cert);
+      if (rc)
         {
-          log_error ("certificate has a BAD signatures\n");
+          do_list (0, lm, fp, _("certificate has a BAD signature"));
+          if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
+            {
+              rc = find_up (kh, subject_cert, issuer, 1);
+              if (!rc)
+                {
+                  do_list (0, lm, fp, _("found another possible matching "
+                                        "CA certificate - trying again"));
+                  goto try_another_cert;
+                }
+            }
+
+          /* We give a more descriptive error code than the one
+             returned from the signature checking. */
           rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
           goto leave;
         }
 
       {
         int chainlen;
-        rc = allowed_ca (issuer_cert, &chainlen);
+        rc = allowed_ca (issuer_cert, &chainlen, listmode, fp);
         if (rc)
           goto leave;
         if (chainlen >= 0 && (depth - 1) > chainlen)
           {
-            log_error (_("certificate chain longer than allowed by CA (%d)\n"),
-                       chainlen);
+            do_list (1, lm, fp,
+                     _("certificate chain longer than allowed by CA (%d)"),
+                     chainlen);
             rc = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
             goto leave;
           }
       }
 
-      rc = gpgsm_cert_use_cert_p (issuer_cert);
-      if (rc)
+      if (!listmode)
         {
-          char numbuf[50];
-          sprintf (numbuf, "%d", rc);
-          gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
-                         numbuf, NULL);
-          rc = 0;
+          rc = gpgsm_cert_use_cert_p (issuer_cert);
+          if (rc)
+            {
+              char numbuf[50];
+              sprintf (numbuf, "%d", rc);
+              gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
+                             numbuf, NULL);
+              rc = 0;
+            }
         }
 
-      if (opt.verbose)
+      if (opt.verbose && !listmode)
         log_info ("certificate is good\n");
       
       keydb_search_reset (kh);
@@ -689,10 +769,15 @@ gpgsm_validate_chain (CTRL ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
       issuer_cert = NULL;
     }
 
-  if (opt.no_policy_check)
-    log_info ("policies not checked due to --disable-policy-checks option\n");
-  if (opt.no_crl_check && !ctrl->use_ocsp)
-    log_info ("CRLs not checked due to --disable-crl-checks option\n");
+  if (!listmode)
+    {
+      if (opt.no_policy_check)
+        log_info ("policies not checked due to %s option\n",
+                  "--disable-policy-checks");
+      if (opt.no_crl_check && !ctrl->use_ocsp)
+        log_info ("CRLs not checked due to %s option\n",
+                  "--disable-crl-checks");
+    }
 
   if (!rc)
     { /* If we encountered an error somewhere during the checks, set
@@ -733,7 +818,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
   char *subject = NULL;
   KEYDB_HANDLE kh = keydb_new (0);
   ksba_cert_t issuer_cert = NULL;
-
+  
   if (opt.no_chain_validation)
     {
       log_info ("WARNING: bypassing basic certificate checks\n");
@@ -760,7 +845,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
     {
       if (gpgsm_check_cert_sig (cert, cert) )
         {
-          log_error ("selfsigned certificate has a BAD signatures\n");
+          log_error ("selfsigned certificate has a BAD signature\n");
           rc = gpg_error (GPG_ERR_BAD_CERT);
           goto leave;
         }
@@ -769,7 +854,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
     {
       /* find the next cert up the tree */
       keydb_search_reset (kh);
-      rc = find_up (kh, cert, issuer);
+      rc = find_up (kh, cert, issuer, 0);
       if (rc)
         {
           if (rc == -1)
@@ -795,7 +880,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
 
       if (gpgsm_check_cert_sig (issuer_cert, cert) )
         {
-          log_error ("certificate has a BAD signatures\n");
+          log_error ("certificate has a BAD signature\n");
           rc = gpg_error (GPG_ERR_BAD_CERT);
           goto leave;
         }
index dbd0ff1..271557a 100644 (file)
@@ -49,7 +49,7 @@ do_encode_md (gcry_md_hd_t md, int algo,  unsigned int nbits,
   asnlen = DIM(asn);
   if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
     {
-      log_error ("No object identifier for algo %d\n", algo);
+      log_error ("no object identifier for algo %d\n", algo);
       return gpg_error (GPG_ERR_INTERNAL);
     }
 
index b61f0f6..66fb463 100644 (file)
@@ -280,7 +280,7 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret,
                     }
                 }
               if (!rc)
-                rc = gpgsm_validate_chain (ctrl, cert, NULL);
+                rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL);
               if (!rc)
                 {
                   CERTLIST cl = xtrycalloc (1, sizeof *cl);
index fa3e1b2..0734c06 100644 (file)
@@ -1,5 +1,5 @@
 /* gpgsm.c - GnuPG for S/MIME 
- *     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -125,6 +125,7 @@ enum cmd_and_opt_values {
   oTextmode,
   oFingerprint,
   oWithFingerprint,
+  oWithMD5Fingerprint,
   oAnswerYes,
   oAnswerNo,
   oKeyring,
@@ -158,6 +159,7 @@ enum cmd_and_opt_values {
   oHomedir,
   oWithColons,
   oWithKeyData,
+  oWithValidation,
   oSkipVerify,
   oCompressKeys,
   oCompressSigs,
@@ -378,6 +380,8 @@ static ARGPARSE_OPTS opts[] = {
     { oNoBatch, "no-batch", 0, "@" },
     { oWithColons, "with-colons", 0, "@"},
     { oWithKeyData,"with-key-data", 0, "@"},
+    { oWithValidation, "with-validation", 0, "@"},
+    { oWithMD5Fingerprint, "with-md5-fingerprint", 0, "@"},
     { aListKeys, "list-key", 0, "@" }, /* alias */
     { aListSigs, "list-sig", 0, "@" }, /* alias */
     { aListSigs, "check-sig",0, "@" }, /* alias */
@@ -925,6 +929,8 @@ main ( int argc, char **argv)
 
         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
+        case oWithMD5Fingerprint:
+          opt.with_md5_fingerprint=1; /*fall thru*/
         case oWithFingerprint:
           with_fpr=1; /*fall thru*/
         case oFingerprint:
@@ -980,6 +986,7 @@ main ( int argc, char **argv)
 
         case oWithKeyData: opt.with_key_data=1; /* fall thru */
         case oWithColons: ctrl.with_colons = 1; break;
+        case oWithValidation: ctrl.with_validation=1; break;
 
         case oSkipVerify: opt.skip_verify=1; break;
 
@@ -1291,7 +1298,8 @@ main ( int argc, char **argv)
     case aListExternalKeys:
       for (sl=NULL; argc; argc--, argv++)
         add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout, (0 | (1<<7)));
+      gpgsm_list_keys (&ctrl, sl, stdout,
+                       (0 | (1<<7)));
       free_strlist(sl);
       break;
 
index eb40b1c..49a7318 100644 (file)
@@ -58,9 +58,12 @@ struct {
   char *outfile;    /* name of output file */
 
   int with_key_data;/* include raw key in the column delimted output */
-
+  
   int fingerprint;  /* list fingerprints in all key listings */
 
+  int with_md5_fingerprint; /* Also print an MD5 fingerprint for
+                               standard key listings. */
+
   int armor;        /* force base64 armoring (see also ctrl.with_base64) */
   int no_armor;     /* don't try to figure out whether data is base64 armored*/
 
@@ -117,13 +120,14 @@ struct server_local_s;
 /* Note that the default values for this are set by
    gpgsm_init_default_ctrl() */
 struct server_control_s {
-  int no_server;     /* we are not running under server control */
-  int  status_fd;    /* only for non-server mode */
+  int no_server;      /* We are not running under server control */
+  int  status_fd;     /* Only for non-server mode */
   struct server_local_s *server_local;
-  int with_colons;  /* use column delimited output format */
-  int with_chain;   /* include the certifying certs in a listing */
+  int with_colons;    /* Use column delimited output format */
+  int with_chain;     /* Include the certifying certs in a listing */
+  int with_validation;/* Validate each key while listing. */
 
-  int autodetect_encoding; /* try to detect the input encoding */
+  int autodetect_encoding; /* Try to detect the input encoding */
   int is_pem;         /* Is in PEM format */
   int is_base64;      /* is in plain base-64 format */
 
@@ -216,7 +220,8 @@ int gpgsm_create_cms_signature (ksba_cert_t cert, gcry_md_hd_t md, int mdalgo,
 int gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next);
 int gpgsm_is_root_cert (ksba_cert_t cert);
 int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert,
-                          ksba_isotime_t r_exptime);
+                          ksba_isotime_t r_exptime,
+                          int listmode, FILE *listfp);
 int gpgsm_basic_cert_check (ksba_cert_t cert);
 
 /*-- certlist.c --*/
index b11cd75..47f0627 100644 (file)
@@ -57,12 +57,17 @@ static gpg_error_t parse_p12 (ksba_reader_t reader, FILE **retfp);
 
 
 static void
-print_imported_status (CTRL ctrl, ksba_cert_t cert)
+print_imported_status (CTRL ctrl, ksba_cert_t cert, int new_cert)
 {
   char *fpr;
+     
   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
-  gpgsm_status2 (ctrl, STATUS_IMPORTED, fpr, "[X.509]", NULL);
+  if (new_cert)
+    gpgsm_status2 (ctrl, STATUS_IMPORTED, fpr, "[X.509]", NULL);
+
+  gpgsm_status2 (ctrl, STATUS_IMPORT_OK, 
+                 new_cert? "1":"0",  fpr, NULL);
+
   xfree (fpr);
 }
 
@@ -146,7 +151,7 @@ check_and_store (CTRL ctrl, struct stats_s *stats, ksba_cert_t cert, int depth)
   /* Some basic checks, but don't care about missing certificates;
      this is so that we are able to import entire certificate chains
      w/o requirening a special order (i.e. root-CA first).  This used
-     to be different but becuase gpgsm_verify even imports
+     to be different but because gpgsm_verify even imports
      certificates without any checks, it doesn't matter much and the
      code gets much cleaner.  A housekeeping function to remove
      certificates w/o an anchor would be nice, though. */
@@ -161,11 +166,14 @@ check_and_store (CTRL ctrl, struct stats_s *stats, ksba_cert_t cert, int depth)
 
           if (!existed)
             {
-              print_imported_status (ctrl, cert);
+              print_imported_status (ctrl, cert, 1);
               stats->imported++;
             }
           else
-            stats->unchanged++;
+            {
+              print_imported_status (ctrl, cert, 0);
+              stats->unchanged++;
+            }
             
           if (opt.verbose > 1 && existed)
             {
index 40fa6b0..e6daec6 100644 (file)
@@ -1,5 +1,6 @@
 /* keylist.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -37,6 +38,7 @@
 #include "i18n.h"
 
 struct list_external_parm_s {
+  ctrl_t ctrl;
   FILE *fp;
   int print_header;
   int with_colons;
@@ -146,28 +148,35 @@ email_kludge (const char *name)
 
 /* List one certificate in colon mode */
 static void
-list_cert_colon (ksba_cert_t cert, unsigned int validity,
+list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
                  FILE *fp, int have_secret)
 {
-  int idx, trustletter = 0;
+  int idx;
+  char truststring[2];
   char *p;
   ksba_sexp_t sexp;
   char *fpr;
   ksba_isotime_t t;
+  gpg_error_t valerr;
 
-  fputs (have_secret? "crs:":"crt:", fp);
-  trustletter = 0;
-  if ((validity & VALIDITY_REVOKED))
-    trustletter = 'r';
-#if 0
-  else if (is_not_valid (cert))
-    putc ('i', fp);
-  else if ( has_expired (cert))
-    putcr ('e', fp);
-#endif
+  if (ctrl->with_validation)
+    valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL);
   else
-    trustletter = '?';
-  putc (trustletter, fp);
+    valerr = 0;
+
+  fputs (have_secret? "crs:":"crt:", fp);
+  truststring[0] = 0;
+  truststring[1] = 0;
+  if ((validity & VALIDITY_REVOKED)
+      || gpg_err_code (valerr) == GPG_ERR_CERT_REVOKED)
+    *truststring = 'r';
+  else if (gpg_err_code (valerr) == GPG_ERR_CERT_EXPIRED)
+    *truststring = 'e';
+  else if (valerr)
+    *truststring = 'i';
+  
+  if (*truststring)
+    fputs (truststring, fp);
 
   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
   fprintf (fp, ":%u:%d:%s:",
@@ -247,7 +256,7 @@ list_cert_colon (ksba_cert_t cert, unsigned int validity,
 
   for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++)
     {
-      fprintf (fp, "uid:%c::::::::", trustletter);
+      fprintf (fp, "uid:%s::::::::", truststring);
       print_sanitized_string (fp, p, ':');
       putc (':', fp);
       putc (':', fp);
@@ -261,7 +270,7 @@ list_cert_colon (ksba_cert_t cert, unsigned int validity,
           char *pp = email_kludge (p);
           if (pp)
             {
-              fprintf (fp, "uid:%c::::::::", trustletter);
+              fprintf (fp, "uid:%s::::::::", truststring);
               print_sanitized_string (fp, pp, ':');
               putc (':', fp);
               putc (':', fp);
@@ -276,9 +285,10 @@ list_cert_colon (ksba_cert_t cert, unsigned int validity,
 
 /* List one certificate in standard mode */
 static void
-list_cert_std (ksba_cert_t cert, FILE *fp, int have_secret)
+list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
+               int with_validation)
 {
-  gpg_error_t kerr;
+  gpg_error_t err;
   ksba_sexp_t sexp;
   char *dn;
   ksba_isotime_t t;
@@ -327,12 +337,12 @@ list_cert_std (ksba_cert_t cert, FILE *fp, int have_secret)
   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)
+  err = ksba_cert_get_key_usage (cert, &kusage);
+  if (gpg_err_code (err) != GPG_ERR_NO_DATA)
     {
       fputs ("    key usage:", fp);
-      if (kerr)
-        fprintf (fp, " [error: %s]", gpg_strerror (kerr));
+      if (err)
+        fprintf (fp, " [error: %s]", gpg_strerror (err));
       else
         {
           if ( (kusage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
@@ -357,12 +367,12 @@ list_cert_std (ksba_cert_t cert, FILE *fp, int have_secret)
       putc ('\n', fp);
     }
 
-  kerr = ksba_cert_get_cert_policies (cert, &string);
-  if (gpg_err_code (kerr) != GPG_ERR_NO_DATA)
+  err = ksba_cert_get_cert_policies (cert, &string);
+  if (gpg_err_code (err) != GPG_ERR_NO_DATA)
     {
       fputs ("     policies: ", fp);
-      if (kerr)
-        fprintf (fp, "[error: %s]", gpg_strerror (kerr));
+      if (err)
+        fprintf (fp, "[error: %s]", gpg_strerror (err));
       else
         {
           for (p=string; *p; p++)
@@ -376,12 +386,12 @@ list_cert_std (ksba_cert_t cert, FILE *fp, int have_secret)
       putc ('\n', fp);
     }
 
-  kerr = ksba_cert_is_ca (cert, &is_ca, &chainlen);
-  if (kerr || is_ca)
+  err = ksba_cert_is_ca (cert, &is_ca, &chainlen);
+  if (err || is_ca)
     {
       fputs (" chain length: ", fp);
-      if (kerr)
-        fprintf (fp, "[error: %s]", gpg_strerror (kerr));
+      if (err)
+        fprintf (fp, "[error: %s]", gpg_strerror (err));
       else if (chainlen == -1)
         fputs ("unlimited", fp);
       else
@@ -389,25 +399,41 @@ list_cert_std (ksba_cert_t cert, FILE *fp, int have_secret)
       putc ('\n', fp);
     }
 
+  if (opt.with_md5_fingerprint)
+    {
+      dn = gpgsm_get_fingerprint_string (cert, GCRY_MD_MD5);
+      fprintf (fp, "      md5 fpr: %s\n", dn?dn:"error");
+      xfree (dn);
+    }
 
   dn = gpgsm_get_fingerprint_string (cert, 0);
   fprintf (fp, "  fingerprint: %s\n", dn?dn:"error");
   xfree (dn);
+
+  if (with_validation)
+    {
+      err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp);
+      if (!err)
+        fprintf (fp, "  [certificate is good]\n");
+      else
+        fprintf (fp, "  [certificate is bad: %s]\n", gpg_strerror (err));
+    }
 }
 
-/* Same as standard mode mode list all certifying certts too */
+
+/* Same as standard mode mode list all certifying certs too. */
 static void
-list_cert_chain (ksba_cert_t cert, FILE *fp)
+list_cert_chain (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int with_validation)
 {
   ksba_cert_t next = NULL;
 
-  list_cert_std (cert, fp, 0);
+  list_cert_std (ctrl, cert, fp, 0, with_validation);
   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);
+      list_cert_std (ctrl, next, fp, 0, with_validation);
       cert = next;
     }
   ksba_cert_release (cert);
@@ -471,7 +497,7 @@ list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
       
     }
 
-  /* it would be nice to see which of the given users did actually
+  /* 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
      all those entries after a match to mark all matched one -
@@ -532,12 +558,13 @@ list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode)
           || ((mode & 2) && have_secret)  )
         {
           if (ctrl->with_colons)
-            list_cert_colon (cert, validity, fp, have_secret);
+            list_cert_colon (ctrl, cert, validity, fp, have_secret);
           else if (ctrl->with_chain)
-            list_cert_chain (cert, fp);
+            list_cert_chain (ctrl, cert, fp, ctrl->with_validation);
           else
             {
-              list_cert_std (cert, fp, have_secret);
+              list_cert_std (ctrl, cert, fp, have_secret,
+                             ctrl->with_validation);
               putc ('\n', fp);
             }
         }
@@ -576,12 +603,12 @@ list_external_cb (void *cb_value, ksba_cert_t cert)
     }
 
   if (parm->with_colons)
-    list_cert_colon (cert, 0, parm->fp, 0);
+    list_cert_colon (parm->ctrl, cert, 0, parm->fp, 0);
   else if (parm->with_chain)
-    list_cert_chain (cert, parm->fp);
+    list_cert_chain (parm->ctrl, cert, parm->fp, 0);
   else
     {
-      list_cert_std (cert, parm->fp, 0);
+      list_cert_std (parm->ctrl, cert, parm->fp, 0, 0);
       putc ('\n', parm->fp);
     }
 }
@@ -597,6 +624,7 @@ list_external_keys (CTRL ctrl, STRLIST names, FILE *fp)
   struct list_external_parm_s parm;
 
   parm.fp = fp;
+  parm.ctrl = ctrl,
   parm.print_header = ctrl->no_server;
   parm.with_colons = ctrl->with_colons;
   parm.with_chain = ctrl->with_chain;
index 549c353..54b220d 100644 (file)
@@ -170,6 +170,10 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
       else
         return ASSUAN_Parameter_Error;
     }
+  else if (!strcmp (key, "with-validation"))
+    {
+      ctrl->with_validation = !!*value;
+    }
   else
     return ASSUAN_Invalid_Option;
 
@@ -898,6 +902,7 @@ get_status_string ( int no )
     case STATUS_BADMDC  : s = "BADMDC"; break;
     case STATUS_ERRMDC  : s = "ERRMDC"; break;
     case STATUS_IMPORTED        : s = "IMPORTED"; break;
+    case STATUS_IMPORT_OK        : s = "IMPORT_OK"; break;
     case STATUS_IMPORT_RES      : s = "IMPORT_RES"; break;
     case STATUS_FILE_START      : s = "FILE_START"; break;
     case STATUS_FILE_DONE       : s = "FILE_DONE"; break;
index 3f64c2e..1d3b01c 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -378,7 +378,7 @@ gpgsm_sign (CTRL ctrl, CERTLIST signerlist,
          valid. */
       rc = gpgsm_cert_use_sign_p (cert);
       if (!rc)
-        rc = gpgsm_validate_chain (ctrl, cert, NULL);
+        rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL);
       if (rc)
         goto leave;
 
index 2a95c81..bd33490 100644 (file)
@@ -458,7 +458,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
 
       if (DBG_X509)
         log_debug ("signature okay - checking certs\n");
-      rc = gpgsm_validate_chain (ctrl, cert, keyexptime);
+      rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL);
       if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
         {
           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);