[svn] dirmngr - r260 - in trunk: . doc jnlib src

svn author wk cvs at cvs.gnupg.org
Thu Aug 9 17:51:45 CEST 2007


Author: wk
Date: 2007-08-09 17:51:16 +0200 (Thu, 09 Aug 2007)
New Revision: 260

Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/doc/dirmngr.texi
   trunk/jnlib/ChangeLog
   trunk/jnlib/argparse.c
   trunk/jnlib/stringhelp.c
   trunk/src/ChangeLog
   trunk/src/crlfetch.c
   trunk/src/dirmngr-client.c
   trunk/src/dirmngr.c
   trunk/src/dirmngr.h
   trunk/src/estream-printf.c
   trunk/src/estream.h
   trunk/src/ocsp.c
   trunk/src/ocsp.h
   trunk/src/server.c
Log:
Fixed OCSP stuff
New OCSP features.
General cleanup.


Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/ChangeLog	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,3 +1,9 @@
+2007-08-09  Werner Koch  <wk at g10code.com>
+
+	* doc/dirmngr.texi (Dirmngr Options): Describe the new format of
+	--ocsp-signer.
+	(Dirmngr ISVALID): Rework.
+
 2007-08-07  Werner Koch  <wk at g10code.com>
 
 	* configure.ac (COPYRIGHT_YEAR_NAME): Set to 2007.

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/NEWS	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,7 +1,16 @@
 Noteworthy changes in version 1.0.1
 ------------------------------------------------
 
+ * The option --ocsp-signer may now take a filename to allow several
+   certificates to be valid signers for the default responder.
 
+ * New option --ocsp-max-period and improved the OCSP time checks.
+
+ * New option --force-default-signer for dirmngr-client.
+
+ * Ported to Windows.
+
+
 Noteworthy changes in version 1.0.0 (2006-11-29)
 ------------------------------------------------
 

Modified: trunk/doc/dirmngr.texi
===================================================================
--- trunk/doc/dirmngr.texi	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/doc/dirmngr.texi	2007-08-09 15:51:16 UTC (rev 260)
@@ -32,7 +32,7 @@
 
 Copyright @copyright{} 2002 Klarälvdalens Datakonsult AB
 
-Copyright @copyright{} 2004, 2005, 2006 g10 Code GmbH
+Copyright @copyright{} 2004, 2005, 2006, 2007 g10 Code GmbH
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -134,7 +134,7 @@
 Dirmngr is a server for managing and downloading certificate revocation
 lists (CRLs) for X.509 certificates and for downloading the certificates
 themselves. Dirmngr also handles OCSP requests as an alternative to
-CRLs. Dirmngr is either invoked internally by gpgsm (from gnupg 1.9) or
+CRLs. Dirmngr is either invoked internally by gpgsm (from GnuPG 2) or
 when running as a system daemon through the @command{dirmngr-client} tool.
 
 @manpause
@@ -146,7 +146,7 @@
 Installation is decribed in the file @file{INSTALL} and given that you
 are already reading this documentation we can only give some hints on
 further configuration.  If you plan to use dirmngr as a system daemon
-and not only as a part of gnupg 1.9, you should read on.
+and not only as a part of GnuPG 2, you should read on.
 
 If @command{dirmngr} is started in system daemon mode, it uses a
 directory layout as common for system daemon and does not make use of
@@ -421,6 +421,11 @@
 the @acronym{LDAP} scheme.  Both options may be combined resulting in 
 ignoring DPs entirely.
 
+ at item --ignore-ocsp-service-url
+ at opindex ignore-ocsp-service-url
+Ignore all OCSP URLs contained in the certificate.  The effect is to 
+force the use of the default responder.
+
 @item --honor-http-proxy
 @opindex honor-http-proxy
 If the environment variable @env{http_proxy} has been set, use its
@@ -507,24 +512,42 @@
 not contain information about an assigned responder.  Note, that
 @code{--ocsp-signer} must also be set to a valid certificate.
 
- at item --ocsp-signer @var{fpr}
+ at item --ocsp-signer @var{fpr}|@var{file}
 @opindex ocsp-signer
 Use the certificate with the fingerprint @var{fpr} to check the
-responses of the default OCSP Responder. Dirmngr will retrieve this
-certificate from the current client.  
+responses of the default OCSP Responder.  Alternativly a filename can be
+given in which case the respinse is expected to be signed by one of the
+certificates described in that file.  Any argument which contains a
+slash, dot or tilde is considered a filename.  Usual filename expansion
+takes place: A tilde at the start followed by a slash is replaced by the
+content of @env{HOME}, no slash at start describes a relative filename
+which will be searched at the home directory.  To make sure that the
+ at var{file} is searched in the home directory, either prepend the name
+with "./" or use a name which contains a dot.
 
-If a response has been signed by this certificate no further check upon
-the validity of this certificate is done!
+If a response has been signed by a certificate described by these
+fingerprints no further check upon the validity of this certificate is
+done.
 
+The format of the @var{FILE} is a list of SHA-1 fingerprint, one per
+line with optional colons between the bytes.  Empty lines and lines
+prefix with a hash mark are ignored.
+
+
 @item --ocsp-max-clock-skew @var{n}
 @opindex ocsp-max-clock-skew
-The number of seconds a skew between the OCSP respinder and them local
+The number of seconds a skew between the OCSP responder and them local
 clock is accepted.  Default is 600 (20 minutes).
 
+ at item --ocsp-max-period @var{n}
+ at opindex ocsp-max-period
+Seconds a response is at maximum considered valid after the time given
+in the thisUpdate field.  Default is 7776000 (90 days).
+
 @item --ocsp-current-period @var{n}
 @opindex ocsp-current-period
-The number of seconds an OCSP reponse is valid after the time given in
-the NEXT_UPDATE datum.  Default is 10800 (3 hours).
+The number of seconds an OCSP response is considered valid after the
+time given in the NEXT_UPDATE datum.  Default is 10800 (3 hours).
 
 
 @item --max-replies @var{n}
@@ -584,15 +607,18 @@
 
 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
 @end example
 
 If a dirmngr is supposed to be used as a system wide daemon, it should
 be started like:
+
 @example 
   dirmngr --daemon
 @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
@@ -657,44 +683,66 @@
 @node Dirmngr ISVALID
 @section Validate a certificate using a CRL or OCSP
 
-Check whether the certificate described by the certificate_ID (which
-is a fingerprint) has been revoked. Due to caching, the Dirmngr is
-able to answer immediately in most cases:
+ at example
+  ISVALID [--only-ocsp] [--force-default-responder] @var{certid}|@var{certfpr}
+ at end example
 
-  @code{S: OK}
+Check whether the certificate described by the @var{certid} has been
+revoked.  Due to caching, the Dirmngr is able to answer immediately in
+most cases.  
 
-Yes, the certificate is not revoked and we have a up-to-date
-revocation list for that certificate.
+The @var{certid} is a hex encoded string consisting of two parts,
+delimited by a single dot.  The first part is the SHA-1 hash of the
+issuer name and the second part the serial number.
 
-  @code{S: E 301 certificate has been revoked}
+Alternatively the certificate's SHA-1 fingerprint @var{certfpr} may be
+given in which case an OCSP request is done before consulting the CRL.
+If the option @option{--only-ocsp} is given, no fallback to a CRL check
+will be used.  If the option @option{--force-default-responder} is
+given, only the default OCSP responder will be used and any other
+methods of obtaining an OCSP responder URL won't be used.
 
-The client may then issue another command to retrieve information on
-the revocation reason.
+ at noindent
+Common return values are:
 
-  @code{S: E 302 no CRL known for this certificate}
+ at table @code
+ at item GPG_ERR_NO_ERROR (0)
+This is the positive answer: The certificate is not revoked and we have
+an up-to-date revocation list for that certificate.  If OCSP was used
+the responder confirmed that the certificate has not been revoked.
 
-  @code{S: E 303 CRL is too old and a new one could not be retrieved}
+ at item GPG_ERR_CERT_REVOKED
+This is the negative answer: The certificate has been revoked.  Either
+it is in a CRL and that list is up to date or an OCSP responder informed
+us that it has been revoked.
 
-If the DirMngr has not enough information about the given
-certificate which is the case for not yet cached certificates
-because the clients only passes the CertID, the DirMngr will will
-inquire the missing data:
+ at item GPG_ERR_NO_CRL_KNOWN
+No CRL is known for this certificate or the CRL is not valid or out of
+date. 
 
+ at item GPG_ERR_NO_DATA
+The OCSP responder returned an ``unknown'' status.  This means that it
+is not aware of the certificate's status.
+
+ at item GPG_ERR_NOT_SUPPORTED
+This is commonly seen if OCSP support has not been enabled in the
+configuration.
+ at end table
+
+If DirMngr has not enough information about the given certificate (which
+is the case for not yet cached certificates), it will will inquire the
+missing data:
+
 @example
   S: INQUIRE SENDCERT <CertID>
   C: D <DER encoded certificate>
   C: END
 @end example
 
-A client should be aware the the DirMngr may ask for more than one Certificate.
+A client should be aware that DirMngr may ask for more than one
+certificate.
 
-If the option @code{--allow-ocsp} is enabled, this command may
-alternativly run an OCSP request.  The client requests this by simply
-using the fingerrpint instead of the certificate-id.  There is no fall
-back to CRL checking if the OCSP requests could not be done for
-whatever reason.
 
-
 @node Dirmngr CHECKCRL
 @section Validate a certificate using a CRL
 
@@ -724,25 +772,34 @@
 @node Dirmngr CHECKOCSP
 @section Validate a certificate using OCSP
 
-   Check whether the certificate with FINGERPRINT (SHA-1 hash of the
-   entire X.509 certificate blob) is valid or not by consulting the
-   appropiateOCSP responder.  If the fingerprint has not
-   been given or the certificate is not know, the function 
-   inquires the certificate using:
+ at example
+  CHECKOCSP [--force-default-responder] [@var{fingerprint}]
+ at end example
 
+Check whether the certificate with @var{fingerprint} (the SHA-1 hash of
+the entire X.509 certificate blob) is valid by consulting the appropiate
+OCSP responder.  If the fingerprint has not been given or the
+certificate is not known by Dirmngr, the function inquires the
+certificate using:
+
 @example
   S: INQUIRE TARGETCERT 
   C: D <DER encoded certificate>
   C: END
 @end example
 
-   Thus the caller is expected to return the certificate for the
-   request (which should match FINGERPRINT) as a binary blob.
-   Processing then takes place without further interaction; in
-   particular dirmngr tries to locate other required certificate by
-   its own mechanism which includes a local certificate store as well
-   as a list of trusted root certificates.
+Thus the caller is expected to return the certificate for the request
+(which should match @var{fingerprint}) as a binary blob.  Processing
+then takes place without further interaction; in particular dirmngr
+tries to locate other required certificates by its own mechanism which
+includes a local certificate store as well as a list of trusted root
+certificates.
 
+If the option @option{--force-default-responder} is given, only the
+default OCSP responder is used.  This option is the per-command variant
+of the global option @option{--ignore-ocsp-service-url}.
+
+
 @noindent
 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.
@@ -889,8 +946,13 @@
 
 @item --ocsp
 @opindex ocsp
-Do the check using the COSP protocol and ignore any CRLs.
+Do the check using the OCSP protocol and ignore any CRLs.
 
+ at item --force-default-responder
+ at opindex force-default-responder
+When checking using the OCSP protocl, force the use of the default OCSP
+responder.  That is not to use the Reponder as given by the certificate.
+
 @item --ping
 @opindex ping
 Check whether the dirmngr daemon is up and running.
@@ -908,7 +970,7 @@
 @item --load-crl
 @opindex load-crl
 This command expects a list of filenames with DER encoded CRL files.
-All CRL will be vfalidated and then loaded into dirmngr's cache.
+All CRL will be validated and then loaded into dirmngr's cache.
 
 @item --lookup
 @opindex lookup

Modified: trunk/jnlib/ChangeLog
===================================================================
--- trunk/jnlib/ChangeLog	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/jnlib/ChangeLog	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,3 +1,8 @@
+2007-08-09  Werner Koch  <wk at g10code.com>
+
+	* argparse.c (show_help): Expand the @EMAIL@ macro in the package
+	bug reporting address.
+
 2006-11-29  Werner Koch  <wk at g10code.com>
 
 	* argparse.c (strusage): Define 49 as error reporting address.

Modified: trunk/jnlib/argparse.c
===================================================================
--- trunk/jnlib/argparse.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/jnlib/argparse.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -834,8 +834,21 @@
 	    puts("\n(A single dash may be used instead of the double ones)");
     }
     if( (s=strusage(19)) ) {  /* bug reports to ... */
+        char *s2;
+
 	putchar('\n');
-	fputs(s, stdout);
+        s2 = strstr (s, "@EMAIL@");
+        if (s2)
+          {
+            if (s2-s)
+              fwrite (s, s2-s, 1, stdout);
+            fputs (PACKAGE_BUGREPORT, stdout);
+            s2 += 7;
+            if (*s2)
+              fputs (s2, stdout);
+          }
+        else
+          fputs(s, stdout);
     }
     fflush(stdout);
     exit(0);

Modified: trunk/jnlib/stringhelp.c
===================================================================
--- trunk/jnlib/stringhelp.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/jnlib/stringhelp.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -273,10 +273,10 @@
     char *p;
 
     if ( !(p=strrchr(filepath, '/')) )
-      #ifdef HAVE_DRIVE_LETTERS
+#ifdef HAVE_DRIVE_LETTERS
 	if ( !(p=strrchr(filepath, '\\')) )
 	    if ( !(p=strrchr(filepath, ':')) )
-      #endif
+#endif
 	      {
 		return jnlib_xstrdup(".");
 	      }

Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/ChangeLog	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,3 +1,29 @@
+2007-08-09  Werner Koch  <wk at g10code.com>
+
+	* dirmngr.c (parse_ocsp_signer): New.
+	(parse_rereadable_options): Set opt.ocsp_signer to this.
+	* dirmngr.h (fingerprint_list_t): New.
+	* ocsp.c (ocsp_isvalid, check_signature, validate_responder_cert):
+	Allow for several default ocscp signers.
+	(ocsp_isvalid): Return GPG_ERR_NO_DATA for an unknwon status.
+
+	* dirmngr-client.c: New option --force-default-responder.
+
+	* server.c (has_option, skip_options): New.
+	(cmd_checkocsp): Add option --force-default-responder.
+	(cmd_isvalid): Ditto.  Also add option --only-ocsp.
+
+	* ocsp.c (ocsp_isvalid): New arg FORCE_DEFAULT_RESPONDER.
+
+	* dirmngr.c: New option --ocsp-max-period.
+	* ocsp.c (ocsp_isvalid): Implement it and take care that a missing
+	next_update is to be ignored.
+
+	* crlfetch.c (my_es_read): New.  Use it instead of es_read.
+
+	* estream.h, estream.c, estream-printf.c: Updated from current
+	libestream SVN.
+
 2007-08-08  Werner Koch  <wk at g10code.com>
 
 	* crlcache.c (crl_parse_insert): Hack to allow for a missing

Modified: trunk/src/crlfetch.c
===================================================================
--- trunk/src/crlfetch.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/crlfetch.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <config.h>
@@ -83,6 +84,14 @@
 }
 
 
+
+static int 
+my_es_read (void *opaque, char *buffer, size_t nbytes, size_t *nread)
+{
+  return es_read (opaque, buffer, nbytes, nread);
+}
+           
+
 /* Fetch CRL from URL and return the entire CRL using new ksba reader
    object in READER.  Note that this reader object should be closed
    only using ldap_close_reader. */
@@ -143,7 +152,7 @@
             
             err = ksba_reader_new (reader);
             if (!err)
-	      err = ksba_reader_set_cb (*reader, &es_read, fp);
+	      err = ksba_reader_set_cb (*reader, &my_es_read, fp);
             if (err)
               {
                 log_error (_("error initializing reader object: %s\n"),

Modified: trunk/src/dirmngr-client.c
===================================================================
--- trunk/src/dirmngr-client.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/dirmngr-client.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,5 +1,5 @@
 /* dirmngr-client.c  -  A client for the dirmngr daemon
- *	Copyright (C) 2004 g10 Code GmbH
+ *	Copyright (C) 2004, 2007 g10 Code GmbH
  *	Copyright (C) 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of DirMngr.
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -59,6 +60,7 @@
     oSquidMode,
     oPEM,
     oEscapedPEM,
+    oForceDefaultResponder
   };
 
 
@@ -74,6 +76,8 @@
   { oLoadCRL,  "load-crl",  0, N_("load a CRL into the dirmngr")},
   { oSquidMode,"squid-mode",0, N_("special mode for use by Squid")},
   { oPEM,      "pem",       0, N_("certificates are expected in PEM format")},
+  { oForceDefaultResponder, "force-default-responder", 0,
+    N_("force the use of the default OCSP responder")},
   { 0 }
 };
  
@@ -86,11 +90,12 @@
   int verbose;
   const char *dirmngr_program;
   int force_pipe_server;
+  int force_default_responder;
   int pem;
   int escaped_pem; /* PEM is additional percent encoded.  */
 
   int use_ocsp;
-
+  
 } opt;
 
 
@@ -224,6 +229,7 @@
           opt.escaped_pem = 1;
           cmd_squid_mode = 1;
           break;
+        case oForceDefaultResponder: opt.force_default_responder = 1; break;
 
         default : pargs.err = 2; break;
 	}
@@ -801,9 +807,11 @@
   parm.cert = cert;
   parm.certlen = certlen;
 
-  err = assuan_transact (ctx, opt.use_ocsp? "CHECKOCSP":"CHECKCRL", NULL, NULL,
-                        inq_cert, &parm,
-                        status_cb, NULL);
+  err = assuan_transact (ctx, 
+                         (opt.use_ocsp && opt.force_default_responder
+                          ? "CHECKOCSP --force-default-responder" 
+                          : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"), 
+                         NULL, NULL, inq_cert, &parm, status_cb, NULL);
   if (opt.verbose > 1)
     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
   return err;

Modified: trunk/src/dirmngr.c
===================================================================
--- trunk/src/dirmngr.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/dirmngr.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -16,7 +16,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <config.h>
@@ -101,6 +102,7 @@
   oOCSPResponder,
   oOCSPSigner,
   oOCSPMaxClockSkew,
+  oOCSPMaxPeriod,
   oOCSPCurrentPeriod,
   oMaxReplies,
   oFakedSystemTime,
@@ -173,6 +175,7 @@
   { oOCSPResponder, "ocsp-responder", 2, N_("|URL|use OCSP responder at URL")},
   { oOCSPSigner, "ocsp-signer", 2, N_("|FPR|OCSP response signed by FPR")}, 
   { oOCSPMaxClockSkew, "ocsp-max-clock-skew", 1, "@" },
+  { oOCSPMaxPeriod, "ocsp-max-period", 1, "@" },
   { oOCSPCurrentPeriod, "ocsp-current-period", 1, "@" },
 
   { oMaxReplies, "max-replies", 1,
@@ -218,6 +221,7 @@
 static void cleanup (void);
 static ldap_server_t parse_ldapserver_file (const char* filename);
 static void free_ldapservers_list (ldap_server_t servers);
+static fingerprint_list_t parse_ocsp_signer (const char *string);
 static void handle_connections (int listen_fd);
 
 /* Pth wrapper function definitions. */
@@ -235,8 +239,9 @@
     case 13: p = VERSION; break;
     case 14: p = "Copyright (C) " COPYRIGHT_YEAR_NAME; break;
     case 17: p = PRINTABLE_OS_NAME; break;
-      /* TRANSLATORS: @EMAIL will get replaced by the actual bug
-         reporting address. */
+      /* TRANSLATORS: @EMAIL@ will get replaced by the actual bug
+         reporting address.  This is so that we can change the
+         reporting address without breaking the translations.  */
     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     case 49: p = PACKAGE_BUGREPORT; break;
     case 1:
@@ -415,10 +420,16 @@
       opt.ignore_ocsp_service_url = 0;
       opt.allow_ocsp = 0;
       opt.ocsp_responder = NULL;
-      opt.ocsp_signer = NULL; 
       opt.ocsp_max_clock_skew = 10 * 60;      /* 10 minutes.  */
+      opt.ocsp_max_period = 90 * 86400;       /* 90 days.  */
       opt.ocsp_current_period = 3 * 60 * 60;  /* 3 hours. */
       opt.max_replies = DEFAULT_MAX_REPLIES;
+      while (opt.ocsp_signer)
+        {
+          fingerprint_list_t tmp = opt.ocsp_signer->next;
+          xfree (opt.ocsp_signer);
+          opt.ocsp_signer = tmp;
+        }
       return 1;
     }
 
@@ -461,8 +472,11 @@
 
     case oAllowOCSP: opt.allow_ocsp = 1; break;
     case oOCSPResponder: opt.ocsp_responder = pargs->r.ret_str; break;
-    case oOCSPSigner:    opt.ocsp_signer = pargs->r.ret_str; break;
+    case oOCSPSigner: 
+      opt.ocsp_signer = parse_ocsp_signer (pargs->r.ret_str);
+      break;
     case oOCSPMaxClockSkew: opt.ocsp_max_clock_skew = pargs->r.ret_int; break;
+    case oOCSPMaxPeriod: opt.ocsp_max_period = pargs->r.ret_int; break;
     case oOCSPCurrentPeriod: opt.ocsp_current_period = pargs->r.ret_int; break;
 
     case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
@@ -1398,6 +1412,129 @@
 }
 
 
+static fingerprint_list_t
+parse_ocsp_signer (const char *string)
+{
+  gpg_error_t err;
+  char *fname;
+  FILE *fp;
+  char line[256];
+  char *p;
+  fingerprint_list_t list, *list_tail, item;
+  unsigned int lnr = 0;
+  int c, i, j;
+  int errflag = 0;
+
+
+  /* Check whether this is not a filename and treat it as a direct
+     fingerprint specification.  */
+  if (!strpbrk (string, "/.~\\"))
+    {
+      item = xcalloc (1, sizeof *item);
+      for (i=j=0; (string[i] == ':' || hexdigitp (string+i)) && j < 40; i++)
+        if ( string[i] != ':' )
+          item->hexfpr[j++] = string[i] >= 'a'? (string[i] & 0xdf): string[i];
+      item->hexfpr[j] = 0;
+      if (j != 40 || !(spacep (string+i) || !string[i]))
+        {
+          log_error (_("%s:%u: invalid fingerprint detected\n"), 
+                     "--ocsp-signer", 0);
+          xfree (item);
+          return NULL;
+        }
+      return item;
+    }
+  
+  /* Well, it is a filename.  */
+  if (*string == '/' || (*string == '~' && string[1] == '/'))
+    fname = make_filename (string, NULL);
+  else
+    {
+      if (string[0] == '.' && string[1] == '/' )
+        string += 2;
+      fname = make_filename (opt.homedir, string, NULL);
+    }
+
+  fp = fopen (fname, "r");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("can't open `%s': %s\n"), fname, gpg_strerror (err));
+      xfree (fname);
+      return NULL;
+    }
+
+  list = NULL;
+  list_tail = &list;
+  for (;;)
+    {
+      if (!fgets (line, DIM(line)-1, fp) )
+        {
+          if (!feof (fp))
+            {
+              err = gpg_error_from_syserror ();
+              log_error (_("%s:%u: read error: %s\n"),
+                         fname, lnr, gpg_strerror (err));
+              errflag = 1;
+            }
+          fclose (fp);
+          if (errflag)
+            {
+              while (list)
+                {
+                  fingerprint_list_t tmp = list->next;
+                  xfree (list);
+                  list = tmp;
+                }
+            }
+          xfree (fname);
+          return list; /* Ready.  */
+        }
+
+      lnr++;
+      if (!*line || line[strlen(line)-1] != '\n')
+        {
+          /* Eat until end of line. */
+          while ( (c=getc (fp)) != EOF && c != '\n')
+            ;
+          err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
+                           /* */: GPG_ERR_INCOMPLETE_LINE);
+          log_error (_("%s:%u: read error: %s\n"), 
+                     fname, lnr, gpg_strerror (err));
+          errflag = 1;
+          continue;
+        }
+
+      /* Allow for empty lines and spaces */
+      for (p=line; spacep (p); p++)
+        ;
+      if (!*p || *p == '\n' || *p == '#')
+        continue;
+
+      item = xcalloc (1, sizeof *item);
+      *list_tail = item;
+      list_tail = &item->next;
+
+      for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
+        if ( p[i] != ':' )
+          item->hexfpr[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
+      item->hexfpr[j] = 0;
+      if (j != 40 || !(spacep (p+i) || p[i] == '\n'))
+        {
+          log_error (_("%s:%u: invalid fingerprint detected\n"), fname, lnr);
+          errflag = 1;
+        }
+      i++;
+      while (spacep (p+i))
+        i++;
+      if (p[i] && p[i] != '\n')
+        log_info (_("%s:%u: garbage at end of line ignored\n"), fname, lnr);
+    }
+  /*NOTREACHED*/
+}
+
+
+
 
 /*
    Stuff used in daemon mode.  

Modified: trunk/src/dirmngr.h
===================================================================
--- trunk/src/dirmngr.h	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/dirmngr.h	2007-08-09 15:51:16 UTC (rev 260)
@@ -51,7 +51,16 @@
 typedef struct ldap_server_s *ldap_server_t;
 
 
+/* A list of fingerprints.  */
+struct fingerprint_list_s;
+typedef struct fingerprint_list_s *fingerprint_list_t;
+struct fingerprint_list_s
+{
+  fingerprint_list_t next;
+  char hexfpr[20+20+1];
+};
 
+
 /* A large struct name "opt" to keep global flags. */
 struct 
 {
@@ -97,12 +106,15 @@
   ldap_server_t ldapservers;
   int add_new_ldapservers;
 
-  const char *ocsp_responder; /* Standard OCSP responder's URL. */
-  const char *ocsp_signer;    /* The fingerprint of the standard OCSP
-                                 responder signer's certificate. */
-  unsigned int ocsp_max_clock_skew;  /* Allowed seconds of clocks skew. */
-  unsigned int ocsp_current_period;  /* Seconds a response is
-                                        considered current. */
+  const char *ocsp_responder;     /* Standard OCSP responder's URL. */
+  fingerprint_list_t ocsp_signer; /* The list of fingerprints with allowed
+                                     standard OCSP signer certificates.  */
+  
+  unsigned int ocsp_max_clock_skew; /* Allowed seconds of clocks skew. */
+  unsigned int ocsp_max_period;     /* Seconds a response is at maximum
+                                       considered valid after thisUpdate. */
+  unsigned int ocsp_current_period; /* Seconds a response is considered 
+                                       current after nextUpdate. */
 } opt;
 
 

Modified: trunk/src/estream-printf.c
===================================================================
--- trunk/src/estream-printf.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/estream-printf.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -17,8 +17,6 @@
  * along with Libestream; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  * USA.
- *
- * $Id: estream-printf.c 56 2007-05-15 18:38:43Z wk $
  */
 
 /*  Required autoconf tests:
@@ -60,19 +58,20 @@
 #endif
 #ifdef TEST
 # include <locale.h>
+#else
+# ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE
+#  include _ESTREAM_PRINTF_EXTRA_INCLUDE
+# endif
 #endif
-#ifdef _ESTREAM_PRINTF_EXTRA_INCLUDE
-#include _ESTREAM_PRINTF_EXTRA_INCLUDE
-#endif
 #include "estream-printf.h"
 
 /* Allow redefinition of asprintf used malloc functions.  */
-#ifdef _ESTREAM_PRINTF_MALLOC
+#if defined(_ESTREAM_PRINTF_MALLOC) && !defined(TEST)
 #define my_printf_malloc(a) _ESTREAM_PRINTF_MALLOC((a))  
 #else
 #define my_printf_malloc(a) malloc((a))
 #endif
-#ifdef _ESTREAM_PRINTF_FREE
+#if defined(_ESTREAM_PRINTF_FREE) && !defined(TEST)
 #define my_printf_free(a)   _ESTREAM_PRINTF_FREE((a))  
 #else
 #define my_printf_free(a)   free((a))
@@ -645,57 +644,7 @@
   return -1;
 }
 
-/* This function is used for testing to provide default arguments.  */
-static int
-read_dummy_value (value_t *value, valtype_t vt)
-{
-  switch (vt)
-    {
-    case VALTYPE_CHAR: value->a_char = 'a'; break;
-    case VALTYPE_CHAR_PTR: value->a_char_ptr = NULL; break;
-    case VALTYPE_SCHAR: value->a_schar = 'a'; break;
-    case VALTYPE_SCHAR_PTR: value->a_schar_ptr = NULL; break;
-    case VALTYPE_UCHAR: value->a_uchar = 'a'; break;
-    case VALTYPE_SHORT: value->a_short = -4711; break;
-    case VALTYPE_USHORT: value->a_ushort = 4711; break;
-    case VALTYPE_SHORT_PTR: value->a_short_ptr = NULL; break;
-    case VALTYPE_INT: value->a_int = 42; break;
-    case VALTYPE_INT_PTR: value->a_int_ptr = NULL; break;
-    case VALTYPE_UINT: value->a_uint = 65535; break;
-    case VALTYPE_LONG: value->a_long = 11071961; break;
-    case VALTYPE_ULONG: value->a_ulong = 19610711; break;
-    case VALTYPE_LONG_PTR: value->a_long_ptr = NULL; break;
-#ifdef HAVE_LONG_LONG_INT
-    case VALTYPE_LONGLONG: value->a_longlong = 11223344; break;
-    case VALTYPE_ULONGLONG: value->a_ulonglong = 2233445566u; break;
-    case VALTYPE_LONGLONG_PTR: value->a_longlong_ptr = NULL; break;
-#endif
-    case VALTYPE_DOUBLE: value->a_double = 3.1415926535; break;
-#ifdef HAVE_LONG_DOUBLE
-    case VALTYPE_LONGDOUBLE: value->a_longdouble = 2.7; break;
-#endif
-    case VALTYPE_STRING: value->a_string = "heart of gold"; break;
-    case VALTYPE_POINTER: value->a_void_ptr = (void*)0xdeadbeef; break;
-#ifdef HAVE_INTMAX_T
-    case VALTYPE_INTMAX: value->a_intmax = 100; break;
-    case VALTYPE_INTMAX_PTR: value->a_intmax_ptr = NULL; break;
-#endif
-#ifdef HAVE_UINTMAX_T
-    case VALTYPE_UINTMAX: value->a_uintmax = 200; break;
-#endif
-    case VALTYPE_SIZE: value->a_size = 65537; break;
-    case VALTYPE_SIZE_PTR: value->a_size_ptr = NULL; break;
-#ifdef HAVE_PTRDIFF_T
-    case VALTYPE_PTRDIFF: value->a_ptrdiff = 2; break;
-    case VALTYPE_PTRDIFF_PTR: value->a_ptrdiff_ptr = NULL; break;
-#endif
-    default: /* Unsupported type.  */
-      return -1;
-    }
-  return 0;
-}
 
-
 /* This function reads all the values as specified by VALUETABLE into
    VALUETABLE.  The values are expected in VAARGS.  The function
    returns -1 if a specified type is not supported. */
@@ -709,102 +658,94 @@
       value_t *value = &valuetable[validx].value;
       valtype_t vt = valuetable[validx].vt;
 
-      if (!vaargs)
+      switch (vt)
         {
-          if (read_dummy_value (value, vt))
-            return -1;
-        }
-      else
-        {
-          switch (vt)
-            {
-            case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break;
-            case VALTYPE_CHAR_PTR:
-              value->a_char_ptr = va_arg (vaargs, char *);
-              break;
-            case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break;
-            case VALTYPE_SCHAR_PTR: 
-              value->a_schar_ptr = va_arg (vaargs, signed char *); 
-              break;
-            case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break;
-            case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break;
-            case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break;
-            case VALTYPE_SHORT_PTR: 
-              value->a_short_ptr = va_arg (vaargs, short *); 
-              break;
-            case VALTYPE_INT:
-              value->a_int = va_arg (vaargs, int);
-              break;
-            case VALTYPE_INT_PTR:
-              value->a_int_ptr = va_arg (vaargs, int *);
-              break;
-            case VALTYPE_UINT:
-              value->a_uint = va_arg (vaargs, unsigned int);
-              break;
-            case VALTYPE_LONG:
-              value->a_long = va_arg (vaargs, long);
-              break;
-            case VALTYPE_ULONG: 
-              value->a_ulong = va_arg (vaargs, unsigned long);
-              break;
-            case VALTYPE_LONG_PTR: 
-              value->a_long_ptr = va_arg (vaargs, long *); 
-              break;
+        case VALTYPE_CHAR: value->a_char = va_arg (vaargs, int); break;
+        case VALTYPE_CHAR_PTR:
+          value->a_char_ptr = va_arg (vaargs, char *);
+          break;
+        case VALTYPE_SCHAR: value->a_schar = va_arg (vaargs, int); break;
+        case VALTYPE_SCHAR_PTR: 
+          value->a_schar_ptr = va_arg (vaargs, signed char *); 
+          break;
+        case VALTYPE_UCHAR: value->a_uchar = va_arg (vaargs, int); break;
+        case VALTYPE_SHORT: value->a_short = va_arg (vaargs, int); break;
+        case VALTYPE_USHORT: value->a_ushort = va_arg (vaargs, int); break;
+        case VALTYPE_SHORT_PTR: 
+          value->a_short_ptr = va_arg (vaargs, short *); 
+          break;
+        case VALTYPE_INT:
+          value->a_int = va_arg (vaargs, int);
+          break;
+        case VALTYPE_INT_PTR:
+          value->a_int_ptr = va_arg (vaargs, int *);
+          break;
+        case VALTYPE_UINT:
+          value->a_uint = va_arg (vaargs, unsigned int);
+          break;
+        case VALTYPE_LONG:
+          value->a_long = va_arg (vaargs, long);
+          break;
+        case VALTYPE_ULONG: 
+          value->a_ulong = va_arg (vaargs, unsigned long);
+          break;
+        case VALTYPE_LONG_PTR: 
+          value->a_long_ptr = va_arg (vaargs, long *); 
+          break;
 #ifdef HAVE_LONG_LONG_INT
-            case VALTYPE_LONGLONG:
-              value->a_longlong = va_arg (vaargs, long long int);
-              break;
-            case VALTYPE_ULONGLONG: 
-              value->a_ulonglong = va_arg (vaargs, unsigned long long int); 
-              break;
-            case VALTYPE_LONGLONG_PTR: 
-              value->a_longlong_ptr = va_arg (vaargs, long long *);
-              break;
+        case VALTYPE_LONGLONG:
+          value->a_longlong = va_arg (vaargs, long long int);
+          break;
+        case VALTYPE_ULONGLONG: 
+          value->a_ulonglong = va_arg (vaargs, unsigned long long int); 
+          break;
+        case VALTYPE_LONGLONG_PTR: 
+          value->a_longlong_ptr = va_arg (vaargs, long long *);
+          break;
 #endif
-            case VALTYPE_DOUBLE:
-              value->a_double = va_arg (vaargs, double);
-              break;
+        case VALTYPE_DOUBLE:
+          value->a_double = va_arg (vaargs, double);
+          break;
 #ifdef HAVE_LONG_DOUBLE
-            case VALTYPE_LONGDOUBLE:
-              value->a_longdouble = va_arg (vaargs, long double);
-              break;
+        case VALTYPE_LONGDOUBLE:
+          value->a_longdouble = va_arg (vaargs, long double);
+          break;
 #endif
-            case VALTYPE_STRING:
-              value->a_string = va_arg (vaargs, const char *);
-              break;
-            case VALTYPE_POINTER: 
-              value->a_void_ptr = va_arg (vaargs, void *);
-              break;
+        case VALTYPE_STRING:
+          value->a_string = va_arg (vaargs, const char *);
+          break;
+        case VALTYPE_POINTER: 
+          value->a_void_ptr = va_arg (vaargs, void *);
+          break;
 #ifdef HAVE_INTMAX_T
-            case VALTYPE_INTMAX:
-              value->a_intmax = va_arg (vaargs, intmax_t);
-              break;
-            case VALTYPE_INTMAX_PTR: 
-              value->a_intmax_ptr = va_arg (vaargs, intmax_t *); 
-              break;
+        case VALTYPE_INTMAX:
+          value->a_intmax = va_arg (vaargs, intmax_t);
+          break;
+        case VALTYPE_INTMAX_PTR: 
+          value->a_intmax_ptr = va_arg (vaargs, intmax_t *); 
+          break;
 #endif
 #ifdef HAVE_UINTMAX_T
-            case VALTYPE_UINTMAX: 
-              value->a_uintmax = va_arg (vaargs, uintmax_t); 
-              break;
+        case VALTYPE_UINTMAX: 
+          value->a_uintmax = va_arg (vaargs, uintmax_t); 
+          break;
 #endif
-            case VALTYPE_SIZE:
-              value->a_size = va_arg (vaargs, size_t);
-              break;
-            case VALTYPE_SIZE_PTR: 
-              value->a_size_ptr = va_arg (vaargs, size_t *); 
-              break;
+        case VALTYPE_SIZE:
+          value->a_size = va_arg (vaargs, size_t);
+          break;
+        case VALTYPE_SIZE_PTR: 
+          value->a_size_ptr = va_arg (vaargs, size_t *); 
+          break;
 #ifdef HAVE_PTRDIFF_T
-            case VALTYPE_PTRDIFF:
-              value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); 
-              break;
-            case VALTYPE_PTRDIFF_PTR:
-              value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *);
-              break;
+        case VALTYPE_PTRDIFF:
+          value->a_ptrdiff = va_arg (vaargs, ptrdiff_t); 
+          break;
+        case VALTYPE_PTRDIFF_PTR:
+          value->a_ptrdiff_ptr = va_arg (vaargs, ptrdiff_t *);
+          break;
 #endif
-            default: /* Unsupported type.  */
-              return -1;
-            }
+        default: /* Unsupported type.  */
+          return -1;
         }
     }
   return 0;
@@ -1329,7 +1270,7 @@
 /* Run the actual formatting.  OUTFNC and OUTFNCARG are the output
    functions.  FORMAT is format string ARGSPECS is the parsed format
    string, ARGSPECS_LEN the number of items in ARGSPECS.  VALUETABLE
-   holds the values and may be directly addressed using the poistion
+   holds the values and may be directly addressed using the position
    arguments given by ARGSPECS.  MYERRNO is used for the "%m"
    conversion. NBYTES well be updated to reflect the number of bytes
    send to the output function. */ 
@@ -1449,8 +1390,8 @@
     }
   
   /* Print out any trailing stuff. */
-  s++;  /* Need to output a terminating nul; take it from format.  */
-  rc = outfnc (outfncarg, format, (n=s - format));
+  n = s - format;
+  rc = n? outfnc (outfncarg, format, n) : 0;
   if (!rc)
     *nbytes += n;
 
@@ -1619,10 +1560,8 @@
 {
   FILE *fp = (FILE*)outfncarg;
 
-  fputs ("OUT->", fp);
   if ( fwrite (buf, buflen, 1, fp) != 1 )
     return -1;
-  fputs ("<-\n", fp);
   return 0;
 }
 
@@ -1715,6 +1654,8 @@
   parm.used = 0;
   parm.buffer = bufsize?buf:NULL;
   rc = estream_format (fixed_buffer_out, &parm, format, arg_ptr);
+  if (!rc)
+    rc = fixed_buffer_out (&parm, "", 1); /* Print terminating Nul.  */
   if (rc == -1)
     return -1;
   if (bufsize && buf && parm.count >= parm.size)
@@ -1807,7 +1748,9 @@
     }
   
   rc = estream_format (dynamic_buffer_out, &parm, format, arg_ptr);
-
+  if (!rc)
+    rc = dynamic_buffer_out (&parm, "", 1); /* Print terminating Nul.  */
+  /* Fixme: Should we shrink the resulting buffer?  */
   if (rc != -1 && parm.error_flag)
     {
       rc = -1;
@@ -1820,9 +1763,9 @@
       *bufp = NULL;
       return -1;
     }
-  
+  assert (parm.used);   /* We have at least the terminating Nul.  */
   *bufp = parm.buffer;
-  return parm.used - 1; /* Do not include the nul. */
+  return parm.used - 1; /* Do not include that Nul. */
 }
 
 /* A replacement for asprintf.  As with the BSD of asprintf version -1
@@ -1891,8 +1834,7 @@
 static void
 run_tests (void)
 {
-#if 0
-  one_test ("%d %% %'d", 17, 19681977);
+  /*one_test ("%d %% %'d", 17, 19681977);*/
 
   one_test ("%d %% %d", 17, 768114563);
   one_test ("%d %% %d", 17, -768114563);
@@ -2011,8 +1953,9 @@
   one_test ("%50s", "the quick brown fox jumps over the lazy dogs back");
   one_test ("%51s", "the quick brown fox jumps over the lazy dogs back");
   one_test ("%-51s", "the quick brown fox jumps over the lazy dogs back");
-#endif
 
+  one_test ("/%s=", "CN");
+
   one_test ("%f", 3.1415926535);
   one_test ("%f", -3.1415926535);
   one_test ("%.10f", 3.1415926535);

Modified: trunk/src/estream.h
===================================================================
--- trunk/src/estream.h	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/estream.h	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,4 +1,4 @@
-/* estream.h - Extended stream I/O/ Library
+/* estream.h - Extended stream I/O Library
  * Copyright (C) 2004, 2005, 2006, 2007 g10 Code GmbH
  *
  * This file is part of Libestream.

Modified: trunk/src/ocsp.c
===================================================================
--- trunk/src/ocsp.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/ocsp.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -1,5 +1,5 @@
 /* ocsp.c - OCSP management
- *      Copyright (C) 2004 g10 Code GmbH
+ *      Copyright (C) 2004, 2007 g10 Code GmbH
  *
  * This file is part of DirMngr.
  *
@@ -298,26 +298,29 @@
 
 
 /* Validate that CERT is indeed valid to sign an OCSP response. If
-   signer_fpr is not NULL we simply check that CERT matches this
-   fingerprint. */
+   SIGNER_FPR_LIST is not NULL we simply check that CERT matches one
+   of the fingerprints in this list. */
 static gpg_error_t
-validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert, const char *signer_fpr)
+validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert, 
+                         fingerprint_list_t signer_fpr_list)
 {
   gpg_error_t err;
   char *fpr;
 
-  if (signer_fpr)
+  if (signer_fpr_list)
     {
-      fpr = (strchr (signer_fpr, ':')
-             ? get_fingerprint_hexstring_colon (cert)
-             : get_fingerprint_hexstring (cert));
-      if (ascii_strcasecmp (signer_fpr, fpr))
+      fpr = get_fingerprint_hexstring (cert);
+      for (; signer_fpr_list && strcmp (signer_fpr_list->hexfpr, fpr); 
+           signer_fpr_list = signer_fpr_list->next)
+        ;
+      if (signer_fpr_list)
+        err = 0;
+      else
         {
-          log_error (_("not signed by default OCSP signer certificate"));
+          log_error (_("not signed by a default OCSP signer's certificate"));
           err = gpg_error (GPG_ERR_BAD_CA_CERT);
         }
-      else
-        err = 0;
+      xfree (fpr);
     }
   else if (opt.system_daemon)
     {
@@ -354,7 +357,7 @@
 /* Helper for check_signature. */
 static int
 check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
-                      gcry_sexp_t s_hash, const char *signer_fpr)
+                      gcry_sexp_t s_hash, fingerprint_list_t signer_fpr_list)
 {
   gpg_error_t err;
   ksba_sexp_t pubkey;
@@ -369,7 +372,7 @@
   if (!err)
     err = gcry_pk_verify (s_sig, s_hash, s_pkey);
   if (!err)
-    err = validate_responder_cert (ctrl, cert, signer_fpr);
+    err = validate_responder_cert (ctrl, cert, signer_fpr_list);
   if (!err)
     {
       gcry_sexp_release (s_pkey);
@@ -385,13 +388,13 @@
 /* Check the signature of an OCSP repsonse.  OCSP is the context,
    S_SIG the signature value and MD the handle of the hash we used for
    the response.  This function automagically finds the correct public
-   key.  If SIGNER_FPR is not NULL, the default OCSP reponder has been
-   used and thus the certificate to be used is the one identified by
-   this fingerprint. */
+   key.  If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
+   used and thus the certificate is one of those identified by
+   the fingerprints. */
 static gpg_error_t
 check_signature (ctrl_t ctrl,
                  ksba_ocsp_t ocsp, gcry_sexp_t s_sig, gcry_md_hd_t md,
-                 const char *signer_fpr)
+                 fingerprint_list_t signer_fpr_list)
 {
   gpg_error_t err;
   int algo, cert_idx;
@@ -418,16 +421,18 @@
   /* Get rid of old OCSP specific certificate references. */
   release_ctrl_ocsp_certs (ctrl);
 
-  if (signer_fpr)
+  if (signer_fpr_list && !signer_fpr_list->next)
     {
-      /* We use the default OCSP responder's certificate.  Get it from
-         the fingerprint. */
-      cert = get_cert_byhexfpr (signer_fpr);
+      /* There is exactly one signer fingerprint given. Thus we use
+         the default OCSP responder's certificate and instantly know
+         the certificate to use.  */
+      cert = get_cert_byhexfpr (signer_fpr_list->hexfpr);
       if (!cert)
-        cert = get_cert_local (ctrl, signer_fpr);
+        cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
       if (cert)
         {
-          err = check_signature_core (ctrl, cert, s_sig, s_hash, signer_fpr);
+          err = check_signature_core (ctrl, cert, s_sig, s_hash,
+                                      signer_fpr_list);
           ksba_cert_release (cert);
           cert = NULL;
           if (!err)
@@ -463,7 +468,7 @@
             xfree (cref);
         }
 
-      /* Get the certificate by means of the respinder ID. */
+      /* Get the certificate by means of the responder ID. */
       err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
       if (err)
         {
@@ -490,7 +495,8 @@
 
       if (cert)
         {
-          err = check_signature_core (ctrl, cert, s_sig, s_hash, NULL);
+          err = check_signature_core (ctrl, cert, s_sig, s_hash,
+                                      signer_fpr_list);
           ksba_cert_release (cert);
           if (!err)
             {
@@ -508,9 +514,11 @@
 
 /* Check whether the certificate either given by fingerprint CERT_FPR
    or directly through the CERT object is valid by running an OCSP
-   transaction.  */
+   transaction.  With FORCE_DEFAULT_RESPONDER set only the configured
+   default responder is used. */
 gpg_error_t
-ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr)
+ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
+              int force_default_responder)
 {
   gpg_error_t err;
   ksba_ocsp_t ocsp = NULL;
@@ -528,7 +536,7 @@
   int i, idx;
   char *oid;
   ksba_name_t name;
-  const char *default_signer = NULL;
+  fingerprint_list_t default_signer = NULL;
 
   /* Get the certificate.  */
   if (cert)
@@ -578,7 +586,7 @@
      2. If this fails use the default responder, if any.
    */
   url = NULL;
-  for (idx=0; !url && !opt.ignore_ocsp_service_url
+  for (idx=0; !url && !opt.ignore_ocsp_service_url && !force_default_responder
          && !(err=ksba_cert_get_authority_info_access (cert, idx,
                                                        &oid, &name)); idx++)
     {
@@ -610,7 +618,7 @@
           err = gpg_error (GPG_ERR_CONFIGURATION);
           goto leave;
         }
-      if (!opt.ocsp_signer || !*opt.ocsp_signer)
+      if (!opt.ocsp_signer)
         {
           log_info (_("no default OCSP signer defined\n"));
           err = gpg_error (GPG_ERR_CONFIGURATION);
@@ -717,31 +725,51 @@
 
   if (status == KSBA_STATUS_REVOKED)
     err = gpg_error (GPG_ERR_CERT_REVOKED);
+  else if (status == KSBA_STATUS_UNKNOWN)
+    err = gpg_error (GPG_ERR_NO_DATA);
   else if (status != KSBA_STATUS_GOOD)
     err = gpg_error (GPG_ERR_GENERAL);
 
+  /* Allow for some clock skew. */
   get_isotime (current_time);
-  /* Allow for some clock skew. Note, that NEXT_UPDATE is
-     optional. */
   add_isotime (current_time, opt.ocsp_max_clock_skew);
-  if (*next_update && strcmp (next_update, current_time) < 0 )
+
+  if (strcmp (this_update, current_time) > 0 )
     {
-      log_error (_("OCSP responder returned an too old status\n"));
-      log_info ("now: %s  next_update: %s\n", current_time, next_update);
+      log_error (_("OCSP responder returned a status in the future\n"));
+      log_info ("used now: %s  this_update: %s\n", current_time, this_update);
       if (!err)
         err = gpg_error (GPG_ERR_TIME_CONFLICT);
     }
+
   /* Check that THIS_UPDATE is not too far back in the past. */
   copy_time (tmp_time, this_update);
-  add_isotime (this_update, opt.ocsp_current_period + opt.ocsp_max_clock_skew);
-  if (!*this_update || strcmp (this_update, current_time) < 0 )
+  add_isotime (tmp_time, opt.ocsp_max_period+opt.ocsp_max_clock_skew);
+  if (!*tmp_time || strcmp (tmp_time, current_time) < 0 )
     {
       log_error (_("OCSP responder returned a non-current status\n"));
-      log_info ("now: %s  this_update: %s\n", current_time, tmp_time);
+      log_info ("used now: %s  this_update: %s\n", 
+                current_time, this_update);
       if (!err)
         err = gpg_error (GPG_ERR_TIME_CONFLICT);
     }
 
+  /* Check that we are not beyound NEXT_UPDATE  (plus some extra time). */
+  if (*next_update)
+    {
+      copy_time (tmp_time, next_update);
+      add_isotime (tmp_time, opt.ocsp_current_period+opt.ocsp_max_clock_skew);
+      if (!*tmp_time && strcmp (tmp_time, current_time) < 0 )
+        {
+          log_error (_("OCSP responder returned an too old status\n"));
+          log_info ("used now: %s  next_update: %s\n", 
+                    current_time, next_update);
+          if (!err)
+            err = gpg_error (GPG_ERR_TIME_CONFLICT);
+        }
+    }
+
+
  leave:
   gcry_md_close (md);
   gcry_sexp_release (s_sig);

Modified: trunk/src/ocsp.h
===================================================================
--- trunk/src/ocsp.h	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/ocsp.h	2007-08-09 15:51:16 UTC (rev 260)
@@ -15,13 +15,15 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #ifndef OCSP_H
 #define OCSP_H
 
-gpg_error_t ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr);
+gpg_error_t ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
+                          int force_default_responder);
 
 /* Release the list of OCSP certificates hold in the CTRL object. */
 void release_ctrl_ocsp_certs (ctrl_t ctrl);

Modified: trunk/src/server.c
===================================================================
--- trunk/src/server.c	2007-08-08 17:06:34 UTC (rev 259)
+++ trunk/src/server.c	2007-08-09 15:51:16 UTC (rev 260)
@@ -85,6 +85,53 @@
 }
 
 
+/* Check whether the option NAME appears in LINE */
+static int
+has_option (const char *line, const char *name)
+{
+  const char *s;
+  int n = strlen (name);
+
+  s = strstr (line, name);
+  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
+}
+
+
+/* Same as has_option but does only test for the name of the option
+   and ignores an argument, i.e. with NAME being "--hash" it would
+   return a pointer for "--hash" as well as for "--hash=foo".  If
+   thhere is no such option NULL is returned.  The pointer returned
+   points right behind the option name, this may be an equal sign, Nul
+   or a space.  */
+/* static const char * */
+/* has_option_name (const char *line, const char *name) */
+/* { */
+/*   const char *s; */
+/*   int n = strlen (name); */
+
+/*   s = strstr (line, name); */
+/*   return (s && (s == line || spacep (s-1)) */
+/*           && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL; */
+/* } */
+
+
+/* Skip over options.  It is assumed that leading spaces have been
+   removed (this is the case for lines passed to a handler from
+   assuan).  Blanks after the options are also removed. */
+static char *
+skip_options (char *line)
+{
+  while ( *line == '-' && line[1] == '-' )
+    {
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+    }
+  return line;
+}
+
+
 /* Common code for get_cert_local and get_issuer_cert_local. */
 static ksba_cert_t 
 do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
@@ -309,7 +356,8 @@
 }
 
 
-/* IS_VALID <certificate_id>|<certificate_fpr>
+/* ISVALID [--only-ocsp] [--force-default-responder]
+            <certificate_id>|<certificate_fpr>
   
    This command checks whether the certificate identified by the
    certificate_id is valid.  This is done by consulting CRLs or
@@ -317,12 +365,19 @@
    are from gpg-error.h.  The command may callback using the inquire
    function.  See the manual for details.
  
-   The certificate_id is a hex encoded string consisting of two parts,
+   The CERTIFICATE_ID is a hex encoded string consisting of two parts,
    delimited by a single dot.  The first part is the SHA-1 hash of the
    issuer name and the second part the serial number.
 
    Alternatively the certificate's fingerprint may be given in which
    case an OCSP request is done before consulting the CRL.
+
+   If the option --only-ocsp is given, no fallback to a CRL check will
+   be used.
+
+   If the option --force-default-responder is given, only the default
+   OCSP responder will be used and any other methods of obtaining an
+   OCSP responder URL won't be used.
  */
 
 static int
@@ -333,7 +388,13 @@
   gpg_error_t err;
   int did_inquire = 0;
   int ocsp_mode = 0;
+  int only_ocsp;
+  int force_default_responder;
   
+  only_ocsp = has_option (line, "--only-ocsp");
+  force_default_responder = has_option (line, "--force-default-responder");
+  line = skip_options (line);
+
   issuerhash = xstrdup (line); /* We need to work on a copy of the
                                   line because that same Assuan
                                   context may be used for an inquiry.
@@ -367,13 +428,15 @@
       if (!opt.allow_ocsp)
         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       else
-        err = ocsp_isvalid (ctrl, NULL, NULL);
-      /* Fixme: If we got no ocsp response we should fall back to CRL
-         mode.  Thus we need to clear OCSP_MODE, get the issuerhash
-         and the serialno from the current certificate and jump to
-         again. */
+        err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
+      /* Fixme: If we got no ocsp response and --only-ocsp is not used
+         we should fall back to CRL mode.  Thus we need to clear
+         OCSP_MODE, get the issuerhash and the serialno from the
+         current certificate and jump to again. */
     }
-  else
+  else if (only_ocsp)
+    err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+  else 
     {
       switch (crl_cache_isvalid (ctrl,
                                  issuerhash, serialno,
@@ -523,13 +586,13 @@
 }
 
 
-/* CHECKOCSP [<fingerprint>]
+/* CHECKOCSP [--force-default-responder] [<fingerprint>]
 
    Check whether the certificate with FINGERPRINT (SHA-1 hash of the
    entire X.509 certificate blob) is valid or not by asking an OCSP
    responder responsible for this certificate.  The optional
    fingerprint may be used for a quick check in case an OCSP check has
-   been down for this certificate recently (we always cache OCSP
+   been done for this certificate recently (we always cache OCSP
    responses for a couple of minutes). If the fingerprint has not been
    given or there is no cached result, the function inquires the
    certificate using the
@@ -543,6 +606,10 @@
    its own mechanism which includes a local certificate store as well
    as a list of trusted root certifciates.
 
+   If the option --force-default-responder is given, only the default
+   OCSP responder will be used and any other methods of obtaining an
+   OCSP responder URL won't be used.
+
    The return value is the usual gpg-error code or 0 for ducesss;
    i.e. the certificate validity has been confirmed by a valid CRL.
 */
@@ -553,6 +620,10 @@
   gpg_error_t err;
   unsigned char fprbuffer[20], *fpr;
   ksba_cert_t cert;
+  int force_default_responder;
+  
+  force_default_responder = has_option (line, "--force-default-responder");
+  line = skip_options (line);
 
   fpr = get_fingerprint_from_line (line, fprbuffer);
   cert = fpr? get_cert_byfpr (fpr) : NULL;
@@ -590,7 +661,7 @@
   if (!opt.allow_ocsp)
     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
   else
-    err = ocsp_isvalid (ctrl, cert, NULL);
+    err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder);
 
  leave:
   if (err)




More information about the Gnupg-commits mailing list