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