dirmngr (21 files)

cvs user wk cvs at cvs.gnupg.org
Mon Nov 22 22:24:17 CET 2004


    Date: Monday, November 22, 2004 @ 22:30:50
  Author: wk
    Path: /cvs/dirmngr/dirmngr

Modified: NEWS doc/dirmngr.texi jnlib/ChangeLog jnlib/logging.c
          src/ChangeLog src/Makefile.am src/certcache.c src/certcache.h
          src/crlcache.c src/crlcache.h src/crlfetch.c src/dirmngr.c
          src/dirmngr.h src/dirmngr_ldap.c src/http.c src/http.h
          src/ldap.c src/ocsp.c src/server.c src/validate.c src/validate.h

* logging.c (log_test_fd): Add test on LOGSTREAM.

* dirmngr_ldap.c (main): New option --proxy.
* ocsp.c (do_ocsp_request): Take care of opt.disable_http.
* crlfetch.c (crl_fetch): Honor the --honor-http-proxy variable.
(crl_fetch): Take care of  opt.disable_http and disable_ldap.
(crl_fetch_default, ca_cert_fetch, start_cert_fetch): 
* ldap.c (run_ldap_wrapper): New arg PROXY.
(url_fetch_ldap, attr_fetch_ldap, start_cert_fetch_ldap): Pass it.

* http.c (http_open_document): Add arg PROXY.
(http_open): Ditto.
(send_request): Ditto and implement it as an override.

* ocsp.c (validate_responder_cert): Use validate_cert_chain.

* Makefile.am (AM_CPPFLAGS): Add macros for a few system
directories.
* dirmngr.h (opt): New members homedir_data, homedir_cache,
ldap_wrapper_program, system_daemon, honor_http_proxy, http_proxy,
ldap_proxy, only_ldap_proxy, disable_ldap, disable_http.
* dirmngr.c (main): Initialize new opt members HOMEDIR_DATA and
HOMEDIR_CACHE.
(parse_rereadable_options): New options --ldap-wrapper-program,
--http-wrapper-program, --disable-ldap, --disable-http,
--honor-http-proxy, --http-proxy, --ldap-proxy, --only-ldap-proxy.
(reread_configuration): New.

* ldap.c (ldap_wrapper): Use the correct name for the wrapper.

* crlcache.c (DBDIR_D): Make it depend on opt.SYSTEM_DAEMON.
(cleanup_cache_dir, open_dir, update_dir, make_db_file_name) 
(crl_cache_insert, create_directory_if_needed): Use opt.HOMEDIR_CACHE

* validate.c (check_revocations): New.
* crlcache.c (crl_cache_isvalid): Factored most code out to 
(cache_isvalid): .. new.
(crl_cache_cert_isvalid): New.
* server.c (cmd_checkcrl): Cleaned up by using this new function.
(reload_crl): Moved to ..
* crlcache.c (crl_cache_reload_crl): .. here and made global.

* certcache.c (cert_compute_fpr): Renamed from computer_fpr and
made global.
(find_cert_bysn): Try to lookup missing certs.
(cert_cache_init): Intialize using opt.HOMEDIR_DATA.


--------------------+
 NEWS               |   15 ++
 doc/dirmngr.texi   |   50 ++++++++-
 jnlib/ChangeLog    |    4 
 jnlib/logging.c    |    9 +
 src/ChangeLog      |   48 ++++++++
 src/Makefile.am    |    2 
 src/certcache.c    |   82 ++++++++++++--
 src/certcache.h    |    4 
 src/crlcache.c     |  282 +++++++++++++++++++++++++++++++++++++++++++++------
 src/crlcache.h     |    5 
 src/crlfetch.c     |   40 ++++++-
 src/dirmngr.c      |  144 +++++++++++++++++++++++---
 src/dirmngr.h      |   17 ++-
 src/dirmngr_ldap.c |   21 +++
 src/http.c         |   33 +++--
 src/http.h         |    6 -
 src/ldap.c         |   35 +++++-
 src/ocsp.c         |   63 +++++++----
 src/server.c       |  228 +----------------------------------------
 src/validate.c     |  162 ++++++++++++++++++++++++-----
 src/validate.h     |   10 +
 21 files changed, 902 insertions(+), 358 deletions(-)


Index: dirmngr/NEWS
diff -u dirmngr/NEWS:1.27 dirmngr/NEWS:1.28
--- dirmngr/NEWS:1.27	Tue Nov 16 19:24:36 2004
+++ dirmngr/NEWS	Mon Nov 22 22:30:50 2004
@@ -1,11 +1,22 @@
 Noteworthy changes in version 0.9.0
 ------------------------------------------------
 
-  WARNING: CURRENTLY UNDER HEAVY RECONSTRUCTION.  Many things might
-  not yet work again. 
+ * New option --daemon to start dirmngr as a system daemon.  This
+   switched to the use of different directories and also does
+   certificate validation on its own.
 
  * New tool dirmngr-client.
 
+ * New options: --ldap-wrapper-program, --http-wrapper-program,
+   --disable-ldap, --disable-http, --honor-http-proxy, --http-proxy,
+   --ldap-proxy and --only-ldap-proxy.
+
+ * Uses an external ldap wrapper to cope with timeouts and general
+   LDAP problems.  Prepared for using 
+
+ * SIGHUP may be used to reread the configuration and to flush the
+   certificate cache.
+
 
 Noteworthy changes in version 0.5.6 (2004-09-28)
 ------------------------------------------------
Index: dirmngr/doc/dirmngr.texi
diff -u dirmngr/doc/dirmngr.texi:1.15 dirmngr/doc/dirmngr.texi:1.16
--- dirmngr/doc/dirmngr.texi:1.15	Thu Nov 18 16:37:48 2004
+++ dirmngr/doc/dirmngr.texi	Mon Nov 22 22:30:50 2004
@@ -155,7 +155,8 @@
 @item --daemon
 @opindex daemon
 Run in background daemon mode and listen for commands on a socket.
-Note that this also changes the default home directory.
+Note that this also changes the default home directory and enables the
+internal certificate validation code.
 
 @item --list-crls
 @opindex list-crls
@@ -210,11 +211,14 @@
 
  @table @asis
  @item With @code{--daemon} given on the commandline
- the directory named @file{/etc/dirmngr}. 
+the directory named @file{/etc/dirmngr} for configuration files,
+ at file{/var/lib/dirmngr/} for extra data and @file{/var/cache/dirmngr}
+for cached CRLs.
  @item Without @code{--daemon} given on the commandline
 the directory named @file{.gnupg} directly below the home directory
 of the user unless the environment variable @code{GNUPGHOME} has been set
-in which case its value will be used.
+in which case its value will be used.  All kind of data is stored below
+this directory.
  @end table
 
 
@@ -290,11 +294,46 @@
 Enabling this option forces loading of expired CRLs; this is only
 useful for debugging.
 
+ at item --disable-ldap
+ at opindex disable-ldap
+Entirely disables the use of LDAP.
+
+ at item --disable-http
+ at opindex disable-http
+Entirely disables the use of HTTP.
+
+ at item --honor-http-proxy
+ at opindex honor-http-proxy
+If the environment variable @env{http_proxy} has been set, use its
+value to access HTTP servers.
+
+ at item --http-proxy @var{host}[:@var{port}]
+ at opindex http-proxy
+Use @var{host} and @var{port} to access HTTP servers.  The use of this
+options overrides the environment variable @env{http_proxy} regardless
+whether @option{--honor-http-proxy} has been set.
+
+
+ at item --ldap-proxy @var{host}[:@var{port}]
+ at opindex ldap-proxy
+Use @var{host} and @var{port} to connect to LDAP servers.  If @var{port}
+is ommitted, port 389 (standard LDAP port) is used.  This overrides any
+specified host and port part in a LDAP URL and will also be used if host
+and port have been ommitted from the URL.
+
+ at item --only-ldap-proxy
+ at opindex only-ldap-proxy
+Never use anything else but the LDAP "proxy" as configured with
+ at option{--ldap-proxy}.  Usually @command{dirmngr} tries to use other
+configured LDAP server if the connection using the "proxy" failed.
+
+
 @item --ldapserverlist-file @var{file}
 @opindex ldapserverlist-file
 Read the list of LDAP servers to consult for CRLs and certificates from
 file instead of the default per-user ldap server list file. The default 
-value for @var{file} is @samp{dirmngr_ldapservers.conf}.
+value for @var{file} is @file{dirmngr_ldapservers.conf} or
+ at file{ldapservers.conf} when running in @option{--daemon} mode.
 
 The server list file contains one LDAP server per line in the format
 
@@ -307,6 +346,7 @@
 Specify the number of seconds to wait for an LDAP query before timing
 out. The default is currently 100 seconds.
 
+
 @item --add-servers
 @opindex add-servers
 This options makes dirmngr add any servers it discovers when validating
@@ -370,7 +410,7 @@
 @cpindex SIGHUP
 This signals flushes all internally cached CRLs as well as any cached
 certificates.  Then the certificate cache is reinitialized as on
-startup.
+startup.  Options are re-read from the configuration file.
 
 @item SIGTERM
 @cpindex SIGTERM
Index: dirmngr/jnlib/ChangeLog
diff -u dirmngr/jnlib/ChangeLog:1.9 dirmngr/jnlib/ChangeLog:1.10
--- dirmngr/jnlib/ChangeLog:1.9	Tue Nov 16 19:24:35 2004
+++ dirmngr/jnlib/ChangeLog	Mon Nov 22 22:30:50 2004
@@ -1,3 +1,7 @@
+2004-11-22  Werner Koch  <wk at g10code.com>
+
+	* logging.c (log_test_fd): Add test on LOGSTREAM.
+
 2004-10-21  Werner Koch  <wk at g10code.com>
 
 	* logging.c (do_logv): Use set_log_stream to setup a default.
Index: dirmngr/jnlib/logging.c
diff -u dirmngr/jnlib/logging.c:1.8 dirmngr/jnlib/logging.c:1.9
--- dirmngr/jnlib/logging.c:1.8	Tue Nov 16 19:24:35 2004
+++ dirmngr/jnlib/logging.c	Mon Nov 22 22:30:50 2004
@@ -411,9 +411,12 @@
 int
 log_test_fd (int fd)
 {
-  int tmp = fileno (logstream);
-  if ( tmp != -1 && tmp == fd)
-    return 1;
+  if (logstream)
+    {
+      int tmp = fileno (logstream);
+      if ( tmp != -1 && tmp == fd)
+        return 1;
+    }
   if (log_socket != -1 && log_socket == fd)
     return 1;
   return 0;
Index: dirmngr/src/ChangeLog
diff -u dirmngr/src/ChangeLog:1.24 dirmngr/src/ChangeLog:1.25
--- dirmngr/src/ChangeLog:1.24	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/ChangeLog	Mon Nov 22 22:30:50 2004
@@ -1,3 +1,51 @@
+2004-11-22  Werner Koch  <wk at g10code.com>
+
+	* dirmngr_ldap.c (main): New option --proxy.
+	* ocsp.c (do_ocsp_request): Take care of opt.disable_http.
+	* crlfetch.c (crl_fetch): Honor the --honor-http-proxy variable.
+	(crl_fetch): Take care of  opt.disable_http and disable_ldap.
+	(crl_fetch_default, ca_cert_fetch, start_cert_fetch): 
+	* ldap.c (run_ldap_wrapper): New arg PROXY.
+	(url_fetch_ldap, attr_fetch_ldap, start_cert_fetch_ldap): Pass it.
+
+	* http.c (http_open_document): Add arg PROXY.
+	(http_open): Ditto.
+	(send_request): Ditto and implement it as an override.
+
+	* ocsp.c (validate_responder_cert): Use validate_cert_chain.
+
+	* Makefile.am (AM_CPPFLAGS): Add macros for a few system
+	directories.
+	* dirmngr.h (opt): New members homedir_data, homedir_cache,
+	ldap_wrapper_program, system_daemon, honor_http_proxy, http_proxy,
+	ldap_proxy, only_ldap_proxy, disable_ldap, disable_http.
+	* dirmngr.c (main): Initialize new opt members HOMEDIR_DATA and
+	HOMEDIR_CACHE.
+	(parse_rereadable_options): New options --ldap-wrapper-program,
+	--http-wrapper-program, --disable-ldap, --disable-http,
+	--honor-http-proxy, --http-proxy, --ldap-proxy, --only-ldap-proxy.
+	(reread_configuration): New.
+
+	* ldap.c (ldap_wrapper): Use the correct name for the wrapper.
+
+	* crlcache.c (DBDIR_D): Make it depend on opt.SYSTEM_DAEMON.
+	(cleanup_cache_dir, open_dir, update_dir, make_db_file_name) 
+	(crl_cache_insert, create_directory_if_needed): Use opt.HOMEDIR_CACHE
+
+	* validate.c (check_revocations): New.
+	* crlcache.c (crl_cache_isvalid): Factored most code out to 
+	(cache_isvalid): .. new.
+	(crl_cache_cert_isvalid): New.
+	* server.c (cmd_checkcrl): Cleaned up by using this new function.
+	(reload_crl): Moved to ..
+	* crlcache.c (crl_cache_reload_crl): .. here and made global.
+
+	* certcache.c (cert_compute_fpr): Renamed from computer_fpr and
+	made global.
+	(find_cert_bysn): Try to lookup missing certs.
+	(cert_cache_init): Intialize using opt.HOMEDIR_DATA.
+
+
 2004-11-19  Werner Koch  <wk at g10code.com>
 
 	* dirmngr-client.c (status_cb): New.  Use it in very verbose mode.
Index: dirmngr/src/Makefile.am
diff -u dirmngr/src/Makefile.am:1.18 dirmngr/src/Makefile.am:1.19
--- dirmngr/src/Makefile.am:1.18	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/Makefile.am	Mon Nov 22 22:30:50 2004
@@ -30,6 +30,8 @@
 AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" 
 AM_CPPFLAGS += -DDIRMNGR_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" 
 AM_CPPFLAGS += -DDIRMNGR_LIBEXECDIR="\"$(libexecdir)\""
+AM_CPPFLAGS += -DDIRMNGR_DATADIR="\"$(localstatedir)/lib/@PACKAGE@\""
+AM_CPPFLAGS += -DDIRMNGR_CACHEDIR="\"$(localstatedir)/cache/@PACKAGE@\""
 
 AM_CFLAGS = -I$(top_srcdir)/jnlib @LIBGCRYPT_CFLAGS@ @LIBASSUAN_CFLAGS@ \
               @KSBA_CFLAGS@ @GPG_ERROR_CFLAGS@  $(PTH_CFLAGS)
Index: dirmngr/src/certcache.c
diff -u dirmngr/src/certcache.c:1.4 dirmngr/src/certcache.c:1.5
--- dirmngr/src/certcache.c:1.4	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/certcache.c	Mon Nov 22 22:30:50 2004
@@ -32,8 +32,10 @@
 
 #include "dirmngr.h"
 #include "misc.h"
+#include "crlfetch.h"
 #include "certcache.h"
 
+
 #define MAX_EXTRA_CACHED_CERTS 200 /* FIXME: This is a debugging value.  */
 
 
@@ -136,10 +138,10 @@
 }
 
 
-/* Computer the fingerprint of the certificate CERT and put it into
+/* Compute the fingerprint of the certificate CERT and put it into
    the 20 bytes large buffer DIGEST.  Return address of this buffer.  */
-static unsigned char *
-compute_fpr (ksba_cert_t cert, unsigned char *digest)
+unsigned char *
+cert_compute_fpr (ksba_cert_t cert, unsigned char *digest)
 {
   gpg_error_t err;
   gcry_md_hd_t md;
@@ -237,7 +239,7 @@
       idx %= 256;
     }
 
-  compute_fpr (cert, fpr);
+  cert_compute_fpr (cert, fpr);
   for (ci=cert_cache[*fpr]; ci; ci = ci->next)
     if (ci->cert && !memcmp (ci->fpr, fpr, 20))
       return gpg_error (GPG_ERR_DUP_VALUE);          
@@ -298,8 +300,9 @@
   dir = opendir (dirname);
   if (!dir)
     {
-      log_info (_("can't access directory `%s': %s\n"),
-                 dirname, strerror (errno));
+      if (opt.system_daemon)
+        log_info (_("can't access directory `%s': %s\n"),
+                  dirname, strerror (errno));
       return 0; /* We do not consider this a severe error.  */
     }
 
@@ -376,7 +379,7 @@
   load_certs_from_dir (dname, 1);
   xfree (dname);
 
-  dname = make_filename (opt.homedir, "extra-certs", NULL);
+  dname = make_filename (opt.homedir_data, "extra-certs", NULL);
   load_certs_from_dir (dname, 0);
   xfree (dname);
 
@@ -538,15 +541,68 @@
 /* Return the certificate matching ISSUER_DN and SERIALNO; if it is
    not already in the cache, try to find it from other resources.  */
 ksba_cert_t
-find_cert_bysn (const char *issuer_dn, ksba_sexp_t serialno)
+find_cert_bysn (ctrl_t ctrl, const char *issuer_dn, ksba_sexp_t serialno)
 {
+  gpg_error_t err;
   ksba_cert_t cert;
+  ksba_reader_t reader;
 
   cert = get_cert_bysn (issuer_dn, serialno);
-  if (cert)
-    return cert;
 
-  return NULL;
+  /* Fixme: We should not use the simple ca-fetch_cert but do a
+     regular lookup and iterate over all certificates until we found
+     a matching S/N.  */
+  while (!cert)
+    {
+      ksba_sexp_t sn;
+      char *issdn;
+
+      err = ca_cert_fetch (ctrl, issuer_dn, &reader);
+      if (err)
+        {
+          log_error (_("error fetching certificate for issuer: %s\n"),
+                     gpg_strerror (err));
+          return NULL;
+        }
+      
+      err = ksba_cert_new (&cert);
+      if (!err)
+        err = ksba_cert_read_der (cert, reader);
+      ksba_reader_release (reader);
+      if (err)
+        {
+          log_error (_("invalid issuer certificate: %s\n"),
+                     gpg_strerror (err) );
+          ksba_cert_release (cert);
+          return NULL;
+        }
+      
+      issdn = ksba_cert_get_issuer (cert, 0);
+      if (strcmp (issuer_dn, issdn))
+        {
+          log_debug ("find_cert_bysn: Ooops: Issuer DN does not match\n");
+          ksba_cert_release (cert);
+          cert = NULL;
+          ksba_free (issdn);
+          break; 
+        }
+
+      sn = ksba_cert_get_serial (cert);
+      if (!compare_serialno (serialno, sn))
+        {
+          ksba_free (sn);
+          cache_cert (cert);
+          break; /* Ready.  */
+        }
+
+      log_debug ("find_cert_bysn: S/N does not match\n");
+      ksba_cert_release (cert);
+      cert = NULL;
+      ksba_free (sn);
+      break; /* FIXME: That should be a get next cert.  */ 
+    }
+
+  return cert;
 }
 
 
@@ -560,7 +616,7 @@
   unsigned char fpr[20];
   cert_item_t ci;
 
-  compute_fpr (cert, fpr);
+  cert_compute_fpr (cert, fpr);
 
   acquire_cache_read_lock ();
   for (ci=cert_cache[*fpr]; ci; ci = ci->next)
@@ -614,7 +670,7 @@
       const char *s = ksba_name_enum (authid, 0);
       if (s && *authidno)
         {
-          issuer_cert = find_cert_bysn (s, authidno);
+          issuer_cert = find_cert_bysn (ctrl, s, authidno);
         }
       /* Print a note so that the user does not feel too helpless when
          an issuer certificate was found and gpgsm prints BAD
Index: dirmngr/src/certcache.h
diff -u dirmngr/src/certcache.h:1.3 dirmngr/src/certcache.h:1.4
--- dirmngr/src/certcache.h:1.3	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/certcache.h	Mon Nov 22 22:30:50 2004
@@ -30,6 +30,9 @@
 /* Print some statistics to the log file.  */
 void cert_cache_print_stats (void);
 
+/* Compute the fingerprint of the certificate CERT and put it into
+   the 20 bytes large buffer DIGEST.  Return address of this buffer.  */
+unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest);
 
 /* Put CERT into the certificate cache.  */
 gpg_error_t cache_cert (ksba_cert_t cert);
@@ -60,4 +63,5 @@
 
 
 
+
 #endif /*CERTCACHE_H*/
Index: dirmngr/src/crlcache.c
diff -u dirmngr/src/crlcache.c:1.48 dirmngr/src/crlcache.c:1.49
--- dirmngr/src/crlcache.c:1.48	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/crlcache.c	Mon Nov 22 22:30:50 2004
@@ -105,7 +105,7 @@
 #include "cdb.h"
 
 /* Change this whenever the format changes */
-#define DBDIR_D "dirmngr-cache.d"
+#define DBDIR_D (opt.system_daemon? "crls.d" : "dirmngr-cache.d")
 #define DBDIRFILE "DIR.txt"
 #define DBDIRVERSION 1
 
@@ -194,7 +194,7 @@
   DIR *dir;
   char *fname;
 
-  fname = make_filename (opt.homedir, name, NULL);
+  fname = make_filename (opt.homedir_cache, name, NULL);
   dir = opendir (fname);
   if (!dir)
     {
@@ -221,7 +221,7 @@
 static int
 cleanup_cache_dir (int force)
 {
-  char *dname = make_filename (opt.homedir, DBDIR_D, NULL);
+  char *dname = make_filename (opt.homedir_cache, DBDIR_D, NULL);
   DIR *dir;
   struct dirent *de;
   int problem = 0;
@@ -489,7 +489,7 @@
   gpg_error_t err = 0;
   int anyerr = 0;
 
-  fname = make_filename (opt.homedir, DBDIR_D, DBDIRFILE, NULL);
+  fname = make_filename (opt.homedir_cache, DBDIR_D, DBDIRFILE, NULL);
 
   lineno = 0;
   fp = open_dir_file (fname);
@@ -687,7 +687,7 @@
   unsigned int lineno;
   gpg_error_t err = 0;
 
-  fname = make_filename (opt.homedir, DBDIR_D, DBDIRFILE, NULL);
+  fname = make_filename (opt.homedir_cache, DBDIR_D, DBDIRFILE, NULL);
 
   /* Fixme: Take an update file lock here. */
 
@@ -725,7 +725,7 @@
     for (p=tmpbuf; *p; p++)
       if (*p == '/')
         *p = '.';
-    tmpfname = make_filename (opt.homedir, DBDIR_D, tmpbuf, NULL);
+    tmpfname = make_filename (opt.homedir_cache, DBDIR_D, tmpbuf, NULL);
     xfree (tmpbuf);
   }
   fpout = fopen (tmpfname, "w");
@@ -859,7 +859,7 @@
   memcpy (bname, "crl-", 4);
   memcpy (bname + 4, issuer_hash, 40);
   strcpy (bname + 44, ".db");
-  return make_filename (opt.homedir, DBDIR_D, bname, NULL);
+  return make_filename (opt.homedir_cache, DBDIR_D, bname, NULL);
 }
 
 
@@ -1129,14 +1129,15 @@
 
 
 /* Check whether the certificate identified by ISSUER_HASH and
-   SERIALNO is valid; i.e. not listed in our cache.  With
+   SN/SNLEN is valid; i.e. not listed in our cache.  With
    FORCE_REFRESH set to true, a new CRL will be retrieved even if the
    cache has not yet expired.  We use a 30 minutes threshold here so
    that invoking this function several times won't load the CRL over
    and over.  */
-crl_cache_result_t 
-crl_cache_isvalid (ctrl_t ctrl, const char *issuer_hash, const char *serialno,
-                   int force_refresh)
+static crl_cache_result_t 
+cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
+               const unsigned char *sn, size_t snlen,
+               int force_refresh)
 {
   crl_cache_t cache = get_current_cache ();
   crl_cache_result_t retval;
@@ -1144,8 +1145,6 @@
   int rc;
   crl_cache_entry_t entry;
   dirmngr_isotime_t current_time;
-  unsigned char snbuf_buffer[50];
-  unsigned char *snbuf;
   size_t n;
 
   entry = find_entry (cache->entries, issuer_hash);
@@ -1206,38 +1205,39 @@
       return CRL_CACHE_DONTKNOW;
     }
 
-  n = strlen (serialno)/2+1;
-  if (n < sizeof snbuf_buffer - 1)
-    snbuf = snbuf_buffer;
-  else
-    snbuf = xmalloc (n);
-
-  n = unhexify (snbuf, serialno);
-  rc = cdb_find (cdb, snbuf, n);
+  rc = cdb_find (cdb, sn, snlen);
   if (rc == 1) 
     {
       n = cdb_datalen (cdb);
       if (n != 16)
-        log_error (_("WARNING: invalid cache record length for S/N %s\n"),
-                   serialno );
+        {
+          log_error (_("WARNING: invalid cache record length for S/N "));
+          log_printhex ("", sn, snlen);
+        }
       else if (opt.verbose)
         {
           unsigned char record[16];
+          char *tmp = hexify_data (sn, snlen);
 
           if (cdb_read (cdb, record, n, cdb_datapos (cdb)))
             log_error (_("problem reading cache record for S/N %s: %s\n"),
-                       serialno, strerror (errno));
+                       tmp, strerror (errno));
           else
             log_info (_("S/N %s is not valid; reason=%02X  date=%.15s\n"),
-                      serialno, *record, record+1);
+                      tmp, *record, record+1);
+          xfree (tmp);
         }
       retval = CRL_CACHE_INVALID;
     }
   else if (!rc)
     {
       if (opt.verbose)
-        log_info (_("S/N %s is valid, it is not listed in the CRL\n"),
-                  serialno );
+        {
+          char *serialno = hexify_data (sn, snlen);
+          log_info (_("S/N %s is valid, it is not listed in the CRL\n"),
+                    serialno );
+          xfree (serialno);
+        }
       retval = CRL_CACHE_VALID;
     }
   else 
@@ -1247,15 +1247,123 @@
       retval = CRL_CACHE_DONTKNOW;
     }
 
-  if (snbuf != snbuf_buffer)
-    xfree (snbuf);
-
   unlock_db_file (cache, entry);
 
   return retval;
 }
 
 
+/* Check whether the certificate identified by ISSUER_HASH and
+   SERIALNO is valid; i.e. not listed in our cache.  With
+   FORCE_REFRESH set to true, a new CRL will be retrieved even if the
+   cache has not yet expired.  We use a 30 minutes threshold here so
+   that invoking this function several times won't load the CRL over
+   and over.  */
+crl_cache_result_t 
+crl_cache_isvalid (ctrl_t ctrl, const char *issuer_hash, const char *serialno,
+                   int force_refresh)
+{
+  crl_cache_result_t result;
+  unsigned char snbuf_buffer[50];
+  unsigned char *snbuf;
+  size_t n;
+
+  n = strlen (serialno)/2+1;
+  if (n < sizeof snbuf_buffer - 1)
+    snbuf = snbuf_buffer;
+  else
+    snbuf = xmalloc (n);
+
+  n = unhexify (snbuf, serialno);
+
+  result = cache_isvalid (ctrl, issuer_hash, snbuf, n, force_refresh);
+
+  if (snbuf != snbuf_buffer)
+    xfree (snbuf);
+
+  return result;
+}  
+
+
+/* Check whether the certificate CERT is valid; i.e. not listed in our
+   cache.  With FORCE_REFRESH set to true, a new CRL will be retrieved
+   even if the cache has not yet expired.  We use a 30 minutes
+   threshold here so that invoking this function several times won't
+   load the CRL over and over.  */
+gpg_error_t
+crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
+                        int force_refresh)
+{
+  gpg_error_t err;
+  crl_cache_result_t result;
+  unsigned char issuerhash[20];
+  char issuerhash_hex[41];
+  ksba_sexp_t serial;
+  unsigned char *sn;
+  size_t snlen;
+  char *endp, *tmp;
+  int i;
+
+  /* Compute the hash value of the issuer name.  */
+  tmp = ksba_cert_get_issuer (cert, 0);
+  if (!tmp)
+    {
+      log_error ("oops: issuer missing in certificate\n");
+      return gpg_error (GPG_ERR_INV_CERT_OBJ);
+    }
+  gcry_md_hash_buffer (GCRY_MD_SHA1, issuerhash, tmp, strlen (tmp));
+  xfree (tmp);
+  for (i=0,tmp=issuerhash_hex; i < 20; i++, tmp += 2)
+    sprintf (tmp, "%02X", issuerhash[i]);
+  
+  /* Get the serial number.  */
+  serial = ksba_cert_get_serial (cert);
+  if (!serial)
+    {
+      log_error ("oops: S/N missing in certificate\n");
+      return gpg_error (GPG_ERR_INV_CERT_OBJ);
+    }
+  sn = serial;
+  if (*sn != '(')
+    {
+      log_error ("oops: invalid S/N\n");
+      xfree (serial);
+      return gpg_error (GPG_ERR_INV_CERT_OBJ);
+    }
+  sn++;
+  snlen = strtoul (sn, &endp, 10);
+  sn = endp;
+  if (*sn != ':')
+    {
+      log_error ("oops: invalid S/N\n");
+      xfree (serial);
+      return gpg_error (GPG_ERR_INV_CERT_OBJ);
+    }
+  sn++;
+
+  /* Check the cache.  */
+  result = cache_isvalid (ctrl, issuerhash_hex, sn, snlen, force_refresh);
+  switch (result)
+    {
+    case CRL_CACHE_VALID:
+      err = 0;
+      break;
+    case CRL_CACHE_INVALID:
+      err = gpg_error (GPG_ERR_CERT_REVOKED);
+      break;
+    case CRL_CACHE_DONTKNOW: 
+      err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+    case CRL_CACHE_CANTUSE: 
+      err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+      break;
+    default:
+      log_fatal ("cache_isvalid returned invalid status code %d\n", result);
+    }
+
+  xfree (serial);
+  return err;
+}  
+
 
 /* Return the certificate for ISSUER or NULL if it can't be found. */
 static ksba_cert_t 
@@ -1553,7 +1661,8 @@
                            gpg_strerror (err));
                 goto failure;
               }
-            err = validate_cert_chain (ctrl, issuer_cert, NULL);
+            err = validate_cert_chain (ctrl, issuer_cert,
+                                       NULL, VALIDATE_MODE_CRL);
             if (err)
               {
                 log_error (_("error checking validity of CRL "
@@ -1708,7 +1817,7 @@
     for (p=tmpfname; *p; p++)
       if (*p == '/')
         *p = '.';
-    fname = make_filename (opt.homedir, DBDIR_D, tmpfname, NULL);
+    fname = make_filename (opt.homedir_cache, DBDIR_D, tmpfname, NULL);
     xfree (tmpfname);
     if (!remove (fname))
       log_info (_("removed stale temporary cache file `%s'\n"), fname);
@@ -2040,3 +2149,112 @@
   return err;
 }
 
+
+/* Locate the corresponding CRL for the certificate CERT, read and
+   verify the CRL and store it in the cache.  */
+gpg_error_t
+crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert) 
+{
+  gpg_error_t err;
+  ksba_reader_t reader = NULL;
+  char *issuer = NULL;
+  ksba_name_t distpoint = NULL;
+  ksba_name_t issuername = NULL;
+  char *distpoint_uri = NULL;
+  char *issuername_uri = NULL;
+  int any_dist_point = 0;
+  int seq;
+
+  /* Loop over all distribution points, get the CRLs and put them into
+     the cache. */
+  if (DBG_X509)
+    log_debug ("checking distribution points\n");
+  seq = 0;
+  while ( !(err = ksba_cert_get_crl_dist_point (cert, seq++,
+                                                &distpoint,
+                                                &issuername, NULL )))
+    {
+      if (!distpoint && !issuername)
+        {
+          if (DBG_X509)
+            log_debug ("no issuer name and no distribution point\n");
+          break; /* Not allowed; i.e. an invalid certificate.  We give
+                    up here and hope that the default method returns a
+                    suitable CRL. */
+        }
+
+      /* Get the URIs. */
+      xfree (distpoint_uri); distpoint_uri = NULL;
+      xfree (issuername_uri); issuername_uri = NULL;
+      distpoint_uri = ksba_name_get_uri (distpoint, 0); 
+      issuername_uri = ksba_name_get_uri (issuername, 0); 
+      ksba_name_release (distpoint); distpoint = NULL;
+      ksba_name_release (issuername); issuername = NULL;
+      any_dist_point = 1;
+      
+      err = crl_fetch (ctrl, distpoint_uri, &reader);
+      if (err)
+        {
+          log_error (_("crl_fetch via DP failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+      
+      err = crl_cache_insert (ctrl, distpoint_uri, reader); 
+      if (err)
+        {
+          log_error (_("crl_cache_insert via DP failed: %s\n"),
+                     gpg_strerror (err));
+          goto leave;
+        }
+    }
+  if (gpg_err_code (err) == GPG_ERR_EOF)
+    err = 0;
+
+  /* If we did not found any distpoint, try something reasonable. */
+  if (!any_dist_point )
+    {
+      if (DBG_X509)
+        log_debug ("no distribution point - trying issuer name\n");
+      
+      if (reader)
+        {
+          crl_close_reader (reader);
+          reader = NULL;
+        }
+
+      issuer = ksba_cert_get_issuer (cert, 0);
+      if (!issuer) 
+        {
+          log_error ("oops: issuer missing in certificate\n");
+          err = gpg_error (GPG_ERR_INV_CERT_OBJ); 
+          goto leave;
+        }
+
+      err = crl_fetch_default (ctrl, issuer, &reader);
+      if (err)
+          {
+            log_error (_("crl_fetch via issuer failed: %s\n"),
+                       gpg_strerror (err));
+            goto leave;
+          }
+
+      err = crl_cache_insert (ctrl, "default location(s)", reader);
+      if (err)
+        {
+          log_error (_("crl_cache_insert via issuer failed: %s\n"),
+                     gpg_strerror (err));
+          goto leave;
+        }
+    }
+
+ leave:
+  if (reader)
+    crl_close_reader (reader);
+  xfree (distpoint_uri);
+  xfree (issuername_uri);
+  ksba_name_release (distpoint); 
+  ksba_name_release (issuername); 
+  ksba_free (issuer);
+  return err;
+}
+
Index: dirmngr/src/crlcache.h
diff -u dirmngr/src/crlcache.h:1.23 dirmngr/src/crlcache.h:1.24
--- dirmngr/src/crlcache.h:1.23	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/crlcache.h	Mon Nov 22 22:30:50 2004
@@ -61,6 +61,9 @@
                                       const char *cert_id,
                                       int force_refresh);
 
+gpg_error_t crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
+                                    int force_refresh);
+
 gpg_error_t crl_cache_insert (ctrl_t ctrl, const char *url,
                               ksba_reader_t reader);
 
@@ -68,5 +71,7 @@
 
 gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename);
 
+gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
+
 
 #endif /* CRLCACHE_H */
Index: dirmngr/src/crlfetch.c
diff -u dirmngr/src/crlfetch.c:1.20 dirmngr/src/crlfetch.c:1.21
--- dirmngr/src/crlfetch.c:1.20	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/crlfetch.c	Mon Nov 22 22:30:50 2004
@@ -67,7 +67,17 @@
     {
       struct http_context_s hd;
       
-      err = http_open_document (&hd, url, 0);
+      if (opt.disable_http)
+        {
+          log_error (_("CRL access not possible due to disabled %s\n"),
+                     "HTTP");
+          err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+        }
+      else
+        err = http_open_document (&hd, url,
+                                  opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0,
+                                  opt.http_proxy);
+
       if (err)
         log_error (_("error retrieving `%s': %s\n"), url, gpg_strerror (err));
       else if (hd.status_code != 200)
@@ -103,7 +113,15 @@
     {
       const char *s;
 
-      err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
+      if (opt.disable_ldap)
+        {
+          log_error (_("CRL access not possible due to disabled %s\n"),
+                     "LDAP");
+          err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+        }
+      else
+        err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
+
 /*       if (err) */
 /*         { */
 /*           /\* If the function failed we try again using our default */
@@ -144,6 +162,12 @@
 gpg_error_t
 crl_fetch_default (ctrl_t ctrl, const char *issuer, ksba_reader_t *reader)
 {
+  if (opt.disable_ldap)
+    {
+      log_error (_("CRL access not possible due to disabled %s\n"),
+                 "LDAP");
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
   return attr_fetch_ldap (ctrl, issuer, "certificateRevocationList;binary",
                           reader);
 }
@@ -153,6 +177,12 @@
 int
 ca_cert_fetch (ctrl_t ctrl, const char *dn, ksba_reader_t *reader)
 {
+  if (opt.disable_ldap)
+    {
+      log_error (_("CRL access not possible due to disabled %s\n"),
+                 "LDAP");
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
   return attr_fetch_ldap (ctrl, dn, "cACertificate;binary", reader);
 }
 
@@ -161,6 +191,12 @@
 start_cert_fetch (ctrl_t ctrl, cert_fetch_context_t *context,
                   strlist_t patterns, const ldap_server_t server)
 {
+  if (opt.disable_ldap)
+    {
+      log_error (_("Certificate search not possible due to disabled %s\n"),
+                 "LDAP");
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
   return start_cert_fetch_ldap (ctrl, context, patterns, server);
 }
 
Index: dirmngr/src/dirmngr.c
diff -u dirmngr/src/dirmngr.c:1.44 dirmngr/src/dirmngr.c:1.45
--- dirmngr/src/dirmngr.c:1.44	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/dirmngr.c	Mon Nov 22 22:30:50 2004
@@ -76,6 +76,12 @@
   oNoDetach,
   oLogFile,
   oBatch,
+  oDisableHTTP,
+  oDisableLDAP,
+  oHonorHTTPProxy,
+  oHTTPProxy,
+  oLDAPProxy,
+  oOnlyLDAPProxy,
   oLDAPFile,
   oLDAPTimeout,
   oLDAPAddServers,
@@ -86,6 +92,8 @@
   oForce,
   oAllowOCSP,
   oSocketName,
+  oLDAPWrapperProgram,
+  oHTTPWrapperProgram,
 aTest };
 
 
@@ -117,6 +125,14 @@
   { oBatch   , "batch"     ,0, N_("run without asking a user")},
   { oForce,    "force"     ,0, N_("force loading of outdated CRLs")},
   { oAllowOCSP, "allow-ocsp",0,N_("allow sending OCSP requests")},
+  { oDisableHTTP, "disable-http", 0, N_("inhibit the use of HTTP")},
+  { oDisableLDAP, "disable-ldap", 0, N_("inhibit the use of LDAP")},
+  { oHTTPProxy,  "http-proxy", 2,
+    N_("|URL|redirect all HTTP requests to URL")},
+  { oLDAPProxy,  "ldap-proxy", 2,
+    N_("|HOST|use HOST for LDAP queries")},
+  { oOnlyLDAPProxy, "only-ldap-proxy", 0, 
+    N_("do not use fallback hosts with --ldap-proxy")},
 
   { oLDAPFile, "ldapserverlist-file", 2,
     N_("|FILE|read LDAP server list from FILE")},
@@ -139,6 +155,9 @@
   { oDebugWait, "debug-wait", 1, "@"},
   { oNoGreeting, "no-greeting", 0, "@"},
   { oHomedir, "homedir", 2, "@" },  
+  { oLDAPWrapperProgram, "ldap-wrapper-program", 2, "@"},
+  { oHTTPWrapperProgram, "http-wrapper-program", 2, "@"},
+  { oHonorHTTPProxy,     "honor-http-proxy", 0, "@" },
   {0}
 };
 
@@ -153,6 +172,8 @@
 /* Keep track of the current log file so that we can avoid updating
    the log file after a SIGHUP if it didn't changed. Malloced. */
 static char *current_logfile;
+/* Name of a config file, which will be reread on a HUP if it is not NULL. */
+static char *config_filename;
 /* Helper to implement --debug-level. */
 static const char *debug_level;
 /* Flag indicating that a shutdown has been requested.  */
@@ -344,6 +365,13 @@
       opt.quiet = 0;
       opt.verbose = 0;
       opt.debug = 0;
+      opt.ldap_wrapper_program = NULL;
+      opt.disable_http = 0;
+      opt.disable_ldap = 0; 
+      opt.honor_http_proxy = 0; 
+      opt.http_proxy = NULL; 
+      opt.ldap_proxy = NULL; 
+      opt.only_ldap_proxy = 0;
       return 1;
     }
 
@@ -367,10 +395,24 @@
         }
       break;
 
+    case oLDAPWrapperProgram:
+      opt.ldap_wrapper_program = pargs->r.ret_str;
+      break;
+    case oHTTPWrapperProgram:
+      opt.http_wrapper_program = pargs->r.ret_str;
+      break;
+
+    case oDisableHTTP: opt.disable_http = 1; break;
+    case oDisableLDAP: opt.disable_ldap = 1; break;
+    case oHonorHTTPProxy: opt.honor_http_proxy = 1; break;
+    case oHTTPProxy: opt.http_proxy = pargs->r.ret_str; break;
+    case oLDAPProxy: opt.ldap_proxy = pargs->r.ret_str; break;
+    case oOnlyLDAPProxy: opt.only_ldap_proxy = 1; break;
+
     default:
       return 0; /* Not handled. */
     }
-  set_debug ();
+
   return 1; /* Handled. */
 }
 
@@ -396,7 +438,6 @@
   int debug_wait = 0;
   int rc;
   int homedir_seen = 0;
-  int daemon_seen = 0;
 
   set_strusage (my_strusage);
   log_set_prefix ("dirmngr", 1|4); 
@@ -458,6 +499,9 @@
 #endif
     }
 
+  /* Reset rereadable options to default values. */
+  parse_rereadable_options (NULL, 0); 
+
   /* LDAP defaults */
   opt.add_new_ldapservers = 0;
   opt.ldaptimeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
@@ -494,14 +538,18 @@
           homedir_seen = 1;
         }
       else if (pargs.r_opt == aDaemon)
-        daemon_seen = 1;
+        opt.system_daemon = 1;
     }
 
   /* If --daemon has been given on the command line but not --homedir,
      we switch to /etc/dirmngr as default home directory.  Note, that
      this also overrides the GNUPGHOME environment variable.  */
-  if (daemon_seen && !homedir_seen)
-    opt.homedir = DIRMNGR_SYSCONFDIR;
+  if (opt.system_daemon && !homedir_seen)
+    {
+      opt.homedir = DIRMNGR_SYSCONFDIR;
+      opt.homedir_data = DIRMNGR_DATADIR;
+      opt.homedir_cache = DIRMNGR_CACHEDIR;
+    }
 
   if (default_config)
     configname = make_filename (opt.homedir, "dirmngr.conf", NULL );
@@ -608,7 +656,8 @@
     {
       fclose( configfp );
       configfp = NULL;
-      xfree(configname);
+      /* Keep a copy of the name so that it can be read on SIGHUP. */
+      config_filename = configname;
       configname = NULL;
       goto next_pass;
     }
@@ -619,6 +668,11 @@
   if (nogreeting )
     greeting = 0;
 
+  if (!opt.homedir_data)
+    opt.homedir_data = opt.homedir;
+  if (!opt.homedir_cache)
+    opt.homedir_cache = opt.homedir;
+
   if (greeting)
     {
       fprintf (stderr, "%s %s; %s\n",
@@ -642,7 +696,10 @@
   /* Get LDAP server list from file. */
   if (!ldapfile) 
     {
-      ldapfile = make_filename (opt.homedir, "dirmngr_ldapservers.conf", NULL);
+      ldapfile = make_filename (opt.homedir,
+                                opt.system_daemon?
+                                "ldapservers.conf":"dirmngr_ldapservers.conf",
+                                NULL);
       opt.ldapservers = parse_ldapserver_file (ldapfile);
       xfree (ldapfile);
     }
@@ -896,7 +953,6 @@
   else if (cmd == aGPGConfList)
     {
       char *filename;
-
       /* List options and default values in the GPG Conf format.  */
 
 /* The following list is taken from gnupg/tools/gpgconf-comp.c.  */
@@ -915,10 +971,11 @@
 
       /* First the configuration file.  This is not an option, but it
 	 is vital information for GPG Conf.  */
-      filename = make_filename (opt.homedir, "dirmngr.conf", NULL);
+      if (!config_filename)
+        config_filename = make_filename (opt.homedir, "dirmngr.conf", NULL );
+
       printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
-              GC_OPT_FLAG_DEFAULT, filename);
-      xfree (filename);
+              GC_OPT_FLAG_DEFAULT, config_filename);
 
       printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
       printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
@@ -932,7 +989,10 @@
          and having both of them is thus problematic.  --no-detach is
          also only usable on the command line.  --batch is unused.  */
 
-      filename = make_filename (opt.homedir, "dirmngr_ldapservers.conf", NULL);
+      filename = make_filename (opt.homedir, 
+                                opt.system_daemon?
+                                "ldapservers.conf":"dirmngr_ldapservers.conf",
+                                NULL);
       printf ("ldapserverlist-file:%lu:\"%s\n", GC_OPT_FLAG_DEFAULT, filename);
       xfree (filename);
 
@@ -946,6 +1006,13 @@
 
       printf ("faked-system-time:%lu:\n", GC_OPT_FLAG_NONE);
       printf ("no-greeting:%lu:\n", GC_OPT_FLAG_NONE);
+
+      printf ("disable-http:%lu:\n", GC_OPT_FLAG_NONE);
+      printf ("disable-ldap:%lu:\n", GC_OPT_FLAG_NONE);
+      printf ("http-proxy:%lu:\n", GC_OPT_FLAG_NONE);
+      printf ("ldap-proxy:%lu:\n", GC_OPT_FLAG_NONE);
+      printf ("only-ldap-proxy:%lu:\n", GC_OPT_FLAG_NONE);
+
     }
   cleanup ();
   return !!rc;
@@ -1140,6 +1207,57 @@
 /*
    Stuff used in daemon mode.  
  */
+
+
+
+/* Reread parts of the configuration.  Note, that this function is
+   obviously not thread-safe and should only be called from the PTH
+   signal handler. 
+
+   Fixme: Due to the way the argument parsing works, we create a
+   memory leak here for all string type arguments.  There is currently
+   no clean way to tell whether the memory for the argument has been
+   allocated or points into the process' original arguments.  Unless
+   we have a mechanism to tell this, we need to live on with this. */
+static void
+reread_configuration (void)
+{
+  ARGPARSE_ARGS pargs;
+  FILE *fp;
+  unsigned int configlineno = 0;
+  int dummy;
+
+  if (!config_filename)
+    return; /* No config file. */
+
+  fp = fopen (config_filename, "r");
+  if (!fp)
+    {
+      log_error (_("option file `%s': %s\n"),
+                 config_filename, strerror(errno) );
+      return;
+    }
+
+  parse_rereadable_options (NULL, 1); /* Start from the default values. */
+
+  memset (&pargs, 0, sizeof pargs);
+  dummy = 0;
+  pargs.argc = &dummy;
+  pargs.flags = 1;  /* do not remove the args */
+  while (optfile_parse (fp, config_filename, &configlineno, &pargs, opts) )
+    {
+      if (pargs.r_opt < -1)
+        pargs.err = 1; /* Print a warning. */
+      else /* Try to parse this option - ignore unchangeable ones. */
+        parse_rereadable_options (&pargs, 1);
+    }
+  fclose (fp);
+
+  set_debug ();
+}
+
+
+
 /* The signal handler. */
 static void
 handle_signal (int signo)
@@ -1149,7 +1267,7 @@
     case SIGHUP:
       log_info (_("SIGHUP received - "
                   "re-reading configuration and flushing caches\n"));
-/*       reread_configuration (); */
+      reread_configuration ();
       cert_cache_deinit (0);
       crl_cache_deinit ();
       cert_cache_init ();
Index: dirmngr/src/dirmngr.h
diff -u dirmngr/src/dirmngr.h:1.20 dirmngr/src/dirmngr.h:1.21
--- dirmngr/src/dirmngr.h:1.20	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/dirmngr.h	Mon Nov 22 22:30:50 2004
@@ -67,12 +67,27 @@
   int quiet;          /* be as quiet as possible */
   int dry_run;        /* don't change any persistent data */
   int batch;          /* batch mode */
-  const char *homedir;/* configuration directory name */
+  const char *homedir;      /* Configuration directory name */
+  const char *homedir_data; /* Ditto for data files (/usr/share/dirmngr).  */
+  const char *homedir_cache; /* Ditto for cache files (/var/cache/dirmngr).  */
+
+  char *ldap_wrapper_program; /* Override value for the LDAP wrapper
+                                 program.  */
+  char *http_wrapper_program; /* Override value for the HTTP wrapper
+                                 program.  */
 
+  int system_daemon;    /* We are running in system daemon mode.  */
   int running_detached; /* We are running in detached mode.  */
 
   int force;          /* Force loading outdated CRLs. */
 
+  int disable_http;       /* Do not use HTTP at all.  */
+  int disable_ldap;       /* Do not use LDAP at all.  */
+  int honor_http_proxy;   /* Honor the http_proxy env variable. */
+  const char *http_proxy; /* Use given HTTP proxy.  */
+  const char *ldap_proxy; /* Use given LDAP proxy.  */
+  int only_ldap_proxy;    /* Only use the LDAP proxy; no fallback.  */
+
   int allow_ocsp;     /* Allow using OCSP. */
 
   int max_replies;
Index: dirmngr/src/dirmngr_ldap.c
diff -u dirmngr/src/dirmngr_ldap.c:1.2 dirmngr/src/dirmngr_ldap.c:1.3
--- dirmngr/src/dirmngr_ldap.c:1.2	Thu Nov 18 16:37:48 2004
+++ dirmngr/src/dirmngr_ldap.c	Mon Nov 22 22:30:50 2004
@@ -54,6 +54,7 @@
 
     oTimeout      = 500,
     oMulti,
+    oProxy,
     oHost,
     oPort,
     oUser,
@@ -74,6 +75,8 @@
   { oTimeout,  "timeout",   1, N_("|N|set LDAP timeout to N seconds")},
   { oMulti,    "multi",     0, N_("return all values in"
                                   " a record oriented format")},
+  { oProxy,    "proxy",     2,
+    N_("|NAME|ignore host part and connect through NAME")},
   { oHost,     "host",      2, N_("|NAME|connect to host NAME")},
   { oPort,     "port",      1, N_("|N|connect to port N")},
   { oUser,     "user",      2, N_("|NAME|use user NAME for authentication")},
@@ -97,6 +100,7 @@
 
   /* Note that we can't use const for the strings because ldap_* are
      not defined that way.  */
+  char *proxy; /* Host and Port override.  */
   char *user;  /* Authentication user.  */
   char *pass;  /* Authentication password.  */
   char *host;  /* Override host.  */
@@ -165,6 +169,7 @@
 {
   ARGPARSE_ARGS pargs;
   int any_err = 0;
+  char *p;
 
   set_strusage (my_strusage);
   log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX); 
@@ -197,6 +202,7 @@
         case oEnvPass:
           opt.pass = getenv ("DIRMNGR_LDAP_PASS");
           break;
+        case oProxy: opt.proxy = pargs.r.ret_str; break;
         case oHost: opt.host = pargs.r.ret_str; break;
         case oPort: opt.port = pargs.r.ret_int; break;
         case oDN:   opt.dn = pargs.r.ret_str; break;
@@ -206,6 +212,20 @@
         default : pargs.err = 2; break;
 	}
     }
+
+  if (opt.proxy)
+    {
+      opt.host = xstrdup (opt.proxy);
+      p = strchr (opt.host, ':');
+      if (p)
+        {
+          *p++ = 0;
+          opt.port = atoi (p);
+        }
+      if (!opt.port)
+        opt.port = 389;  /* make sure ports gets overridden.  */
+    }
+        
   if (opt.port < 0 || opt.port > 65535)
     log_error (_("invalid port number %d\n"), opt.port);
 
@@ -215,6 +235,7 @@
   if (argc < 1)
     usage (1);
 
+
   for (; argc; argc--, argv++)
     if (process_url (*argv))
       any_err = 1;
Index: dirmngr/src/http.c
diff -u dirmngr/src/http.c:1.6 dirmngr/src/http.c:1.7
--- dirmngr/src/http.c:1.6	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/http.c	Mon Nov 22 22:30:50 2004
@@ -1,5 +1,5 @@
 /* http.c  -  HTTP protocol handler
- *      Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -63,7 +63,7 @@
 static int insert_escapes (unsigned char *buffer, const unsigned char *string,
                            const unsigned char *special);
 static uri_tuple_t parse_tuple (unsigned char *string);
-static gpg_error_t send_request (http_t hd);
+static gpg_error_t send_request (http_t hd, const char *proxy);
 static unsigned char *build_rel_path (parsed_uri_t uri);
 static gpg_error_t parse_response (http_t hd);
 
@@ -72,7 +72,8 @@
 
 
 gpg_error_t
-http_open (http_t hd, http_req_t reqtype, const char *url, unsigned int flags)
+http_open (http_t hd, http_req_t reqtype, const char *url, unsigned int flags,
+           const char *proxy)
 {
   gpg_error_t err;
 
@@ -89,7 +90,7 @@
   err = http_parse_uri (&hd->uri, url);
   if (!err)
     {
-      err = send_request (hd);
+      err = send_request (hd, proxy);
       if (!err)
         {
           hd->fp_write = fdopen (hd->sock, "w");
@@ -156,13 +157,16 @@
 
 
 /* Convenience function to send a request and wait for the response.
-   Closes the handle on error. */
+   Closes the handle on error.  If PROXY is not NULL, this value will
+   be used as a HTTP proxy and any enabled $http_proxy gets
+   ignored. */
 gpg_error_t
-http_open_document (http_t hd, const char *document, unsigned int flags)
+http_open_document (http_t hd, const char *document, unsigned int flags,
+                    const char *proxy)
 {
   gpg_error_t err;
 
-  err = http_open (hd, HTTP_REQ_GET, document, flags);
+  err = http_open (hd, HTTP_REQ_GET, document, flags, proxy);
   if (err)
     return err;
 
@@ -444,7 +448,7 @@
  * Returns 0 if the request was successful
  */
 static gpg_error_t
-send_request (http_t hd)
+send_request (http_t hd, const char *proxy)
 {
   const unsigned char *server;
   unsigned char *request, *p;
@@ -456,17 +460,20 @@
   server = *hd->uri->host ? hd->uri->host : "localhost";
   port = hd->uri->port ? hd->uri->port : 80;
 
-  if ((hd->flags & HTTP_FLAG_TRY_PROXY)
-      && (http_proxy = getenv (HTTP_PROXY_ENV)))
+  if (proxy
+      || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
+           && (http_proxy = getenv (HTTP_PROXY_ENV))))
     {
       parsed_uri_t uri;
+      
+      if (proxy)
+        http_proxy = proxy;
 
       err = http_parse_uri (&uri, http_proxy);
       if (err)
         {
-          log_error (_("invalid %s: %s\n"),
-                     HTTP_PROXY_ENV_PRINTABLE,
-                     gpg_strerror (err));
+          log_error (_("invalid HTTP proxy (%s): %s\n"),
+                     http_proxy, gpg_strerror (err));
           http_release_parsed_uri (uri);
           return gpg_error (GPG_ERR_CONFIGURATION);
         }
Index: dirmngr/src/http.h
diff -u dirmngr/src/http.h:1.1 dirmngr/src/http.h:1.2
--- dirmngr/src/http.h:1.1	Fri Dec 12 18:36:49 2003
+++ dirmngr/src/http.h	Mon Nov 22 22:30:50 2004
@@ -76,12 +76,14 @@
 void http_release_parsed_uri (parsed_uri_t uri);
 
 gpg_error_t http_open (http_t hd, http_req_t reqtype,
-                       const char *url, unsigned int flags );
+                       const char *url, unsigned int flags,
+                       const char *proxy);
 void http_start_data (http_t hd);
 gpg_error_t http_wait_response (http_t hd, unsigned int *ret_status);
 void http_close (http_t hd, int keep_read_stream);
 
 gpg_error_t http_open_document (http_t hd,
-                                const char *document, unsigned int flags);
+                                const char *document, unsigned int flags,
+                                const char *proxy);
 
 #endif /*HTTP_H*/
Index: dirmngr/src/ldap.c
diff -u dirmngr/src/ldap.c:1.35 dirmngr/src/ldap.c:1.36
--- dirmngr/src/ldap.c:1.35	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/ldap.c	Mon Nov 22 22:30:50 2004
@@ -1,6 +1,6 @@
 /* ldap.c - LDAP access
  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *      Copyright (C) 2003 g10 Code GmbH
+ *      Copyright (C) 2003, 2004 g10 Code GmbH
  *
  * This file is part of DirMngr.
  *
@@ -541,11 +541,16 @@
 
   if (!pid)
     { /* Child. */
-      char *pgmname = "/home/wk/w/dirmngr/src/dirmngr_ldap"; /*FIXME*/
+      char *pgmname;
       char **arg_list;
       int n, i, j;
       int fd;
 
+      if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
+        pgmname = DIRMNGR_LIBEXECDIR "/ldap_wrapper";
+      else
+        pgmname = opt.ldap_wrapper_program;
+
       /* Create command line argument array.  */
       for (i=0; argv[i]; i++)
         ;
@@ -658,6 +663,7 @@
    The function returns a new stream at R_FP. */
 static gpg_error_t
 run_ldap_wrapper (ctrl_t ctrl, 
+                  const char *proxy,
                   const char *host, int port, 
                   const char *user, const char *pass,
                   const char *dn, const char *filter, const char *attr,
@@ -678,6 +684,11 @@
     }
   if (opt.verbose)
     argv[argc++] = "-vv";
+  if (proxy)
+    {
+      argv[argc++] = "--proxy";
+      argv[argc++] = proxy;
+    }
   if (host)
     {
       argv[argc++] = "--host";
@@ -725,12 +736,16 @@
 url_fetch_ldap (ctrl_t ctrl, const char *url, const char *host, int port,
                 ksba_reader_t *reader)
 {
-  return run_ldap_wrapper (ctrl,
-                           host, port,
-                           NULL, NULL,
-                           NULL, NULL, NULL, url,
-                           reader);
+  gpg_error_t err;
 
+  err = run_ldap_wrapper (ctrl,
+                          opt.ldap_proxy,
+                          host, port,
+                          NULL, NULL,
+                          NULL, NULL, NULL, url,
+                          reader);
+
+  return err;
   /* FIXME: This option might be used for DoS attacks.  Becuase it
      will enlarge the list of servers to consult without a limit and
      all LDAP queries w/o a host are will then try each host in
@@ -754,6 +769,7 @@
   for (server = opt.ldapservers; server; server = server->next)
     {
       err = run_ldap_wrapper (ctrl,
+                              opt.ldap_proxy,
                               server->host, server->port,
                               server->user, server->pass,
                               dn, "objectClass=*", attr, NULL,
@@ -978,6 +994,11 @@
   if (opt.verbose)
     argv[argc++] = "-vv";
   argv[argc++] = "--multi";
+  if (opt.ldap_proxy)
+    {
+      argv[argc++] = "--proxy";
+      argv[argc++] = opt.ldap_proxy;
+    }
   if (host)
     {
       argv[argc++] = "--host";
Index: dirmngr/src/ocsp.c
diff -u dirmngr/src/ocsp.c:1.9 dirmngr/src/ocsp.c:1.10
--- dirmngr/src/ocsp.c:1.9	Wed Aug 18 18:41:42 2004
+++ dirmngr/src/ocsp.c	Mon Nov 22 22:30:50 2004
@@ -27,6 +27,7 @@
 #include "dirmngr.h"
 #include "misc.h"
 #include "http.h"
+#include "validate.h"
 
 #include "ocsp.h"
 
@@ -112,8 +113,13 @@
   struct http_context_s http;
   ksba_ocsp_response_status_t response_status;
   const char *t;
-  
-    
+
+  if (opt.disable_http)
+    {
+      log_error (_("OCSP request not possible due to disabled HTTP\n"));
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
   err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
   if (err)
     {
@@ -139,7 +145,9 @@
       return err;
     }
 
-  err = http_open (&http, HTTP_REQ_POST, url, 0);
+  err = http_open (&http, HTTP_REQ_POST, url,
+                   opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0,
+                   opt.http_proxy);
   if (err)
     {
       log_error (_("error connecting to `%s': %s\n"), url, gpg_strerror (err));
@@ -236,29 +244,38 @@
 static gpg_error_t
 validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert)
 {
+  gpg_error_t err;
   char *fpr;
 
-  /* We avoid duplicating the entire certificate validation code from
-     gpgsm here.  Because we have no way calling back to the client
-     and letting it compute the validity, we use the ugly hack of
-     telling the client that the response will only be valid if the
-     certificate given in this status message is valid. 
-
-     Note, that in theory we could simply ask the client via an
-     inquire to validate a certificate but this might involve calling
-     DirMngr again recursivly - we can't do that as of now (neither
-     DirMngr nor gpgsm have the ability for concurrent access to
-     DirMngr.
-   */
-
-  /* FIXME: We should cache this certificate locally, so that the next
-     call to dirmngr won't need to look it up - if this works at
-     all. */
-  fpr = get_fingerprint_hexstring (cert);
-  dirmngr_status (ctrl, "ONLY_VALID_IF_CERT_VALID", fpr, NULL);
-  xfree (fpr);
+  if (opt.system_daemon)
+    {
+      err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_OCSP);
+    }
+  else
+    {
+      /* We avoid duplicating the entire certificate validation code
+         from gpgsm here.  Because we have no way calling back to the
+         client and letting it compute the validity, we use the ugly
+         hack of telling the client that the response will only be
+         valid if the certificate given in this status message is
+         valid.
+
+         Note, that in theory we could simply ask the client via an
+         inquire to validate a certificate but this might involve
+         calling DirMngr again recursivly - we can't do that as of now
+         (neither DirMngr nor gpgsm have the ability for concurrent
+         access to DirMngr.   */
+
+      /* FIXME: We should cache this certificate locally, so that the next
+         call to dirmngr won't need to look it up - if this works at
+         all. */
+      fpr = get_fingerprint_hexstring (cert);
+      dirmngr_status (ctrl, "ONLY_VALID_IF_CERT_VALID", fpr, NULL);
+      xfree (fpr);
+      err = 0;
+    }
 
-  return 0;
+  return err;
 }
 
 
Index: dirmngr/src/server.c
diff -u dirmngr/src/server.c:1.45 dirmngr/src/server.c:1.46
--- dirmngr/src/server.c:1.45	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/server.c	Mon Nov 22 22:30:50 2004
@@ -83,8 +83,8 @@
    target string D as long as the source string S, i.e.: strlen(s)+1.
    NOte further that If S contains an escaped binary nul the resulting
    string D will contain the 0 as well as all other characters but it
-   will be impossible to kno whether this is the original eos or a
-   copied nul. */
+   will be impossible to know whether this is the original EOS or a
+   copied Nul. */
 static void
 strcpy_escaped_plus (char *d, const unsigned char *s)
 {
@@ -190,114 +190,6 @@
 }
 
 
-/* Locate the corresponding CRL for the certificate CERT, read and
-   verify the CRL and store it in the cache.  */
-static int
-reload_crl (ctrl_t ctrl, ksba_cert_t cert) 
-{
-  gpg_error_t err;
-  ksba_reader_t reader = NULL;
-  char *issuer = NULL;
-  ksba_name_t distpoint = NULL;
-  ksba_name_t issuername = NULL;
-  char *distpoint_uri = NULL;
-  char *issuername_uri = NULL;
-  int any_dist_point = 0;
-  int seq;
-
-  /* Loop over all distribution points, get the CRLs and put them into
-     the cache. */
-  if (DBG_X509)
-    log_debug ("checking distribution points\n");
-  seq = 0;
-  while ( !(err = ksba_cert_get_crl_dist_point (cert, seq++,
-                                                &distpoint,
-                                                &issuername, NULL )))
-    {
-      if (!distpoint && !issuername)
-        {
-          if (DBG_X509)
-            log_debug ("no issuer name and no distribution point\n");
-          break; /* Not allowed; i.e. an invalid certificate.  We give
-                    up here and hope that the default method returns a
-                    suitable CRL. */
-        }
-
-      /* Get the URIs. */
-      xfree (distpoint_uri); distpoint_uri = NULL;
-      xfree (issuername_uri); issuername_uri = NULL;
-      distpoint_uri = ksba_name_get_uri (distpoint, 0); 
-      issuername_uri = ksba_name_get_uri (issuername, 0); 
-      ksba_name_release (distpoint); distpoint = NULL;
-      ksba_name_release (issuername); issuername = NULL;
-      any_dist_point = 1;
-      
-      err = crl_fetch (ctrl, distpoint_uri, &reader);
-      if (err)
-        {
-          log_error (_("crl_fetch via DP failed: %s\n"), gpg_strerror (err));
-          goto leave;
-        }
-      
-      err = crl_cache_insert (ctrl, distpoint_uri, reader); 
-      if (err)
-        {
-          log_error (_("crl_cache_insert via DP failed: %s\n"),
-                     gpg_strerror (err));
-          goto leave;
-        }
-    }
-  if (gpg_err_code (err) == GPG_ERR_EOF)
-    err = 0;
-
-  /* If we did not found any distpoint, try something reasonable. */
-  if (!any_dist_point )
-    {
-      if (DBG_X509)
-        log_debug ("no distribution point - trying issuer name\n");
-      
-      if (reader)
-        {
-          crl_close_reader (reader);
-          reader = NULL;
-        }
-
-      issuer = ksba_cert_get_issuer (cert, 0);
-      if (!issuer) 
-        {
-          log_error ("oops: issuer missing in certificate\n");
-          err = gpg_error (GPG_ERR_INV_CERT_OBJ); 
-          goto leave;
-        }
-
-      err = crl_fetch_default (ctrl, issuer, &reader);
-      if (err)
-          {
-            log_error (_("crl_fetch via issuer failed: %s\n"),
-                       gpg_strerror (err));
-            goto leave;
-          }
-
-      err = crl_cache_insert (ctrl, "default location(s)", reader);
-      if (err)
-        {
-          log_error (_("crl_cache_insert via issuer failed: %s\n"),
-                     gpg_strerror (err));
-          goto leave;
-        }
-    }
-
- leave:
-  if (reader)
-    crl_close_reader (reader);
-  xfree (distpoint_uri);
-  xfree (issuername_uri);
-  ksba_name_release (distpoint); 
-  ksba_name_release (issuername); 
-  ksba_free (issuer);
-  return err;
-}
-
 
 
 /* Ask the client to return the certificate asscociated with the
@@ -336,7 +228,7 @@
     goto leave;
   xfree (value); value = NULL;
 
-  err = reload_crl (ctrl, cert);
+  err = crl_cache_reload_crl (ctrl, cert);
 
  leave:
   ksba_cert_release (cert);
@@ -526,10 +418,7 @@
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
   unsigned char fprbuffer[20], *fpr;
-  unsigned char issuerhash[20];
-  char issuerhash_hex[41];
   ksba_cert_t cert;
-  char *serialno = NULL;
 
   fpr = get_fingerprint_from_line (line, fprbuffer);
   cert = fpr? get_cert_byfpr (fpr) : NULL;
@@ -566,113 +455,18 @@
 
   assert (cert);
 
-  /* Compute the hash value of the issuer name.  */
-  {
-    char *tmp;
-    int i;
-
-    tmp = ksba_cert_get_issuer (cert, 0);
-    if (!tmp)
-      {
-        log_error ("oops: issuer missing in certificate\n");
-        err = gpg_error (GPG_ERR_INV_CERT_OBJ);
-        goto leave;
-      }
-    gcry_md_hash_buffer (GCRY_MD_SHA1, issuerhash, tmp, strlen (tmp));
-    xfree (tmp);
-    for (i=0,tmp=issuerhash_hex; i < 20; i++, tmp += 2)
-      sprintf (tmp, "%02X", issuerhash[i]);
-  }
-
-  /* FIXME: We don't have a suitable check function so we need to format the
-     S/N as string first. */
-  {
-    ksba_sexp_t serial;
-    unsigned char *p;
-    unsigned long n;
-    char *endp, *tmp;
-    int i;
-
-    serial = ksba_cert_get_serial (cert);
-    if (!serial)
-      {
-        log_error ("oops: S/N missing in certificate\n");
-        err = gpg_error (GPG_ERR_INV_CERT_OBJ);
-        goto leave;
-      }
-    p = serial;
-    if (*p != '(')
-      {
-        log_error ("oops: invalid S/N\n");
-        err = gpg_error (GPG_ERR_INV_CERT_OBJ);
-        xfree (serial);
-        goto leave;
-      }
-    p++;
-    n = strtoul (p, &endp, 10);
-    p = endp;
-    if (*p != ':')
-      {
-        log_error ("oops: invalid S/N\n");
-        err = gpg_error (GPG_ERR_INV_CERT_OBJ);
-        xfree (serial);
-        goto leave;
-      }
-    p++;
-
-    serialno = tmp = xtrymalloc (n*2 + 1);
-    if (!serialno)
-      {
-        err = gpg_error_from_errno (errno);
-        xfree (serial);
-        goto leave;
-      }
-    
-    for (i=0; i < n; i++, tmp += 2)
-      sprintf (tmp, "%02X", p[i]);
-    *tmp = 0;
-    xfree (serial);
-  }
-
-  /* Now use our old function to do the actual CRL check.  */
-  {
-    int reloaded = 0;
-
-  again:
-    switch (crl_cache_isvalid (ctrl,
-                               issuerhash_hex, serialno,
-                               ctrl->force_crl_refresh))
-      {
-      case CRL_CACHE_VALID:
-        err = 0;
-        break;
-      case CRL_CACHE_INVALID:
-        err = gpg_error (GPG_ERR_CERT_REVOKED);
-        break;
-      case CRL_CACHE_DONTKNOW: 
-        if (reloaded)
-          err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
-        else
-          {
-            reloaded = 1;
-            err = reload_crl (ctrl, cert);
-            if (!err)
-              goto again;
-          }
-        break;
-      case CRL_CACHE_CANTUSE: 
-        err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
-        break;
-      default:
-        log_fatal ("crl_cache_isvalid returned invalid status code\n");
-      }
-  }
+  err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
+  if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
+    {
+      err = crl_cache_reload_crl (ctrl, cert);
+      if (!err)
+        err = crl_cache_cert_isvalid (ctrl, cert, 0);
+    }
 
  leave:
   if (err)
     log_error (_("command %s failed: %s\n"), "CHECKCRL", gpg_strerror (err));
   ksba_cert_release (cert);
-  xfree (serialno);
   return map_to_assuan_status (err);
 }
 
@@ -1001,7 +795,7 @@
   if(err)
     goto leave;
 
-  err = validate_cert_chain (ctrl, cert, NULL);
+  err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_CRL_RECURSIVE);
 
  leave:
   if (err)
Index: dirmngr/src/validate.c
diff -u dirmngr/src/validate.c:1.3 dirmngr/src/validate.c:1.4
--- dirmngr/src/validate.c:1.3	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/validate.c	Mon Nov 22 22:30:50 2004
@@ -31,9 +31,24 @@
 
 #include "dirmngr.h"
 #include "certcache.h"
+#include "crlcache.h"
 #include "validate.h"
 #include "misc.h"
 
+/* While running the validation function we need to keep tarckl of the
+   cretificates and the validation outcome of each.  We use this type
+   for it.  */
+struct chain_item_s
+{
+  ksba_cert_t cert;      /* The certificate.  */
+  unsigned char fpr[20]; /* Fingerprint of the certificate.  */
+  int is_self_signed;    /* This certificate is self-signed.  */
+  int is_valid;          /* The certifiate is valid except for revocations.  */
+};
+typedef struct chain_item_s *chain_item_t;
+
+
+/* A couple of constants with Object Identifiers.  */
 static const char oid_kp_serverAuth[]     = "1.3.6.1.5.5.7.3.1";
 static const char oid_kp_clientAuth[]     = "1.3.6.1.5.5.7.3.2";
 static const char oid_kp_codeSigning[]    = "1.3.6.1.5.5.7.3.3";
@@ -42,7 +57,7 @@
 static const char oid_kp_ocspSigning[]    = "1.3.6.1.5.5.7.3.9";
 
 
-
+/* Prototypes.  */
 static gpg_error_t check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert);
 
 
@@ -165,34 +180,88 @@
   return 0;
 }
 
+/* Helper for validate_cert_chain.  IDX is the index to the last
+   element in the chain and NOT the length of the chain. */
+static gpg_error_t
+check_revocations (ctrl_t ctrl, chain_item_t *chain, int idx)
+{
+  gpg_error_t err = 0;
+  int any_revoked = 0;
+  int any_no_crl = 0;
+  int any_crl_too_old = 0;
+
+
+  assert (idx >=0);
+  if (!idx && !chain[0]->cert)
+    return 0; /* Target certificate is a trusted root certificate.  */
+  
+  for (;idx >= 0 && !err; idx--)
+    {
+      assert (chain[idx]->cert);
+      
+      err = crl_cache_cert_isvalid (ctrl, chain[idx]->cert, 0);
+      if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
+        {
+          err = crl_cache_reload_crl (ctrl, chain[idx]->cert);
+          if (!err)
+            err = crl_cache_cert_isvalid (ctrl, chain[idx]->cert, 0);
+        }
+      switch (gpg_err_code (err))
+        {
+        case 0: err = 0; break;
+        case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break;
+        case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break;
+        case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
+        default: break;
+        }
+    }
+
+
+  if (err)
+    ;
+  else if (any_revoked)
+    err = gpg_error (GPG_ERR_CERT_REVOKED);
+  else if (any_no_crl)
+    err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+  else if (any_crl_too_old)
+    err = gpg_error (GPG_ERR_CRL_TOO_OLD);
+  else
+    err = 0;
+  return err;
+}
+
+
 
 /* Validate the certificate CHAIN up to the trust anchor. Optionally
    return the closest expiration time in R_EXPTIME (this is useful for
-   caching issues).  */
-
- /* FIXME: We need to check for evoked certifciates too.  */
+   caching issues).  MODE is one of the VALIDATE_MODE_* constants. */
 gpg_error_t
-validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime)
+validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
+                     int mode)
 {
   gpg_error_t err = 0;
-  int depth = 0, maxdepth;
+  int depth, maxdepth;
   char *issuer = NULL;
   char *subject = NULL;
   ksba_cert_t subject_cert = NULL, issuer_cert = NULL;
   ksba_isotime_t current_time;
   ksba_isotime_t exptime;
   int any_expired = 0;
-  int any_revoked = 0;
-  int any_no_crl = 0;
-  int any_crl_too_old = 0;
   int any_no_policy_match = 0;
+  chain_item_t *chain;
+
 
-  /* Get the current time. */
-  get_isotime (current_time);
   if (r_exptime)
     *r_exptime = 0;
   *exptime = 0;
 
+  if (opt.system_daemon)
+    return 0; /* For backward compatibility we only do this in daemon
+                 mode.  */
+
+  /* Get the current time. */
+  get_isotime (current_time);
+
   if (DBG_X509)
     dump_cert ("subject", cert);
 
@@ -200,6 +269,11 @@
   subject_cert = cert;
   maxdepth = 50;
 
+  chain = xtrycalloc (maxdepth+1, sizeof *chain);
+  if (!chain)
+    return gpg_error_from_errno (errno);
+  depth = 0;
+
   for (;;)
     {
       /* Get the subject and issuer name from the current
@@ -273,7 +347,7 @@
       if (gpg_err_code (err) == GPG_ERR_NO_POLICY_MATCH)
         {
           any_no_policy_match = 1;
-          err = 1; /*???? FIXME*/
+          err = 0; 
         }
       else if (err)
         goto leave;
@@ -293,7 +367,6 @@
           err = allowed_ca (subject_cert, NULL);
           if (err)
             goto leave;  /* No. */
-
           
           err = is_trusted_cert (subject_cert);
           if (!err)
@@ -317,8 +390,6 @@
           if (err)
             goto leave;
 
-          /* FIXME: Now check whether this certificate has been revoked.  */
-
           break;  /* Okay: a self-signed certicate is an end-point. */
         }
 
@@ -425,8 +496,12 @@
       err = cert_use_cert_p (issuer_cert);
       if (err)
         goto leave;  /* No.  */
-
-      /* FIXME: Now check whether this certificate has been revoked.  */
+      
+      /* Append the certificate to our list.  */
+      assert (depth <= maxdepth);
+      ksba_cert_ref (subject_cert);
+      chain[depth]->cert = subject_cert;
+      cert_compute_fpr (subject_cert, chain[depth]->fpr);
 
       if (opt.verbose)
         log_info ("certificate is good\n");
@@ -439,17 +514,52 @@
   if (!err)
     { /* If we encountered an error somewhere during the checks, set
          the error code to the most critical one */
-      if (any_revoked)
-        err = gpg_error (GPG_ERR_CERT_REVOKED);
-      else if (any_expired)
+      if (any_expired)
         err = gpg_error (GPG_ERR_CERT_EXPIRED);
-      else if (any_no_crl)
-        err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
-      else if (any_crl_too_old)
-        err = gpg_error (GPG_ERR_CRL_TOO_OLD);
       else if (any_no_policy_match)
         err = gpg_error (GPG_ERR_NO_POLICY_MATCH);
     }
+
+
+  /* May the certificate be used for OCSP response signing.  */
+  if (mode == VALIDATE_MODE_OCSP && chain[0]->cert)
+    {
+      err = cert_use_ocsp_p (chain[0]->cert);
+    }
+  
+  /* May the certificate be used for CR signing.  */
+
+  /* FIXME. */
+
+
+  if (!err)
+    { /* Now that everything is fine, walk the chain and check each
+         certificate for revocations. 
+
+         chain[0]     - The target certificate.
+         chain[1]     - The CA which signed chain[0]
+         ...
+         chain[depth] - The CA which signed chain[depth-1].
+
+         Note that we do not include the root certificate in this list
+         because we axiomatically know that it is trusted and there is
+         no point to do futher investigations.  DEPTH might be zero in
+         case the target certificate is directly signed by the root
+         certificate or there might even be no list at all (DEPTH is 0
+         and chain[0]->cert is NULL) if the target certificate is the
+         root certificate.
+
+         Now for each certificate in the chain check whether it has
+         been included in a CRL and thus be revoked.  We don't do OCSP
+         here because this does not seem to make much sense.  This
+         might become a recursive process and we should better cache
+         our validity results to avoid double work.  Far worse a
+         catch-22 may happen for an improper setup hierachy and we
+         need a way to break up this deadlock. */
+
+      err = check_revocations (ctrl, chain, depth);
+    }
+
   
  leave:
   if (r_exptime)
@@ -458,6 +568,10 @@
   ksba_cert_release (issuer_cert);
   if (subject_cert != cert)
     ksba_cert_release (subject_cert);
+  for (; depth; depth--)
+    if (chain[depth]->cert)
+      ksba_cert_release (chain[depth]->cert);
+  xfree (chain);
   return err;
 }
 
Index: dirmngr/src/validate.h
diff -u dirmngr/src/validate.h:1.2 dirmngr/src/validate.h:1.3
--- dirmngr/src/validate.h:1.2	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/validate.h	Mon Nov 22 22:30:50 2004
@@ -22,10 +22,18 @@
 #define VALIDATE_H
 
 
+enum {
+  VALIDATE_MODE_CRL = 1,
+  VALIDATE_MODE_CRL_RECURSIVE = 2,
+  VALIDATE_MODE_OCSP = 3
+};
+
+
 /* Validate the certificate CHAIN up to the trust anchor. Optionally
    return the closest expiration time in R_EXPTIME. */
 gpg_error_t validate_cert_chain (ctrl_t ctrl,
-                                 ksba_cert_t cert, ksba_isotime_t r_exptime);
+                                 ksba_cert_t cert, ksba_isotime_t r_exptime,
+                                 int mode);
 
 /* Return 0 if the certificate CERT is usable for certification.  */
 gpg_error_t cert_use_cert_p (ksba_cert_t cert);




More information about the Gnupg-commits mailing list