dirmngr (11 files)
cvs user wk
cvs at cvs.gnupg.org
Thu Nov 18 16:31:40 CET 2004
Date: Thursday, November 18, 2004 @ 16:37:48
Author: wk
Path: /cvs/dirmngr/dirmngr
Modified: doc/dirmngr.texi src/ChangeLog src/certcache.c src/certcache.h
src/crlcache.c src/dirmngr-client.c src/dirmngr.c
src/dirmngr_ldap.c src/ldap.c src/server.c src/validate.c
* dirmngr-client.c: New options --cache-cert and --validate.
(do_cache, do_validate): New.
* server.c (cmd_cachecert, cmd_validate): New.
* crlcache.c (get_issuer_cert): Make use of the certificate cache.
(crl_parse_insert): Validate the issuer certificate.
* dirmngr.c (handle_signal): Reinitialize the certificate cache on
a HUP.
(struct opts): Add --homedir to enable the already implemented code.
(handle_signal): Print stats on SIGUSR1.
* certcache.c (clean_cache_slot, cert_cache_init)
(cert_cache_deinit): New.
(acquire_cache_read_lock, acquire_cache_write_lock)
(release_cache_lock): New. Use them where needed.
(put_cert): Renamed from put_loaded_cert.
(cache_cert): New.
(cert_cache_print_stats): New.
----------------------+
doc/dirmngr.texi | 110 ++++++++++++++
src/ChangeLog | 21 ++
src/certcache.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++--
src/certcache.h | 17 ++
src/crlcache.c | 18 ++
src/dirmngr-client.c | 106 +++++++++++++-
src/dirmngr.c | 13 +
src/dirmngr_ldap.c | 2
src/ldap.c | 21 +-
src/server.c | 110 ++++++++++++++
src/validate.c | 8 -
11 files changed, 754 insertions(+), 34 deletions(-)
Index: dirmngr/doc/dirmngr.texi
diff -u dirmngr/doc/dirmngr.texi:1.14 dirmngr/doc/dirmngr.texi:1.15
--- dirmngr/doc/dirmngr.texi:1.14 Tue Nov 16 19:24:35 2004
+++ dirmngr/doc/dirmngr.texi Thu Nov 18 16:37:48 2004
@@ -115,6 +115,7 @@
@menu
* Dirmngr Commands:: List of all commands.
* Dirmngr Options:: List of all options.
+* Dirmngr Signals:: Use of signals.
* Dirmngr Examples:: Some usage examples.
* Dirmngr Protocol:: The protocol dirmngr uses.
* Dirmngr Client:: How to use the Dirmngr client tool.
@@ -352,6 +353,44 @@
@end table
+
+ at c
+ at c Dirmngr Signals
+ at c
+ at node Dirmngr Signals
+ at chapter Use of signals.
+A running @command{dirmngr} may be controlled by signals, i.e. using
+the @command{kill} command to send a signal to the process.
+
+Here is a list of supported signals:
+
+ at table @gnupgtabopt
+
+ at item SIGHUP
+ at cpindex SIGHUP
+This signals flushes all internally cached CRLs as well as any cached
+certificates. Then the certificate cache is reinitialized as on
+startup.
+
+ at item SIGTERM
+ at cpindex SIGTERM
+Shuts down the process but waits until all current requests are
+fulfilled. If the process has received 3 of these signals and requests
+are still pending, a shutdown is forced.
+
+ at item SIGINT
+ at cpindex SIGINT
+Shuts down the process immediately.
+
+
+ at item SIGUSR1
+ at cpindex SIGUSR1
+This prints some caching statistics to the log file.
+
+ at end table
+
+
+
@c
@c Examples
@c
@@ -360,12 +399,30 @@
@c man begin EXAMPLES
+The way to start the dirmngr in the foreground (as done by tools if no
+dirmngr is running in the background) is to use:
@example
-$ dirmngr --server -v
+ dirmngr --server -v
@end example
+If a dirmngr is supposed to be used as a system wide daemon, it should
+be started like:
+ at example
+ dirmngr --daemon
+ at end example
+This will force it to go into the backround, read the default
+certificates (including the trusted root certificates) and listen on a
+socket for client requests. It does also print information about the
+socket used but they are only for compatibilty reasons with old GnuPG
+versions and may be ignored.
+
+
+
@c man end
+
+
+
@c
@c Assuan Protocol
@c
@@ -380,6 +437,8 @@
* Dirmngr ISVALID:: Validate a certificate using a CRL or OCSP.
* Dirmngr CHECKCRL:: Validate a certificate using a CRL.
* Dirmngr CHECKOCSP:: Validate a certificate using OCSP.
+* Dirmngr CACHECERT:: Put a certificate into the internal cache.
+* Dirmngr VALIDATE:: Validate a certificate for debugging.
@end menu
@node Dirmngr LOOKUP
@@ -504,6 +563,45 @@
The return code is 0 for success; i.e. the certificate has not been
revoked or one of the usual error codes from libgpg-error.
+ at node Dirmngr CACHECERT
+ at section Put a certificate into the internal cache
+
+Put a certificate into the internal cache. This command might be
+useful if a client knows in advance certificates required for a test and
+wnats to make sure they get added to the internal cache. It is also
+helpful for debugging. To get the actual certificate, this command
+immediately inquires it using
+
+ at example
+ S: INQUIRE TARGETCERT
+ C: D <DER encoded certificate>
+ C: END
+ at end example
+
+Thus the caller is expected to return the certificate for the request
+as a binary blob.
+
+ at noindent
+The return code is 0 for success; i.e. the certificate has not been
+succesfully cached or one of the usual error codes from libgpg-error.
+
+ at node Dirmngr VALIDATE
+ at section Validate a certificate for debugging
+
+Validate a certificate using the certificate validation fucntion used
+internally by dirmngr. This command is only useful for debugging. To
+get the actual certificate, this command immediately inquires it using
+
+ at example
+ S: INQUIRE TARGETCERT
+ C: D <DER encoded certificate>
+ C: END
+ at end example
+
+Thus the caller is expected to return the certificate for the request
+as a binary blob.
+
+
@c -------------------------------------------
@c Dirmngr Client
@@ -594,6 +692,16 @@
also implicitly use with @code{--ping}.
+ at item --cache-cert
+ at opindex cache-cert
+Put the given certificate into the cache of a running dirmngr. This is
+mainly useful for debugging.
+
+ at item --validate
+ at opindex validate
+Validate the given certificate using dirmngr's internal validation code.
+This is mainly useful for debugging.
+
@end table
Index: dirmngr/src/ChangeLog
diff -u dirmngr/src/ChangeLog:1.21 dirmngr/src/ChangeLog:1.22
--- dirmngr/src/ChangeLog:1.21 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/ChangeLog Thu Nov 18 16:37:48 2004
@@ -1,3 +1,24 @@
+2004-11-18 Werner Koch <wk at g10code.com>
+
+ * dirmngr-client.c: New options --cache-cert and --validate.
+ (do_cache, do_validate): New.
+ * server.c (cmd_cachecert, cmd_validate): New.
+
+ * crlcache.c (get_issuer_cert): Make use of the certificate cache.
+ (crl_parse_insert): Validate the issuer certificate.
+
+ * dirmngr.c (handle_signal): Reinitialize the certificate cache on
+ a HUP.
+ (struct opts): Add --homedir to enable the already implemented code.
+ (handle_signal): Print stats on SIGUSR1.
+ * certcache.c (clean_cache_slot, cert_cache_init)
+ (cert_cache_deinit): New.
+ (acquire_cache_read_lock, acquire_cache_write_lock)
+ (release_cache_lock): New. Use them where needed.
+ (put_cert): Renamed from put_loaded_cert.
+ (cache_cert): New.
+ (cert_cache_print_stats): New.
+
2004-11-16 Werner Koch <wk at g10code.com>
* Makefile.am (AM_CPPFLAGS): Define DIRMNGR_SYSCONFDIR and
Index: dirmngr/src/certcache.c
diff -u dirmngr/src/certcache.c:1.1 dirmngr/src/certcache.c:1.2
--- dirmngr/src/certcache.c:1.1 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/certcache.c Thu Nov 18 16:37:48 2004
@@ -24,6 +24,9 @@
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <pth.h>
#include <ksba.h>
@@ -31,6 +34,8 @@
#include "misc.h"
#include "certcache.h"
+#define MAX_EXTRA_CACHED_CERTS 200 /* FIXME: This is a debugging value. */
+
/* A certificate cache item. This consists of a the ksba cert object
and some meta data for easier lookup. We use a hash table to keep
@@ -46,21 +51,58 @@
ksba_sexp_t sn; /* The malloced serial number */
struct
{
- int trusted; /* This is a trusted root certificate. */
-
-
-
-
+ unsigned int loaded:1; /* It has been explicitly loaded. */
+ unsigned int trusted:1; /* This is a trusted root certificate. */
} flags;
};
typedef struct cert_item_s *cert_item_t;
-/* The actual cert cache consisting of 256 slots for items idnex by
+/* The actual cert cache consisting of 256 slots for items indexed by
the first byte of the fingerprint. */
static cert_item_t cert_cache[256];
+/* This is the global cache_lock variable. In general looking is not
+ needed but it would take extra efforts to make sure that no
+ indirect use of pth functions is done, so we simply lock it
+ always. */
+static pth_rwlock_t cert_cache_lock = PTH_RWLOCK_INIT;
+
+/* Flag to track whether the cache has been initialized. */
+static int initialization_done;
+
+/* Total number of certificates loaded during initialization and
+ cached during operation. */
+static unsigned int total_loaded_certificates;
+static unsigned int total_extra_certificates;
+
+/* Helper to do the cahce locking. */
+static void
+acquire_cache_read_lock (void)
+{
+ if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RD, FALSE, NULL))
+ log_fatal (_("can't acquire read lock on the certificate cache: %s\n"),
+ strerror (errno));
+}
+
+static void
+acquire_cache_write_lock (void)
+{
+ if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RW, FALSE, NULL))
+ log_fatal (_("can't acquire write lock on the certificate cache: %s\n"),
+ strerror (errno));
+}
+
+static void
+release_cache_lock (void)
+{
+ if (!pth_rwlock_release (&cert_cache_lock))
+ log_fatal (_("can't release lock on the certificate cache: %s\n"),
+ strerror (errno));
+}
+
+
/* Return false if both serial numbers match. Can't be used for
sorting. */
static int
@@ -120,6 +162,296 @@
}
+/* Cleanup one slot. This releases all resourses but keeps the actual
+ slot in the cache marked for reuse. */
+static void
+clean_cache_slot (cert_item_t ci)
+{
+ ksba_cert_t cert;
+
+ if (!ci->cert)
+ return; /* Already cleaned. */
+
+ ksba_free (ci->sn);
+ ci->sn = NULL;
+ ksba_free (ci->issuer_dn);
+ ci->issuer_dn = NULL;
+ cert = ci->cert;
+ ci->cert = NULL;
+
+ ksba_cert_release (cert);
+}
+
+
+/* Put the certificate CERT into the cache. It is assumed that the
+ cache is locked while this function is called. */
+static gpg_error_t
+put_cert (ksba_cert_t cert, int is_loaded, int is_trusted)
+{
+ unsigned char fpr[20];
+ cert_item_t ci;
+
+ /* If we already reached the caching limit, drop a couple of certs
+ from the cache. Our dropping strategy is simple: We keep a
+ static index counter and use this to start looking for
+ certificates, then we drop 5 percent of the oldest certificates
+ starting at that index. For a large cache this is a fair way of
+ removing items. An LRU strategy would be better of course.
+ Because we append new entries to the head of the list and we want
+ to remove old ones first, we need to do this from the tail. The
+ implementation is not very efficient but compared to the long
+ time it takes to retrieve a certifciate from an external resource
+ it seems to be reasonable. */
+ if (!is_loaded && total_extra_certificates >= MAX_EXTRA_CACHED_CERTS)
+ {
+ static int idx;
+ cert_item_t ci_mark;
+ int i;
+ unsigned int drop_count;
+
+ drop_count = MAX_EXTRA_CACHED_CERTS / 20;
+ if (drop_count < 2)
+ drop_count = 2;
+
+ log_info (_("dropping %u certificates from the cache\n"), drop_count);
+ assert (idx < 256);
+ for (i=idx; drop_count; i = ((i+1)%256))
+ {
+ ci_mark = NULL;
+ for (ci = cert_cache[i]; ci; ci = ci->next)
+ if (ci->cert && !ci->flags.loaded)
+ ci_mark = ci;
+ if (ci_mark)
+ {
+ clean_cache_slot (ci_mark);
+ drop_count--;
+ total_extra_certificates--;
+ }
+ }
+ if (i==idx)
+ idx++;
+ else
+ idx = i;
+ idx %= 256;
+ }
+
+ 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);
+ /* Try to reuse an existing entry. */
+ for (ci=cert_cache[*fpr]; ci; ci = ci->next)
+ if (!ci->cert)
+ break;
+ if (!ci)
+ { /* No: Create a new entry. */
+ ci = xtrycalloc (1, sizeof *ci);
+ if (!ci)
+ return gpg_error_from_errno (errno);
+ ci->next = cert_cache[*fpr];
+ cert_cache[*fpr] = ci;
+ }
+ else
+ memset (&ci->flags, 0, sizeof ci->flags);
+
+ ksba_cert_ref (cert);
+ ci->cert = cert;
+ memcpy (ci->fpr, fpr, 20);
+ ci->sn = ksba_cert_get_serial (cert);
+ ci->issuer_dn = ksba_cert_get_issuer (cert, 0);
+ if (!ci->issuer_dn || !ci->sn)
+ {
+ clean_cache_slot (ci);
+ return gpg_error (GPG_ERR_INV_CERT_OBJ);
+ }
+ ci->flags.loaded = !!is_loaded;
+ ci->flags.trusted = !!is_trusted;
+
+ if (is_loaded)
+ total_loaded_certificates++;
+ else
+ total_extra_certificates++;
+
+ return 0;
+}
+
+
+/* Load certificates from the directory DIRNAME. All certificates
+ matching the pattern "*.crt" are loaded. We assume that
+ certificates are DER encoded and not PEM encapsulated. The cache
+ should be in a locked state when calling this fucntion. */
+static gpg_error_t
+load_certs_from_dir (const char *dirname, int are_trusted)
+{
+ gpg_error_t err;
+ DIR *dir;
+ struct dirent *ep;
+ char *p;
+ size_t n;
+ FILE *fp;
+ ksba_reader_t reader;
+ ksba_cert_t cert;
+ char *fname = NULL;
+
+ dir = opendir (dirname);
+ if (!dir)
+ {
+ log_info (_("can't access directory `%s': %s\n"),
+ dirname, strerror (errno));
+ return 0; /* We do not consider this a severe error. */
+ }
+
+ while ( (ep=readdir (dir)) )
+ {
+ p = ep->d_name;
+ if (*p == '.' || !*p)
+ continue; /* Skip any hidden files and invalid entries. */
+ n = strlen (p);
+ if ( n < 5 || strcmp (p+n-4,".crt") )
+ continue; /* Not the desired "*.crt" pattern. */
+
+ xfree (fname);
+ fname = make_filename (dirname, p, NULL);
+ fp = fopen (fname, "rb");
+ if (!fp)
+ {
+ log_error (_("can't open `%s': %s\n"),
+ fname, strerror (errno));
+ continue;
+ }
+ err = ksba_reader_new (&reader);
+ if (!err)
+ err = ksba_reader_set_file (reader, fp);
+ if (err)
+ {
+ log_error (_("can't setup KSBA reader: %s\n"), gpg_strerror (err));
+ ksba_reader_release (reader);
+ fclose (fp);
+ continue;
+ }
+
+ err = ksba_cert_new (&cert);
+ if (!err)
+ err = ksba_cert_read_der (cert, reader);
+ ksba_reader_release (reader);
+ fclose (fp);
+ if (err)
+ {
+ log_error (_("can't parse certificate `%s': %s\n"),
+ fname, gpg_strerror (err));
+ ksba_cert_release (cert);
+ continue;
+ }
+
+ err = put_cert (cert, 1, are_trusted);
+ ksba_cert_release (cert);
+ if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
+ log_info (_("certificate `%s' already cached\n"), fname);
+ else if (!err)
+ log_info (_("certificate `%s' loaded\n"), fname);
+ else
+ log_error (_("error loading certificate `%s': %s\n"),
+ fname, gpg_strerror (err));
+ }
+
+ xfree (fname);
+ closedir (dir);
+ return 0;
+}
+
+
+/* Initialize the certificate cache if not yet done. */
+void
+cert_cache_init (void)
+{
+ char *dname;
+
+ if (initialization_done)
+ return;
+ acquire_cache_write_lock ();
+
+ dname = make_filename (opt.homedir, "trusted-certs", NULL);
+ load_certs_from_dir (dname, 1);
+ xfree (dname);
+
+ dname = make_filename (opt.homedir, "extra-certs", NULL);
+ load_certs_from_dir (dname, 0);
+ xfree (dname);
+
+ initialization_done = 1;
+ release_cache_lock ();
+
+ cert_cache_print_stats ();
+}
+
+/* Deinitialize the certificate cache. With FULL set to true even the
+ unused certificate slots are released. */
+void
+cert_cache_deinit (int full)
+{
+ cert_item_t ci, ci2;
+ int i;
+
+ if (!initialization_done)
+ return;
+
+ acquire_cache_write_lock ();
+
+ for (i=0; i < 256; i++)
+ for (ci=cert_cache[i]; ci; ci = ci->next)
+ clean_cache_slot (ci);
+
+ if (full)
+ {
+ for (i=0; i < 256; i++)
+ {
+ for (ci=cert_cache[i]; ci; ci = ci2)
+ {
+ ci2 = ci->next;
+ xfree (ci);
+ }
+ cert_cache[i] = NULL;
+ }
+ }
+
+ total_loaded_certificates = 0;
+ total_extra_certificates = 0;
+ initialization_done = 0;
+ release_cache_lock ();
+}
+
+/* Print some statistics to the log file. */
+void
+cert_cache_print_stats (void)
+{
+ log_info (_("permanently loaded certificates: %u\n"),
+ total_loaded_certificates);
+ log_info (_(" runtime cached certificates: %u\n"),
+ total_extra_certificates);
+}
+
+
+/* Put CERT into the certificate cache. */
+gpg_error_t
+cache_cert (ksba_cert_t cert)
+{
+ gpg_error_t err;
+
+ acquire_cache_write_lock ();
+ err = put_cert (cert, 0, 0);
+ release_cache_lock ();
+ if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
+ log_info (_("certificate already cached\n"));
+ else if (!err)
+ log_info (_("certificate cached\n"));
+ else
+ log_error (_("error caching certificate: %s\n"),
+ gpg_strerror (err));
+ return err;
+}
+
+
+
/* Return a certificate object for the given fingerprint. FPR is
expected to be a 20 byte binary SHA-1 fingerprint. If no matching
@@ -132,13 +464,16 @@
{
cert_item_t ci;
+ acquire_cache_read_lock ();
for (ci=cert_cache[*fpr]; ci; ci = ci->next)
if (ci->cert && !memcmp (ci->fpr, fpr, 20))
{
ksba_cert_ref (ci->cert);
+ release_cache_lock ();
return ci->cert;
}
+ release_cache_lock ();
return NULL;
}
@@ -151,6 +486,7 @@
cert_item_t ci;
int i;
+ acquire_cache_read_lock ();
for (i=0; i < 256; i++)
{
for (ci=cert_cache[i]; ci; ci = ci->next)
@@ -158,10 +494,12 @@
&& !compare_serialno (ci->sn, serialno))
{
ksba_cert_ref (ci->cert);
+ release_cache_lock ();
return ci->cert;
}
}
+ release_cache_lock ();
return NULL;
}
@@ -175,6 +513,7 @@
cert_item_t ci;
int i;
+ acquire_cache_read_lock ();
for (i=0; i < 256; i++)
{
for (ci=cert_cache[i]; ci; ci = ci->next)
@@ -182,10 +521,12 @@
if (!seq--)
{
ksba_cert_ref (ci->cert);
+ release_cache_lock ();
return ci->cert;
}
}
+ release_cache_lock ();
return NULL;
}
@@ -219,18 +560,23 @@
compute_fpr (cert, fpr);
+ acquire_cache_read_lock ();
for (ci=cert_cache[*fpr]; ci; ci = ci->next)
if (ci->cert && !memcmp (ci->fpr, fpr, 20))
{
if (ci->flags.trusted)
- return 0; /* Yes it is trusted. */
+ {
+ release_cache_lock ();
+ return 0; /* Yes, it is trusted. */
+ }
break;
}
+ release_cache_lock ();
return gpg_error (GPG_ERR_NOT_TRUSTED);
}
-
+
/* Given the certificate CERT locate the issuer for this certificate
and return it at R_CERT. Returns 0 on success or
GPG_ERR_NOT_FOUND. */
Index: dirmngr/src/certcache.h
diff -u dirmngr/src/certcache.h:1.1 dirmngr/src/certcache.h:1.2
--- dirmngr/src/certcache.h:1.1 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/certcache.h Thu Nov 18 16:37:48 2004
@@ -21,6 +21,18 @@
#ifndef CERTCACHE_H
#define CERTCACHE_H
+/* First time initialization of the certificate cache. */
+void cert_cache_init (void);
+
+/* Deinitialize the certificate cache. */
+void cert_cache_deinit (int full);
+
+/* Print some statistics to the log file. */
+void cert_cache_print_stats (void);
+
+
+/* Put CERT into the certificate cache. */
+gpg_error_t cache_cert (ksba_cert_t cert);
/* Return 0 if the certificate is a trusted certificate. Returns
GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
@@ -35,6 +47,11 @@
ksba_cert_t get_cert_byfpr (const unsigned char *fpr);
+/* Return the certificate matching ISSUER_DN. SEQ should initially be
+ set to 0 and bumped up to get the next issuer with that DN. */
+ksba_cert_t get_cert_byissuer (const char *issuer_dn, unsigned int seq);
+
+
/* Given the certificate CERT locate the issuer for this certificate
and return it at R_CERT. Returns 0 on success or
GPG_ERR_NOT_FOUND. */
Index: dirmngr/src/crlcache.c
diff -u dirmngr/src/crlcache.c:1.46 dirmngr/src/crlcache.c:1.47
--- dirmngr/src/crlcache.c:1.46 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/crlcache.c Thu Nov 18 16:37:48 2004
@@ -97,6 +97,8 @@
#include <sys/utsname.h>
#include "dirmngr.h"
+#include "validate.h"
+#include "certcache.h"
#include "crlcache.h"
#include "crlfetch.h"
#include "misc.h"
@@ -1263,6 +1265,11 @@
ksba_cert_t issuer_cert = NULL;
ksba_reader_t reader;
+ /* First check whether it has already been cached. */
+ issuer_cert = get_cert_byissuer (issuer, 0);
+ if (issuer_cert)
+ return issuer_cert; /* Done. */
+
/* Ask back to the service requester to return the certificate.
This is because we can assume that he already used the
certificate while checking for the CRL. */
@@ -1297,6 +1304,9 @@
log_error (_("invalid issuer certificate: %s\n"), gpg_strerror (err) );
ksba_reader_release (reader);
+ if (!err)
+ cache_cert (issuer_cert);
+
return issuer_cert;
}
@@ -1543,6 +1553,14 @@
gpg_strerror (err));
goto failure;
}
+ err = validate_cert_chain (issuer_cert, NULL);
+ if (err)
+ {
+ log_error (_("error checking validity of CRL "
+ "signing certificate: %s\n"),
+ gpg_strerror (err));
+ goto failure;
+ }
}
break;
Index: dirmngr/src/dirmngr-client.c
diff -u dirmngr/src/dirmngr-client.c:1.1 dirmngr/src/dirmngr-client.c:1.2
--- dirmngr/src/dirmngr-client.c:1.1 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/dirmngr-client.c Thu Nov 18 16:37:48 2004
@@ -52,6 +52,8 @@
oOCSP = 500,
oPing,
+ oCacheCert,
+ oValidate,
oUseDaemon,
oDummy
};
@@ -61,9 +63,11 @@
static ARGPARSE_OPTS opts[] = {
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
+ { oUseDaemon,"use-daemon",0, N_("force use of the daemon")},
{ oOCSP, "ocsp", 0, N_("use OCSP instead of CRLs") },
{ oPing, "ping", 0, N_("check whether a dirmngr is running")},
- { oUseDaemon,"use-daemon",0, N_("force use of the daemon")},
+ { oCacheCert,"cache-cert",0, N_("add a certificate to the cache")},
+ { oValidate, "validate", 0, N_("validate a certificate")},
{0}
};
@@ -97,6 +101,10 @@
unsigned char **rbuf, size_t *rbuflen);
static gpg_error_t do_check (assuan_context_t ctx,
const unsigned char *cert, size_t certlen);
+static gpg_error_t do_cache (assuan_context_t ctx,
+ const unsigned char *cert, size_t certlen);
+static gpg_error_t do_validate (assuan_context_t ctx,
+ const unsigned char *cert, size_t certlen);
@@ -156,9 +164,11 @@
gpg_error_t err;
unsigned char *certbuf;
size_t certbuflen;
- int do_ping = 0;
+ int cmd_ping = 0;
int use_daemon = 0;
-
+ int cmd_cache_cert = 0;
+ int cmd_validate = 0;
+
set_strusage (my_strusage);
log_set_prefix ("dirmngr-client",
JNLIB_LOG_WITH_PREFIX);
@@ -180,9 +190,12 @@
{
case oVerbose: opt.verbose++; break;
case oQuiet: opt.quiet++; break;
- case oOCSP: opt.use_ocsp++; break;
- case oPing: do_ping = 1; break;
case oUseDaemon: use_daemon = 1; break;
+
+ case oOCSP: opt.use_ocsp++; break;
+ case oPing: cmd_ping = 1; break;
+ case oCacheCert: cmd_cache_cert = 1; break;
+ case oValidate: cmd_validate = 1; break;
default : pargs.err = 2; break;
}
@@ -190,7 +203,7 @@
if (log_get_errorcount (0))
exit (2);
- if (do_ping)
+ if (cmd_ping)
err = 0;
else if (!argc)
{
@@ -221,11 +234,23 @@
exit (2);
}
- ctx = start_dirmngr (do_ping || use_daemon);
+ ctx = start_dirmngr (cmd_ping || use_daemon);
if (!ctx)
exit (2);
- if (!do_ping)
+ if (cmd_ping)
+ ;
+ else if (cmd_cache_cert)
+ {
+ err = do_cache (ctx, certbuf, certbuflen);
+ xfree (certbuf);
+ }
+ else if (cmd_validate)
+ {
+ err = do_validate (ctx, certbuf, certbuflen);
+ xfree (certbuf);
+ }
+ else
{
err = do_check (ctx, certbuf, certbuflen);
xfree (certbuf);
@@ -233,12 +258,33 @@
assuan_disconnect (ctx);
- if (do_ping)
+ if (cmd_ping)
{
if (!opt.quiet)
log_info (_("a dirmngr daemon is up and running\n"));
return 0;
}
+ else if (cmd_cache_cert)
+ {
+ if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
+ {
+ if (!opt.quiet)
+ log_info (_("certificate already cached\n"));
+ }
+ else if (err)
+ {
+ log_error (_("error caching certificate: %s\n"),
+ gpg_strerror (err));
+ return 1;
+ }
+ return 0;
+ }
+ else if (cmd_validate && err)
+ {
+ log_error (_("validation of certificate failed: %s\n"),
+ gpg_strerror (err));
+ return 1;
+ }
else if (!err)
{
if (!opt.quiet)
@@ -472,3 +518,45 @@
log_info ("response of dirmngr: %s\n", ae? assuan_strerror (ae): "okay");
return map_assuan_err (ae);
}
+
+/* Check the certificate CERT,CERTLEN for validity using a CRL or OCSP.
+ Return a proper error code. */
+static gpg_error_t
+do_cache (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
+{
+ assuan_error_t ae;
+ struct inq_cert_parm_s parm;
+
+ memset (&parm, 0, sizeof parm);
+ parm.ctx = ctx;
+ parm.cert = cert;
+ parm.certlen = certlen;
+
+ ae = assuan_transact (ctx, "CACHECERT", NULL, NULL,
+ inq_cert, &parm,
+ NULL, NULL);
+ if (opt.verbose > 1)
+ log_info ("response of dirmngr: %s\n", ae? assuan_strerror (ae): "okay");
+ return map_assuan_err (ae);
+}
+
+/* Check the certificate CERT,CERTLEN for validity using dirmngrs
+ internal validate feature. Return a proper error code. */
+static gpg_error_t
+do_validate (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
+{
+ assuan_error_t ae;
+ struct inq_cert_parm_s parm;
+
+ memset (&parm, 0, sizeof parm);
+ parm.ctx = ctx;
+ parm.cert = cert;
+ parm.certlen = certlen;
+
+ ae = assuan_transact (ctx, "VALIDATE", NULL, NULL,
+ inq_cert, &parm,
+ NULL, NULL);
+ if (opt.verbose > 1)
+ log_info ("response of dirmngr: %s\n", ae? assuan_strerror (ae): "okay");
+ return map_assuan_err (ae);
+}
Index: dirmngr/src/dirmngr.c
diff -u dirmngr/src/dirmngr.c:1.41 dirmngr/src/dirmngr.c:1.42
--- dirmngr/src/dirmngr.c:1.41 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/dirmngr.c Thu Nov 18 16:37:48 2004
@@ -43,6 +43,7 @@
#define JNLIB_NEED_LOG_LOGV
#include "dirmngr.h"
+#include "certcache.h"
#include "crlcache.h"
#include "crlfetch.h"
#include "misc.h"
@@ -137,6 +138,7 @@
{ oDebugAll, "debug-all" ,0, "@"},
{ oDebugWait, "debug-wait", 1, "@"},
{ oNoGreeting, "no-greeting", 0, "@"},
+ { oHomedir, "homedir", 2, "@" },
{0}
};
@@ -679,6 +681,7 @@
}
launch_ripper_thread ();
+ cert_cache_init ();
crl_cache_init ();
start_command_handler (-1);
}
@@ -830,6 +833,7 @@
launch_ripper_thread ();
+ cert_cache_init ();
crl_cache_init ();
handle_connections (fd);
close (fd);
@@ -846,6 +850,7 @@
else if (cmd == aLoadCRL)
{
launch_ripper_thread ();
+ cert_cache_init ();
crl_cache_init ();
if (!argc)
rc = crl_cache_load (NULL, NULL);
@@ -863,6 +868,7 @@
wrong_args ("--fetch-crl URL");
launch_ripper_thread ();
+ cert_cache_init ();
crl_cache_init ();
rc = crl_fetch (argv[0], &reader);
if (rc)
@@ -947,6 +953,7 @@
cleanup (void)
{
crl_cache_deinit ();
+ cert_cache_deinit (1);
free_ldapservers_list (opt.ldapservers);
opt.ldapservers = NULL;
@@ -1140,10 +1147,14 @@
log_info (_("SIGHUP received - "
"re-reading configuration and flushing caches\n"));
/* reread_configuration (); */
+ cert_cache_deinit (0);
+ crl_cache_deinit ();
+ cert_cache_init ();
+ crl_cache_init ();
break;
case SIGUSR1:
- log_info (_("SIGUSR1 received - no action defined\n"));
+ cert_cache_print_stats ();
break;
case SIGUSR2:
Index: dirmngr/src/dirmngr_ldap.c
diff -u dirmngr/src/dirmngr_ldap.c:1.1 dirmngr/src/dirmngr_ldap.c:1.2
--- dirmngr/src/dirmngr_ldap.c:1.1 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/dirmngr_ldap.c Thu Nov 18 16:37:48 2004
@@ -209,8 +209,6 @@
if (opt.port < 0 || opt.port > 65535)
log_error (_("invalid port number %d\n"), opt.port);
- sleep (5);
-
if (log_get_errorcount (0))
exit (2);
Index: dirmngr/src/ldap.c
diff -u dirmngr/src/ldap.c:1.33 dirmngr/src/ldap.c:1.34
--- dirmngr/src/ldap.c:1.33 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/ldap.c Thu Nov 18 16:37:48 2004
@@ -472,8 +472,8 @@
return err;
}
- pid = fork ();
- if (pid == -1)
+ pid = pth_fork ();
+ if (pid == (pid_t)(-1))
{
err = gpg_error_from_errno (errno);
log_error (_("error forking process: %s\n"), strerror (errno));
@@ -510,13 +510,6 @@
else
arg_list[j] = (char*)argv[i];
- /* Connect stderr to the second pipe. */
- if (rp2[1] != STDERR_FILENO && dup2 (rp2[1], STDERR_FILENO) == -1)
- {
- log_error (_("dup2 failed in child: %s\n"), strerror (errno));
- _exit (4);
- }
-
/* Connect stdin to /dev/null. */
fd = open ("/dev/null", O_RDONLY);
if (fd == -1)
@@ -536,6 +529,14 @@
log_error (_("dup2 failed in child: %s\n"), strerror (errno));
_exit (4);
}
+
+ /* Connect stderr to the second pipe. */
+ if (rp2[1] != STDERR_FILENO && dup2 (rp2[1], STDERR_FILENO) == -1)
+ {
+ log_error (_("dup2 failed in child: %s\n"), strerror (errno));
+ _exit (4);
+ }
+
/* Close all files which will not be duped. */
n = sysconf (_SC_OPEN_MAX);
@@ -557,7 +558,7 @@
/* Parent. */
close (rp[1]);
close (rp2[1]);
-
+
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
{
Index: dirmngr/src/server.c
diff -u dirmngr/src/server.c:1.43 dirmngr/src/server.c:1.44
--- dirmngr/src/server.c:1.43 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/server.c Thu Nov 18 16:37:48 2004
@@ -38,6 +38,7 @@
#include "dirmngr.h"
#include "ocsp.h"
#include "certcache.h"
+#include "validate.h"
/* To avoid DoS attacks we limit the size of a certificate to
something reasonable. */
@@ -905,6 +906,113 @@
}
+/* CACHECERT
+
+ Put a certificate into the internal cache. This command might be
+ usedful if a client knows in advance certificates required for a
+ test and wnats to make sure they get added to the internal cache.
+ It is also helpful for debugging. To get the actual certificate,
+ this command immediately inquires it using
+
+ INQUIRE TARGETCERT
+
+ and the caller is expected to return the certificate for the
+ request as a binary blob.
+*/
+static int
+cmd_cachecert (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ ksba_cert_t cert = NULL;
+ assuan_error_t ae;
+ unsigned char *value = NULL;
+ size_t valuelen;
+
+ ae = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
+ &value, &valuelen, MAX_CERT_LENGTH);
+ if (ae)
+ {
+ log_error (_("assuan_inquire failed: %s\n"), assuan_strerror (ae));
+ err = map_assuan_err (ae);
+ goto leave;
+ }
+
+ if (!valuelen) /* No data returned; return a comprehensible error. */
+ err = gpg_error (GPG_ERR_MISSING_CERT);
+ else
+ {
+ err = ksba_cert_new (&cert);
+ if (!err)
+ err = ksba_cert_init_from_mem (cert, value, valuelen);
+ }
+ xfree (value);
+ if(err)
+ goto leave;
+
+ err = cache_cert (cert);
+
+ leave:
+ if (err)
+ log_error (_("command %s failed: %s\n"), "CACHECERT", gpg_strerror (err));
+ ksba_cert_release (cert);
+ return map_to_assuan_status (err);
+}
+
+
+/* VALIDATE
+
+ Validate a certificate using the certificate validationj fucntion
+ used internally by dirmngr. This command is only useful for
+ debugging. To get the actual certificate, this command immediately
+ inquires it using
+
+ INQUIRE TARGETCERT
+
+ and the caller is expected to return the certificate for the
+ request as a binary blob.
+*/
+static int
+cmd_validate (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ ksba_cert_t cert = NULL;
+ assuan_error_t ae;
+ unsigned char *value = NULL;
+ size_t valuelen;
+
+ ae = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
+ &value, &valuelen, MAX_CERT_LENGTH);
+ if (ae)
+ {
+ log_error (_("assuan_inquire failed: %s\n"), assuan_strerror (ae));
+ err = map_assuan_err (ae);
+ goto leave;
+ }
+
+ if (!valuelen) /* No data returned; return a comprehensible error. */
+ err = gpg_error (GPG_ERR_MISSING_CERT);
+ else
+ {
+ err = ksba_cert_new (&cert);
+ if (!err)
+ err = ksba_cert_init_from_mem (cert, value, valuelen);
+ }
+ xfree (value);
+ if(err)
+ goto leave;
+
+ err = validate_cert_chain (cert, NULL);
+
+ leave:
+ if (err)
+ log_error (_("command %s failed: %s\n"), "VALIDATE", gpg_strerror (err));
+ ksba_cert_release (cert);
+ return map_to_assuan_status (err);
+}
+
+
/* Tell the assuan library about our commands. */
static int
@@ -920,6 +1028,8 @@
{ "LOOKUP", cmd_lookup },
{ "LOADCRL", cmd_loadcrl },
{ "LISTCRLS", cmd_listcrls },
+ { "CACHECERT", cmd_cachecert },
+ { "VALIDATE", cmd_validate },
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ NULL }
Index: dirmngr/src/validate.c
diff -u dirmngr/src/validate.c:1.1 dirmngr/src/validate.c:1.2
--- dirmngr/src/validate.c:1.1 Tue Nov 16 19:24:35 2004
+++ dirmngr/src/validate.c Thu Nov 18 16:37:48 2004
@@ -169,6 +169,8 @@
/* 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. */
gpg_error_t
validate_cert_chain (ksba_cert_t cert, ksba_isotime_t r_exptime)
{
@@ -320,7 +322,7 @@
break; /* Okay: a self-signed certicate is an end-point. */
}
- /* To avoid loops, we use an arbitary limit on tghe length of
+ /* To avoid loops, we use an arbitary limit on the length of
the chain. */
depth++;
if (depth > maxdepth)
@@ -357,8 +359,8 @@
dump_cert ("issuer", issuer_cert);
}
- /* Now check the signature of the certificate. Well, not
- really: We delay this until later so that fakedcertificates
+ /* Now check the signature of the certificate. Well, we
+ shouldnot delay this until later so that faked certificates
can't be turned into a DoS easily. */
err = check_cert_sig (issuer_cert, subject_cert);
if (err)
More information about the Gnupg-commits
mailing list