dirmngr: Load all system provided certificates.
authorWerner Koch <wk@gnupg.org>
Thu, 16 Feb 2017 17:58:27 +0000 (18:58 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 16 Feb 2017 17:58:27 +0000 (18:58 +0100)
* configure.ac: Add option --default-trust-store.
(DEFAULT_TRUST_STORE_FILE): New ac_define.
* dirmngr/certcache.c: Include ksba-io-support.h.
(total_trusted_certificates, total_system_trusted_certificates): New.
(put_cert): Manage the new counters.
(cert_cache_deinit): Reset them.
(cert_cache_print_stats): Print them.
(is_trusted_cert): Add arg WITH_SYSTRUST.  Change all callers to pass
false.
(load_certs_from_file): New.
(load_certs_from_system): New.
(cert_cache_init): Load system certificates.
--

Note that this code does not yet allow to load the system certificates
on Windows.

Signed-off-by: Werner Koch <wk@gnupg.org>
configure.ac
dirmngr/certcache.c
dirmngr/certcache.h
dirmngr/validate.c

index ce02d03..1733c5a 100644 (file)
@@ -990,6 +990,22 @@ else
   fi
 fi
 
+#
+# Allow to set a fixed trust store file for system provided certificates.
+#
+AC_ARG_WITH([default-trust-store-file],
+            [AC_HELP_STRING([--with-default-trust-store-file=FILE],
+                            [Use FILE as system trust store])],
+            default_trust_store_file="$withval",
+            default_trust_store_file="")
+if test x"$default_trust_store_file" = xno;then
+  default_trust_store_file=""
+fi
+if test x"$default_trust_store_file" != x ; then
+  AC_DEFINE_UNQUOTED([DEFAULT_TRUST_STORE_FILE],
+    ["$default_trust_store_file"], [Use as default system trust store file])
+fi
+
 
 AC_MSG_NOTICE([checking for networking options])
 
index d68d503..626e440 100644 (file)
@@ -1,5 +1,5 @@
 /* certcache.c - Certificate caching
- *      Copyright (C) 2004, 2005, 2007, 2008 g10 Code GmbH
+ * Copyright (C) 2004, 2005, 2007, 2008, 2017 g10 Code GmbH
  *
  * This file is part of DirMngr.
  *
 
 #include "dirmngr.h"
 #include "misc.h"
+#include "../common/ksba-io-support.h"
 #include "crlfetch.h"
 #include "certcache.h"
 
-
 #define MAX_EXTRA_CACHED_CERTS 1000
 
 /* Constants used to classify search patterns.  */
@@ -93,10 +93,12 @@ static npth_rwlock_t cert_cache_lock;
 static int initialization_done;
 
 /* Total number of certificates loaded during initialization
- * (ie. configured) and extra certifcates cached during operation.  */
+ * (ie. configured), extra certificates cached during operation,
+ * number of trusted and system trusted certificates.  */
 static unsigned int total_config_certificates;
 static unsigned int total_extra_certificates;
-
+static unsigned int total_trusted_certificates;
+static unsigned int total_system_trusted_certificates;
 
 \f
 /* Helper to do the cache locking.  */
@@ -288,6 +290,10 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
               clean_cache_slot (ci_mark);
               drop_count--;
               total_extra_certificates--;
+              if (ci->flags.trusted)
+                total_trusted_certificates--;
+              if (ci->flags.systrust)
+                total_system_trusted_certificates--;
             }
         }
       if (i==idx)
@@ -331,6 +337,11 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
   ci->flags.trusted = !!is_trusted;
   ci->flags.systrust = (is_trusted && is_trusted == 2);
 
+  if (ci->flags.trusted)
+    total_trusted_certificates++;
+  if (ci->flags.systrust)
+    total_system_trusted_certificates++;
+
   if (from_config)
     total_config_certificates++;
   else
@@ -433,6 +444,121 @@ load_certs_from_dir (const char *dirname, int are_trusted)
 }
 
 
+/* Load certificates from FILE.  The certifciates are expected to be
+ * PEM encoded so that it is possible to load several certificates.
+ * All certates rea considered to be system provided trusted
+ * certificates.  The cache should be in a locked state when calling
+ * this function.  */
+static gpg_error_t
+load_certs_from_file (const char *fname)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  gnupg_ksba_io_t ioctx = NULL;
+  ksba_reader_t reader;
+  ksba_cert_t cert = NULL;
+
+  fp = es_fopen (fname, "rb");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
+      goto leave;
+    }
+
+  err = gnupg_ksba_create_reader (&ioctx,
+                                  (GNUPG_KSBA_IO_PEM | GNUPG_KSBA_IO_MULTIPEM),
+                                  fp, &reader);
+  if (err)
+    {
+      log_error ("can't create reader: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Loop to read all certificates from the file.  */
+  do
+    {
+      ksba_cert_release (cert);
+      cert = NULL;
+      err = ksba_cert_new (&cert);
+      if (!err)
+        err = ksba_cert_read_der (cert, reader);
+      if (err)
+        {
+          if (gpg_err_code (err) == GPG_ERR_EOF)
+            err = 0;
+          else
+            log_error (_("can't parse certificate '%s': %s\n"),
+                       fname, gpg_strerror (err));
+          goto leave;
+        }
+
+      err = put_cert (cert, 1, 2, NULL);
+      if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
+        log_info (_("certificate '%s' already cached\n"), fname);
+      else if (err)
+        log_error (_("error loading certificate '%s': %s\n"),
+                   fname, gpg_strerror (err));
+      else if (opt.verbose > 1)
+        {
+          char *p;
+
+          log_info (_("trusted certificate '%s' loaded\n"), fname);
+          p = get_fingerprint_hexstring_colon (cert);
+          log_info (_("  SHA1 fingerprint = %s\n"), p);
+          xfree (p);
+
+          cert_log_name    (_("   issuer ="), cert);
+          cert_log_subject (_("  subject ="), cert);
+        }
+
+      ksba_reader_clear (reader, NULL, NULL);
+    }
+  while (!gnupg_ksba_reader_eof_seen (ioctx));
+
+ leave:
+  ksba_cert_release (cert);
+  gnupg_ksba_destroy_reader (ioctx);
+  es_fclose (fp);
+
+  return err;
+}
+
+
+/* Load the trusted certificates provided by the system.  */
+static gpg_error_t
+load_certs_from_system (void)
+{
+  /* A list of certificate bundles to try.  */
+  static struct {
+    const char *name;
+  } table[] = {
+#ifdef DEFAULT_TRUST_STORE_FILE
+    { DEFAULT_TRUST_STORE_FILE }
+#else
+    { "/etc/ssl/ca-bundle.pem" },
+    { "/etc/ssl/certs/ca-certificates.crt" },
+    { "/etc/pki/tls/cert.pem" },
+    { "/usr/local/share/certs/ca-root-nss.crt" },
+    { "/etc/ssl/cert.pem" }
+#endif /*!DEFAULT_TRUST_STORE_FILE*/
+  };
+  int idx;
+  gpg_error_t err = 0;
+
+  for (idx=0; idx < DIM (table); idx++)
+    if (!access (table[idx].name, F_OK))
+      {
+        /* Take the first available bundle.  */
+        err = load_certs_from_file (table[idx].name);
+        break;
+      }
+
+
+  return err;
+}
+
+
 /* Initialize the certificate cache if not yet done.  */
 void
 cert_cache_init (void)
@@ -444,6 +570,8 @@ cert_cache_init (void)
   init_cache_lock ();
   acquire_cache_write_lock ();
 
+  load_certs_from_system ();
+
   dname = make_filename (gnupg_sysconfdir (), "trusted-certs", NULL);
   load_certs_from_dir (dname, 1);
   xfree (dname);
@@ -490,6 +618,8 @@ cert_cache_deinit (int full)
 
   total_config_certificates = 0;
   total_extra_certificates = 0;
+  total_trusted_certificates = 0;
+  total_system_trusted_certificates = 0;
   initialization_done = 0;
   release_cache_lock ();
 }
@@ -502,6 +632,8 @@ cert_cache_print_stats (void)
             total_config_certificates);
   log_info (_("    runtime cached certificates: %u\n"),
             total_extra_certificates);
+  log_info (_("           trusted certificates: %u (%u)\n"),
+            total_trusted_certificates, total_system_trusted_certificates);
 }
 
 
@@ -1274,11 +1406,12 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
 }
 
 
-/* Return 0 if the certificate is a trusted certificate. Returns
-   GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
-   case of systems errors. */
+/* Return 0 if the certificate is a trusted certificate.  Returns
+ * GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
+ * case of systems errors.  If WITH_SYSTRUST is set also system
+ * provided certificates are considered trusted.  */
 gpg_error_t
-is_trusted_cert (ksba_cert_t cert)
+is_trusted_cert (ksba_cert_t cert, int with_systrust)
 {
   unsigned char fpr[20];
   cert_item_t ci;
@@ -1289,7 +1422,7 @@ is_trusted_cert (ksba_cert_t cert)
   for (ci=cert_cache[*fpr]; ci; ci = ci->next)
     if (ci->cert && !memcmp (ci->fpr, fpr, 20))
       {
-        if (ci->flags.trusted)
+        if (ci->flags.trusted && (with_systrust || !ci->flags.systrust))
           {
             release_cache_lock ();
             return 0; /* Yes, it is trusted. */
index 9986f15..ac93ee6 100644 (file)
@@ -41,9 +41,10 @@ gpg_error_t cache_cert (ksba_cert_t cert);
 gpg_error_t cache_cert_silent (ksba_cert_t cert, void *fpr_buffer);
 
 /* Return 0 if the certificate is a trusted certificate. Returns
-   GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
-   case of systems errors. */
-gpg_error_t is_trusted_cert (ksba_cert_t cert);
+ * GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
+ * case of systems errors.  If WITH_SYSTRUST is set also system
+ * provided certificates are considered trusted.  */
+gpg_error_t is_trusted_cert (ksba_cert_t cert, int with_systrust);
 
 
 /* Return a certificate object for the given fingerprint.  FPR is
index 68e1bb3..4139c22 100644 (file)
@@ -189,7 +189,7 @@ allowed_ca (ksba_cert_t cert, int *chainlen)
     return err;
   if (!flag)
     {
-      if (!is_trusted_cert (cert))
+      if (!is_trusted_cert (cert, 0))
         {
           /* The German SigG Root CA's certificate does not flag
              itself as a CA; thus we relax this requirement if we
@@ -537,7 +537,7 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
           if (err)
             goto leave;  /* No. */
 
-          err = is_trusted_cert (subject_cert);
+          err = is_trusted_cert (subject_cert, 0);
           if (!err)
             ; /* Yes we trust this cert.  */
           else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)