dirmngr fails to find OCSP signer certificate when responder is identified with key ID
Open, NormalPublic

Description

When dirmngr does an OCSP check it fails to locate the OCSP signer certificate, even though everything is configured correctly and the certificate is present in the key database.

This issue may be related to https://dev.gnupg.org/T3966.

The problem only occurs when the OCSP response uses the byKey type in ResponseData.responderID. The byName type works correctly.

The following code flow shows the problem, assuming that no OCSP signer was specified to dirmngr (no --ocsp-signer option used):

  1. ocsp.c:check_signature is called to verify the signature of an OCSP response.
  2. ksba_ocsp_get_responder_id is called to get responder name and keyid. In this case we only get a keyid and name is NULL.
  3. find_cert_bysubject is called with keyid and the NULL name. This function assumes that name is always present (only keyid is optional). The function therefore fails to find the cert (more specifically: its call to get_cert_local_ski fails to find the cert).

The following is an example patch for solving the problem. It is provided for illustrative purposes only since it was only written for testing quick solution.

--- gnupg2-2.1.18/dirmngr/certcache.c	2016-12-08 19:09:44.000000000 +0100
+++ gnupg2-2.1.18_ocsp_fix/dirmngr/certcache.c	2019-05-23 10:27:25.445000000 +0200
@@ -682,6 +682,39 @@
   return NULL;
 }
 
+ksba_cert_t
+get_cert_byid (ksba_sexp_t keyid)
+{
+  ksba_sexp_t subjid;
+  cert_item_t ci;
+  int i;
+
+  if (!keyid)
+      return NULL;
+
+  acquire_cache_read_lock ();
+  for (i=0; i < 256; i++)
+    {
+      for (ci=cert_cache[i]; ci; ci = ci->next)
+        {
+          if (ci->cert && !ksba_cert_get_subj_key_id (ci->cert, NULL, &subjid))
+            {
+              if (!cmp_simple_canon_sexp (keyid, subjid))
+                {
+                  xfree(subjid);
+                  ksba_cert_ref (ci->cert);
+                  release_cache_lock ();
+                  return ci->cert;
+                }
+              xfree(subjid);
+            }
+        }
+    }
+
+  release_cache_lock ();
+  return NULL;
+}
+
 
 
 /* Return a value describing the the class of PATTERN.  The offset of
@@ -1154,6 +1187,11 @@
   if (cert)
     return cert; /* Done.  */
 
+  /* Attempt with keyid only if no name was present */
+  if (!subject_dn)
+      if ((cert = get_cert_byid(keyid)))
+          return cert;
+
   if (DBG_LOOKUP)
     log_debug ("find_cert_bysubject: certificate not in cache\n");
werner triaged this task as Normal priority.
werner added a subscriber: werner.May 28 2019, 12:36 PM

Do you have any test cases? Note that T3966 is due to missing support for SHA-256.

misterzed88 added a comment.EditedMay 29 2019, 9:10 AM

A high level test description is:

  1. Configure both gpgsm and dirmngr to use OCSP.
  2. Import the responder signer certificate with gpgsm --import.
  3. Use a certificate with OCSP responder extension present, or configure a default OCSP responder in dirmngr.
  4. Configure your OCSP responder to identify itself with key ID (and not subject name)
  5. Attempt to sign or verify with gpgsm.
  6. You should get an error, with dirmngr logs showing that the responder signer certificate could not be found.

Note regarding step 4: exactly how this is done depends on the responder. OpenSSL, for example, when acting as a mini-OCSP-responder server, uses the -resp_key_id option. Or, an MS CA OCSP responder, for example, has an "Online Responder Identifiers" configuration setting where "Key Hash" is one of the options.

Is this the type of test case information you are looking for? Or do you need more details?

Thanks, the mentioned OpenSSL option should be helpful.