dirmngr (10 files)

cvs user wk cvs at cvs.gnupg.org
Mon Apr 18 12:21:14 CEST 2005


    Date: Monday, April 18, 2005 @ 12:37:53
  Author: wk
    Path: /cvs/dirmngr/dirmngr

Modified: ChangeLog NEWS configure.ac src/ChangeLog src/certcache.c
          src/certcache.h src/crlcache.c src/dirmngr.h src/server.c
          src/validate.c

* configure.ac: Require libksba 0.9.11.

* certcache.c (find_issuing_cert): Fixed last resort method which
should be finding by subject and not by issuer. Try to locate it
also using the keyIdentifier method.  Improve error reporting.
(cmp_simple_canon_sexp): New.
(find_cert_bysubject): New.
(find_cert_bysn): Ask back to the caller before trying an extarnl
lookup.
* server.c (get_cert_local_ski): New.
* crlcache.c (crl_parse_insert): Also try to locate issuer
certificate using the keyIdentifier.  Improved error reporting.


-----------------+
 ChangeLog       |    4 +
 NEWS            |    4 +
 configure.ac    |    2 
 src/ChangeLog   |   15 +++-
 src/certcache.c |  199 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/certcache.h |   12 +++
 src/crlcache.c  |   29 ++++++-
 src/dirmngr.h   |    2 
 src/server.c    |   79 ++++++++++++++++++++-
 src/validate.c  |    2 
 10 files changed, 322 insertions(+), 26 deletions(-)


Index: dirmngr/ChangeLog
diff -u dirmngr/ChangeLog:1.86 dirmngr/ChangeLog:1.87
--- dirmngr/ChangeLog:1.86	Tue Feb  8 12:30:41 2005
+++ dirmngr/ChangeLog	Mon Apr 18 12:37:53 2005
@@ -1,3 +1,7 @@
+2005-04-18  Werner Koch  <wk at g10code.com>
+
+	* configure.ac: Require libksba 0.9.11.
+
 2005-02-08  Werner Koch  <wk at g10code.com>
 
 	Released 0.9.1.
Index: dirmngr/NEWS
diff -u dirmngr/NEWS:1.36 dirmngr/NEWS:1.37
--- dirmngr/NEWS:1.36	Tue Feb  8 12:41:46 2005
+++ dirmngr/NEWS	Mon Apr 18 12:37:53 2005
@@ -1,6 +1,10 @@
 Noteworthy changes in version 0.9.2
 ------------------------------------------------
 
+ * Make use of authorityKeyidentifier.keyIdentifier.
+
+ * Fixed a possible hang in the LDAP lookup code.
+
 
 Noteworthy changes in version 0.9.1 (2005-02-08)
 ------------------------------------------------
Index: dirmngr/configure.ac
diff -u dirmngr/configure.ac:1.71 dirmngr/configure.ac:1.72
--- dirmngr/configure.ac:1.71	Tue Feb  8 12:41:46 2005
+++ dirmngr/configure.ac	Mon Apr 18 12:37:53 2005
@@ -31,7 +31,7 @@
 
 NEED_LIBASSUAN_VERSION=0.6.8
 
-NEED_KSBA_VERSION=0.9.6
+NEED_KSBA_VERSION=0.9.11
 
 
 PACKAGE=$PACKAGE_NAME
Index: dirmngr/src/ChangeLog
diff -u dirmngr/src/ChangeLog:1.46 dirmngr/src/ChangeLog:1.47
--- dirmngr/src/ChangeLog:1.46	Thu Apr 14 13:58:29 2005
+++ dirmngr/src/ChangeLog	Mon Apr 18 12:37:53 2005
@@ -1,10 +1,23 @@
+2005-04-18  Werner Koch  <wk at g10code.com>
+
+	* certcache.c (find_issuing_cert): Fixed last resort method which
+	should be finding by subject and not by issuer. Try to locate it
+	also using the keyIdentifier method.  Improve error reporting.
+	(cmp_simple_canon_sexp): New.
+	(find_cert_bysubject): New.
+	(find_cert_bysn): Ask back to the caller before trying an extarnl
+	lookup.
+	* server.c (get_cert_local_ski): New.
+	* crlcache.c (crl_parse_insert): Also try to locate issuer
+	certificate using the keyIdentifier.  Improved error reporting.
+
 2005-04-14  Werner Koch  <wk at g10code.com>
 
 	* ldap.c (start_cert_fetch_ldap): Really return ERR.
 
 2005-03-17  Werner Koch  <wk at g10code.com>
 
-	* http.c (parse_response): Changed MAXLEN and LEN to size-t to
+	* http.c (parse_response): Changed MAXLEN and LEN to size_t to
 	match the requirement of read_line.
 	* http.h (http_context_s): Ditto for BUFFER_SIZE.
 
Index: dirmngr/src/certcache.c
diff -u dirmngr/src/certcache.c:1.9 dirmngr/src/certcache.c:1.10
--- dirmngr/src/certcache.c:1.9	Tue Feb  1 17:49:15 2005
+++ dirmngr/src/certcache.c	Mon Apr 18 12:37:53 2005
@@ -39,10 +39,10 @@
 #define MAX_EXTRA_CACHED_CERTS 1000
 
 
-/* A certificate cache item.  This consists of a the ksba cert object
+/* 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
-   track of all items and use sue the randomly distributed first byte
-   of the fingerprint directly as the hash which makes it pretty easy. */
+   track of all items and use the (randomly distributed) first byte of
+   the fingerprint directly as the hash which makes it pretty easy. */
 struct cert_item_s
 {
   struct cert_item_s *next; /* Next item with the same hash value. */
@@ -138,6 +138,14 @@
   return !!n_a;
 }
 
+/* An alias for the above function to be used with S-expressions
+   similar to serial numbers. */
+int
+cmp_simple_canon_sexp (ksba_sexp_t a, ksba_sexp_t b)
+{
+  return compare_serialno (a, b);
+}
+
 
 /* Compute the fingerprint of the certificate CERT and put it into
    the 20 bytes large buffer DIGEST.  Return address of this buffer.  */
@@ -589,7 +597,7 @@
 }
 
 
-/* Return the certificate matching SUBJEC_DN.  SEQ should initially be
+/* Return the certificate matching SUBJECT_DN.  SEQ should initially be
    set to 0 and bumped up to get the next subject with that DN. */
 ksba_cert_t
 get_cert_bysubject (const char *subject_dn, unsigned int seq)
@@ -630,6 +638,36 @@
 
   cert = get_cert_bysn (issuer_dn, serialno);
 
+  if (!cert)
+    {
+      char *hexsn, *buf;
+      /* 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. */
+      hexsn = serial_hex (serialno);
+      if (!hexsn)
+        {
+          log_debug ("serial_hex() failed\n");
+          return NULL;
+        }
+      buf = xtrymalloc (1 + strlen (hexsn) + 1 + strlen (issuer_dn) + 1);
+      if (!buf)
+        {
+          log_error ("can't allocate enough memory: %s\n", strerror (errno));
+          xfree (hexsn);
+          return NULL;
+        }
+      strcpy (stpcpy (stpcpy (stpcpy (buf, "#"), hexsn),"/"), issuer_dn);
+      xfree (hexsn);
+      cert = get_cert_local (ctrl, buf);
+      xfree (buf);
+      if (cert)
+        {
+          cache_cert (cert);
+          return cert; /* Done. */
+        }
+    }
+
   while (!cert)
     {
       ksba_sexp_t sn;
@@ -694,6 +732,119 @@
   return cert;
 }
 
+/* Return the certificate matching SUBJECT_DN and (if not NULL)
+   KEYID. If it is not already in the cache, try to find it from other
+   resources.  Note, that the external search does not work for user
+   certificates because the LDAP lookup is on the caCertificate
+   attribute. For our purposes this is just fine.  */
+ksba_cert_t
+find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
+{
+  gpg_error_t err;
+  int seq;
+  ksba_cert_t cert = NULL;
+  cert_fetch_context_t context = NULL;
+  ksba_sexp_t subj;
+
+  for (seq=0; (cert = get_cert_bysubject (subject_dn, seq)); seq++)
+    {
+      if (!keyid)
+        break; /* No keyid requested, so return the first one found. */
+      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj)
+          && !cmp_simple_canon_sexp (keyid, subj))
+        {
+          xfree (subj);
+          break; /* Found matching cert. */
+        }
+      xfree (subj);
+      ksba_cert_release (cert);
+    }
+
+  if (!cert)
+    {
+      /* 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. */
+      cert = get_cert_local_ski (ctrl, subject_dn, keyid);
+      if (cert)
+        {
+          cache_cert (cert);
+          return cert; /* Done. */
+        }
+    }
+
+
+  while (!cert)
+    {
+      char *subjdn;
+
+      if (!context)
+        {
+          err = ca_cert_fetch (ctrl, &context, subject_dn);
+          if (err)
+            {
+              log_error (_("error fetching certificate by subject: %s\n"),
+                         gpg_strerror (err));
+              break;
+            }
+        }
+      
+      err = fetch_next_ksba_cert (context, &cert);
+      if (err)
+        {
+          log_error (_("error fetching certificate by subject: %s\n"),
+                     gpg_strerror (err) );
+          break;
+        }
+      
+      subjdn = ksba_cert_get_subject (cert, 0);
+      if (strcmp (subject_dn, subjdn))
+        {
+          log_info ("find_cert_bysubject: subject DN does not match\n");
+          ksba_cert_release (cert);
+          cert = NULL;
+          ksba_free (subjdn);
+          continue; 
+        }
+
+
+      if (DBG_LOOKUP)
+        {
+          log_debug ("   considering certificate (/");
+          dump_string (subjdn);
+          log_printf (")\n");
+        }
+      ksba_free (subjdn);
+
+      if (!keyid)
+        {
+          cache_cert (cert);
+          if (DBG_LOOKUP)
+            log_debug ("   found\n");
+          break; /* Ready.  */
+        }
+
+      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj))
+        {
+          if (!cmp_simple_canon_sexp (keyid, subj))
+            {
+              ksba_free (subj);
+              cache_cert (cert);
+              if (DBG_LOOKUP)
+                log_debug ("   found\n");
+              break; /* Ready.  */
+            }
+        }
+
+      ksba_free (subj);
+      ksba_cert_release (cert);
+      cert = NULL;
+    }
+
+  end_cert_fetch (context);
+  return cert;
+}
+
 
 
 /* Return 0 if the certificate is a trusted certificate. Returns
@@ -735,6 +886,7 @@
   ksba_cert_t issuer_cert = NULL;
   ksba_name_t authid;
   ksba_sexp_t authidno;
+  ksba_sexp_t keyid;
 
   *r_cert = NULL;
 
@@ -748,7 +900,7 @@
 
   /* First we need to check whether we can return that certificate
      using the authorithyKeyIdentifier.  */
-  err = ksba_cert_get_auth_key_id (cert, NULL, &authid, &authidno);
+  err = ksba_cert_get_auth_key_id (cert, &keyid, &authid, &authidno);
   if (err)
     {
       log_info (_("error getting authorityKeyIdentifier: %s\n"),
@@ -761,27 +913,46 @@
         {
           issuer_cert = find_cert_bysn (ctrl, s, authidno);
         }
+      if (!issuer_cert && keyid)
+        {
+          /* Not found by issuer+s/n.  Now that we have an AKI
+             keyIdentifier look for a certificate with a matching
+             SKI. */
+          issuer_cert = find_cert_bysubject (ctrl, issuer_dn, keyid);
+        }
       /* Print a note so that the user does not feel too helpless when
          an issuer certificate was found and gpgsm prints BAD
          signature because it is not the correct one. */
       if (!issuer_cert)
         {
-          log_info ("issuer certificate (#");
-          dump_serial (authidno);
-          log_printf ("/");
-          dump_string (s);
-          log_printf (") not found\n");
+          log_info ("issuer certificate ");
+          if (keyid)
+            {
+              log_printf ("{");
+              dump_serial (keyid);
+              log_printf ("} ");
+            }
+          if (authidno)
+            {
+              log_printf ("(#");
+              dump_serial (authidno);
+              log_printf ("/");
+              dump_string (s);
+              log_printf (") ");
+            }
+          log_printf ("not found using authorityKeyIdentifier\n");
         }
       ksba_name_release (authid);
       xfree (authidno);
+      xfree (keyid);
     }
 
-  /* If this did not work, try just with the issuer's name.  */
+  /* If this did not work, try just with the issuer's name and assume
+     that there is only one such certificate.  We only look into our
+     cache then. */
   if (err || !issuer_cert)
     {
-      /* FIXME: we need to save a sequence number here for later
-         tries.  */
-      issuer_cert = get_cert_byissuer (issuer_dn, 0);
+      issuer_cert = get_cert_bysubject (issuer_dn, 0);
     }
 
  leave:  
Index: dirmngr/src/certcache.h
diff -u dirmngr/src/certcache.h:1.7 dirmngr/src/certcache.h:1.8
--- dirmngr/src/certcache.h:1.7	Tue Feb  1 17:49:15 2005
+++ dirmngr/src/certcache.h	Mon Apr 18 12:37:53 2005
@@ -34,6 +34,9 @@
    the 20 bytes large buffer DIGEST.  Return address of this buffer.  */
 unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest);
 
+/* Compare two simple S-exprerssions A and B and return 0 if they match. */
+int cmp_simple_canon_sexp (ksba_sexp_t a, ksba_sexp_t b);
+
 /* Put CERT into the certificate cache.  */
 gpg_error_t cache_cert (ksba_cert_t cert);
 
@@ -72,6 +75,15 @@
 ksba_cert_t find_cert_bysn (ctrl_t ctrl,
                             const char *issuer_dn, ksba_sexp_t serialno);
 
+
+/* Return the certificate matching SUBJECT_DN and (if not NULL) KEYID. If
+   it is not already in the cache, try to find it from other
+   resources.  Note, that the external search does not work for user
+   certificates because the LDAP lookup is on the caCertificate
+   attribute. For our purposes this is just fine.  */
+ksba_cert_t find_cert_bysubject (ctrl_t ctrl,
+                                 const char *subject_dn, ksba_sexp_t keyid);
+
 /* 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.53 dirmngr/src/crlcache.c:1.54
--- dirmngr/src/crlcache.c:1.53	Tue Feb  1 17:49:15 2005
+++ dirmngr/src/crlcache.c	Mon Apr 18 12:37:53 2005
@@ -1674,6 +1674,7 @@
             char *crlissuer;
             ksba_name_t authid;
             ksba_sexp_t authidsn;
+            ksba_sexp_t keyid;
 
             /* We need to look for the issuer only after having read
                all items.  The issuer itselfs comes before the items
@@ -1690,7 +1691,7 @@
             *r_crlissuer = crlissuer; /* (Do it here so we don't need
                                          to free it later) */
 
-            if (!ksba_crl_get_auth_key_id (crl, NULL, &authid, &authidsn))
+            if (!ksba_crl_get_auth_key_id (crl, &keyid, &authid, &authidsn))
               {
                 const char *s;
 
@@ -1701,16 +1702,32 @@
                 s = ksba_name_enum (authid, 0);
                 if (s && *authidsn)
                   crlissuer_cert = get_crlissuer_cert_bysn (ctrl, s, authidsn);
+                if (!crlissuer_cert && keyid)
+                  crlissuer_cert = find_cert_bysubject (ctrl,
+                                                        crlissuer, keyid);
+
                 if (!crlissuer_cert)
                   {
-                    log_info ("CRL issuer certificate (#");
-                    dump_serial (authidsn);
-                    log_printf ("/");
-                    dump_string (s);
-                    log_printf (") not found\n");
+                    log_info ("CRL issuer certificate ");
+                    if (keyid)
+                      {
+                        log_printf ("{");
+                        dump_serial (keyid);
+                        log_printf ("} ");
+                      }
+                    if (authidsn)
+                      {
+                        log_printf ("(#");
+                        dump_serial (authidsn);
+                        log_printf ("/");
+                        dump_string (s);
+                        log_printf (") ");
+                      }
+                    log_printf ("not found\n");
                   }
                 ksba_name_release (authid);
                 xfree (authidsn);
+                xfree (keyid);
               }
             else
               crlissuer_cert = get_crlissuer_cert (ctrl, crlissuer);
Index: dirmngr/src/dirmngr.h
diff -u dirmngr/src/dirmngr.h:1.25 dirmngr/src/dirmngr.h:1.26
--- dirmngr/src/dirmngr.h:1.25	Mon Dec 13 16:16:35 2004
+++ dirmngr/src/dirmngr.h	Mon Apr 18 12:37:53 2005
@@ -148,6 +148,8 @@
 /*-- server.c --*/
 ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer);
 ksba_cert_t get_issuing_cert_local (ctrl_t ctrl, const char *issuer);
+ksba_cert_t get_cert_local_ski (ctrl_t ctrl,
+                                const char *name, ksba_sexp_t keyid);
 void start_command_handler (int fd);
 gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...);
 gpg_error_t dirmngr_tick (ctrl_t ctrl);
Index: dirmngr/src/server.c
diff -u dirmngr/src/server.c:1.48 dirmngr/src/server.c:1.49
--- dirmngr/src/server.c:1.48	Fri Dec  3 15:42:36 2004
+++ dirmngr/src/server.c	Mon Apr 18 12:37:53 2005
@@ -1,6 +1,6 @@
 /* dirmngr.c - LDAP access
  *	Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *      Copyright (C) 2003, 2004 g10 Code GmbH
+ *      Copyright (C) 2003, 2004, 2005 g10 Code GmbH
  *
  * This file is part of DirMngr.
  *
@@ -39,6 +39,7 @@
 #include "ocsp.h"
 #include "certcache.h"
 #include "validate.h"
+#include "misc.h"
 
 /* To avoid DoS attacks we limit the size of a certificate to
    something reasonable. */
@@ -128,7 +129,8 @@
   xfree (buf);
   if (rc)
     {
-      log_error (_("assuan_inquire failed: %s\n"), assuan_strerror (rc));
+      log_error (_("assuan_inquire(%s) failed: %s\n"),
+                 command, assuan_strerror (rc));
       return NULL;
     }
   
@@ -171,12 +173,13 @@
   return do_get_cert_local (ctrl, name, "SENDCERT");
 
 }
-
+       
 /* Ask back to return the issuing certificate for name, given as a
    regular gpgsm certificate indentificates (e.g. fingerprint or one
    of the other methods).  Alternatively, NULL may be used for NAME to
    return thecurrent target certificate. Either return the certificate
    in a KSBA object or NULL if it is not available.
+   
 */
 ksba_cert_t 
 get_issuing_cert_local (ctrl_t ctrl, const char *name)
@@ -189,6 +192,76 @@
   return do_get_cert_local (ctrl, name, "SENDISSUERCERT");
 }
 
+/* Ask back to return a certificate with subject NAME and a
+   subjectKeyIdentifier of KEYID. */
+ksba_cert_t 
+get_cert_local_ski (ctrl_t ctrl, const char *name, ksba_sexp_t keyid)
+{
+  unsigned char *value;
+  size_t valuelen; 
+  int rc;
+  char *buf;
+  ksba_cert_t cert;
+  char *hexkeyid;
+
+  if (!ctrl || !ctrl->server_local->assuan_ctx)
+    {
+      log_debug ("get_cert_local_ski called w/o context\n");
+      return NULL;
+    }
+  if (!name || !keyid)
+    {
+      log_debug ("get_cert_local_ski called with insufficient arguments\n");
+      return NULL;
+    }
+
+  hexkeyid = serial_hex (keyid);
+  if (!hexkeyid)
+    {
+      log_debug ("serial_hex() failed\n");
+      return NULL;
+    }
+
+  buf = xtrymalloc (15 + strlen (hexkeyid) + 2 + strlen(name) + 1);
+  if (!buf)
+    {
+
+      log_error ("can't allocate enough memory: %s\n", strerror (errno));
+      xfree (hexkeyid);
+      return NULL;
+    }
+  strcpy (stpcpy (stpcpy (stpcpy (buf, "SENDCERT_SKI "), hexkeyid)," /"),name);
+  xfree (hexkeyid);
+
+  rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
+                       &value, &valuelen, MAX_CERT_LENGTH);
+  xfree (buf);
+  if (rc)
+    {
+      log_error (_("assuan_inquire(%s) failed: %s\n"), "SENDCERT_SKI",
+                 assuan_strerror (rc));
+      return NULL;
+    }
+  
+  if (!valuelen)
+    {
+      xfree (value);
+      return NULL;
+    }
+
+  rc = ksba_cert_new (&cert);
+  if (!rc)
+    {
+      rc = ksba_cert_init_from_mem (cert, value, valuelen);
+      if (rc)
+        {
+          ksba_cert_release (cert);
+          cert = NULL;
+        }
+    }
+  xfree (value);
+  return cert;
+}
 
 
 
Index: dirmngr/src/validate.c
diff -u dirmngr/src/validate.c:1.7 dirmngr/src/validate.c:1.8
--- dirmngr/src/validate.c:1.7	Wed Dec 15 23:11:59 2004
+++ dirmngr/src/validate.c	Mon Apr 18 12:37:53 2005
@@ -471,7 +471,7 @@
         }
 
       /* Now check the signature of the certificate.  Well, we
-         shouldnot delay this until later so that faked certificates
+         should 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