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):
- ocsp.c:check_signature is called to verify the signature of an OCSP response.
- 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.
- 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");