Print status of CRL checks in the audit log.
[gnupg.git] / sm / certchain.c
index 04b7e05..e9a1aad 100644 (file)
@@ -1,6 +1,6 @@
 /* certchain.c - certificate chain validation
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007 Free Software Foundation, Inc.
+ *               2006, 2007, 2008 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -60,6 +60,8 @@ struct chain_item_s
 typedef struct chain_item_s *chain_item_t;
 
 
+static int is_root_cert (ksba_cert_t cert,
+                         const char *issuerdn, const char *subjectdn);
 static int get_regtp_ca_info (ctrl_t ctrl, ksba_cert_t cert, int *chainlen);
 
 
@@ -331,8 +333,9 @@ check_cert_policy (ksba_cert_t cert, int listmode, estream_t fplist)
       /* With no critical policies this is only a warning */
       if (!any_critical)
         {
-          do_list (0, listmode, fplist,
-                   _("note: non-critical certificate policy not allowed"));
+          if (!opt.quiet)
+            do_list (0, listmode, fplist,
+                     _("note: non-critical certificate policy not allowed"));
           return 0;
         }
       do_list (1, listmode, fplist,
@@ -536,6 +539,8 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh,
   strlist_t names = NULL;
   int count = 0;
   char *pattern;
+
+  (void)kh;
       
   if (opt.verbose)
     log_info (_("looking up issuer from the Dirmngr cache\n"));
@@ -563,7 +568,7 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh,
 
   if (opt.verbose)
     log_info (_("number of matching certificates: %d\n"), count);
-  if (rc) 
+  if (rc && !opt.quiet
     log_info (_("dirmngr cache-only key lookup failed: %s\n"),
               gpg_strerror (rc));
   return (!rc && count)? 0 : -1;
@@ -593,9 +598,9 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
         {
           rc = keydb_search_issuer_sn (kh, s, authidno);
           if (rc)
-              keydb_search_reset (kh);
+            keydb_search_reset (kh);
           
-          /* In case of an error, try to get the certifcate from the
+          /* In case of an error, try to get the certificate from the
              dirmngr.  That is done by trying to put that certifcate
              into the ephemeral DB and let the code below do the
              actual retrieve.  Thus there is no error checking.
@@ -667,7 +672,9 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
       /* Print a note so that the user does not feel too helpless when
          an issuer certificate was found and gpgsm prints BAD
          signature because it is not the correct one. */
-      if (rc == -1)
+      if (rc == -1 && opt.quiet)
+        ;
+      else if (rc == -1)
         {
           log_info ("%sissuer certificate ", find_next?"next ":"");
           if (keyid)
@@ -697,12 +704,14 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
     rc = keydb_search_subject (kh, issuer);
   if (rc == -1 && !find_next)
     {
+      int old;
+
       /* Also try to get it from the Dirmngr cache.  The function
          merely puts it into the ephemeral database.  */
       find_up_dirmngr (ctrl, kh, NULL, issuer, 0);
 
       /* Not found, let us see whether we have one in the ephemeral key DB. */
-      int old = keydb_set_ephemeral (kh, 1);
+      old = keydb_set_ephemeral (kh, 1);
       if (!old)
         {
           keydb_search_reset (kh);
@@ -752,7 +761,7 @@ gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next)
       goto leave;
     }
 
-  if (!strcmp (issuer, subject))
+  if (is_root_cert (start, issuer, subject))
     {
       rc = -1; /* we are at the root */
       goto leave; 
@@ -784,6 +793,75 @@ gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next)
 }
 
 
+/* Helper for gpgsm_is_root_cert.  This one is used if the subject and
+   issuer DNs are already known.  */
+static int
+is_root_cert (ksba_cert_t cert, const char *issuerdn, const char *subjectdn)
+{
+  gpg_error_t err;
+  int result = 0;
+  ksba_sexp_t serialno;
+  ksba_sexp_t ak_keyid;
+  ksba_name_t ak_name;
+  ksba_sexp_t ak_sn;
+  const char *ak_name_str;
+  ksba_sexp_t subj_keyid = NULL;
+
+  if (!issuerdn || !subjectdn)
+    return 0;  /* No.  */
+
+  if (strcmp (issuerdn, subjectdn))
+    return 0;  /* No.  */
+
+  err = ksba_cert_get_auth_key_id (cert, &ak_keyid, &ak_name, &ak_sn);
+  if (err)
+    {
+      if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+        return 1; /* Yes. Without a authorityKeyIdentifier this needs
+                     to be the Root certifcate (our trust anchor).  */
+      log_error ("error getting authorityKeyIdentifier: %s\n",
+                 gpg_strerror (err));
+      return 0; /* Well, it is broken anyway.  Return No. */
+    }
+
+  serialno = ksba_cert_get_serial (cert);
+  if (!serialno)
+    {
+      log_error ("error getting serialno: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Check whether the auth name's matches the issuer name+sn.  If
+     that is the case this is a root certificate.  */
+  ak_name_str = ksba_name_enum (ak_name, 0);
+  if (ak_name_str
+      && !strcmp (ak_name_str, issuerdn) 
+      && !cmp_simple_canon_sexp (ak_sn, serialno))
+    {
+      result = 1;  /* Right, CERT is self-signed.  */
+      goto leave;
+    } 
+   
+  /* Similar for the ak_keyid. */
+  if (ak_keyid && !ksba_cert_get_subj_key_id (cert, NULL, &subj_keyid)
+      && !cmp_simple_canon_sexp (ak_keyid, subj_keyid))
+    {
+      result = 1;  /* Right, CERT is self-signed.  */
+      goto leave;
+    } 
+
+
+ leave:
+  ksba_free (subj_keyid);
+  ksba_free (ak_keyid);
+  ksba_name_release (ak_name);
+  ksba_free (ak_sn);
+  ksba_free (serialno);
+  return result; 
+}
+
+
+
 /* Check whether the CERT is a root certificate.  Returns True if this
    is the case. */
 int
@@ -795,7 +873,7 @@ gpgsm_is_root_cert (ksba_cert_t cert)
 
   issuer = ksba_cert_get_issuer (cert, 0);
   subject = ksba_cert_get_subject (cert, 0);
-  yes = (issuer && subject && !strcmp (issuer, subject));
+  yes = is_root_cert (cert, issuer, subject);
   xfree (issuer);
   xfree (subject);
   return yes;
@@ -811,11 +889,17 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp,
   gpg_error_t err;
 
   if (opt.no_crl_check && !ctrl->use_ocsp)
-    return 0;
+    {
+      audit_log_ok (ctrl->audit, AUDIT_CRL_CHECK, 
+                    gpg_error (GPG_ERR_NOT_ENABLED));
+      return 0;
+    }
 
   err = gpgsm_dirmngr_isvalid (ctrl,
                                subject_cert, issuer_cert, 
                                force_ocsp? 2 : !!ctrl->use_ocsp);
+  audit_log_ok (ctrl->audit, AUDIT_CRL_CHECK, err);
+
   if (err)
     {
       if (!lm)
@@ -901,7 +985,7 @@ check_validity_period (ksba_isotime_t current_time,
       if (!listmode)
         {
           log_info ("  (valid from ");
-          gpgsm_dump_time (not_before);
+          dump_isotime (not_before);
           log_printf (")\n");
         }
       return gpg_error (GPG_ERR_CERT_TOO_YOUNG);
@@ -916,7 +1000,7 @@ check_validity_period (ksba_isotime_t current_time,
       if (!listmode)
         {
           log_info ("  (expired at ");
-          gpgsm_dump_time (not_after);
+          dump_isotime (not_after);
           log_printf (")\n");
         }
       if (opt.ignore_expiration)
@@ -965,9 +1049,9 @@ check_validity_period_cm (ksba_isotime_t current_time,
       do_list (1, listmode, listfp,
                _("certificate with invalid validity"));
       log_info ("  (valid from ");
-      gpgsm_dump_time (not_before);
+      dump_isotime (not_before);
       log_printf (" expired at ");
-      gpgsm_dump_time (not_after);
+      dump_isotime (not_after);
       log_printf (")\n");
       return gpg_error (GPG_ERR_BAD_CERT);
     }
@@ -986,7 +1070,7 @@ check_validity_period_cm (ksba_isotime_t current_time,
       if (!listmode)
         {
           log_info ("  (valid from ");
-          gpgsm_dump_time (not_before);
+          dump_isotime (not_before);
           log_printf (")\n");
         }
       return gpg_error (GPG_ERR_CERT_TOO_YOUNG);
@@ -1009,13 +1093,13 @@ check_validity_period_cm (ksba_isotime_t current_time,
         {
           log_info (depth== 0? _("  (  signature created at ") :
                     /* */      _("  (certificate created at ") );
-          gpgsm_dump_time (check_time);
+          dump_isotime (check_time);
           log_printf (")\n");
           log_info (depth==0? _("  (certificate valid from ") :
                     /* */     _("  (     issuer valid from ") );
-          gpgsm_dump_time (not_before);
+          dump_isotime (not_before);
           log_info (" to ");
-          gpgsm_dump_time (not_after);
+          dump_isotime (not_after);
           log_printf (")\n");
         }
       if (opt.ignore_expiration)
@@ -1197,11 +1281,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
         }
 
 
-      /* Is this a self-issued certificate (i.e. the root
-         certificate)?  This is actually the same test as done by
-         gpgsm_is_root_cert but here we want to keep the issuer and
-         subject for later use.  */
-      is_root = (subject && !strcmp (issuer, subject));
+      /* Is this a self-issued certificate (i.e. the root certificate)?  */
+      is_root = is_root_cert (subject_cert, issuer, subject);
       if (is_root)
         {
           chain->is_root = 1;
@@ -1209,7 +1290,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
              We used to do this only later but changed it to call the
              check right here so that we can access special flags
              associated with that specific root certificate.  */
-          istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert,
+          istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
                                                 rootca_flags);
           audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED,
                           subject_cert, istrusted_rc);
@@ -1490,7 +1571,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
                performance reasons. */
             if (is_root)
               {
-                istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert,
+                istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert, NULL,
                                                       rootca_flags);
                 if (!istrusted_rc && rootca_flags->relax)
                   {
@@ -1570,7 +1651,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
       depth++;
     } /* End chain traversal. */
 
-  if (!listmode)
+  if (!listmode && !opt.quiet)
     {
       if (opt.no_policy_check)
         log_info ("policies not checked due to %s option\n",
@@ -1771,7 +1852,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
       goto leave;
     }
 
-  if (subject && !strcmp (issuer, subject))
+  if (is_root_cert (cert, issuer, subject))
     {
       rc = gpgsm_check_cert_sig (cert, cert);
       if (rc)