dirmngr: Allow for other hash algorithms than SHA-1 in OCSP.

* dirmngr/ocsp.c (do_ocsp_request): Remove arg md.  Add args r_sigval,
r_produced_at, and r_md.  Get the hash algo from the signature and
create the context here.
(check_signature): Allow any hash algo.  Print a diagnostic if the
signature does not verify.
--

GnuPG-bug-id: 3966
Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-05-28 12:27:00 +02:00
parent 582dee2418
commit 5281ecbe3a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
1 changed files with 80 additions and 25 deletions

View File

@ -116,10 +116,15 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
/* Construct an OCSP request, send it to the configured OCSP responder /* Construct an OCSP request, send it to the configured OCSP responder
and parse the response. On success the OCSP context may be used to and parse the response. On success the OCSP context may be used to
further process the response. */ further process the response. The signature value and the
production date are returned at R_SIGVAL and R_PRODUCED_AT; they
may be NULL or an empty string if not available. A new hash
context is returned at R_MD. */
static gpg_error_t static gpg_error_t
do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert) const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert,
ksba_sexp_t *r_sigval, ksba_isotime_t r_produced_at,
gcry_md_hd_t *r_md)
{ {
gpg_error_t err; gpg_error_t err;
unsigned char *request, *response; unsigned char *request, *response;
@ -132,6 +137,10 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
(void)ctrl; (void)ctrl;
*r_sigval = NULL;
*r_produced_at = 0;
*r_md = NULL;
if (dirmngr_use_tor ()) if (dirmngr_use_tor ())
{ {
/* For now we do not allow OCSP via Tor due to possible privacy /* For now we do not allow OCSP via Tor due to possible privacy
@ -263,6 +272,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
xfree (free_this); xfree (free_this);
return err; return err;
} }
/* log_printhex (response, responselen, "ocsp response"); */
err = ksba_ocsp_parse_response (ocsp, response, responselen, err = ksba_ocsp_parse_response (ocsp, response, responselen,
&response_status); &response_status);
@ -290,11 +300,34 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
} }
if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS) if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS)
{ {
int hash_algo;
if (opt.verbose) if (opt.verbose)
log_info (_("OCSP responder at '%s' status: %s\n"), url, t); log_info (_("OCSP responder at '%s' status: %s\n"), url, t);
/* Get the signature value now because we can all this fucntion
* only once. */
*r_sigval = ksba_ocsp_get_sig_val (ocsp, r_produced_at);
hash_algo = hash_algo_from_sigval (*r_sigval);
if (!hash_algo)
{
if (opt.verbose)
log_info ("ocsp: using SHA-256 as fallback hash algo.\n");
hash_algo = GCRY_MD_SHA256;
}
err = gcry_md_open (r_md, hash_algo, 0);
if (err)
{
log_error (_("failed to establish a hashing context for OCSP: %s\n"),
gpg_strerror (err));
goto leave;
}
if (DBG_HASHING)
gcry_md_debug (*r_md, "ocsp");
err = ksba_ocsp_hash_response (ocsp, response, responselen, err = ksba_ocsp_hash_response (ocsp, response, responselen,
HASH_FNC, md); HASH_FNC, *r_md);
if (err) if (err)
log_error (_("hashing the OCSP response for '%s' failed: %s\n"), log_error (_("hashing the OCSP response for '%s' failed: %s\n"),
url, gpg_strerror (err)); url, gpg_strerror (err));
@ -305,8 +338,17 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
err = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
} }
leave:
xfree (response); xfree (response);
xfree (free_this); xfree (free_this);
if (err)
{
xfree (*r_sigval);
*r_sigval = NULL;
*r_produced_at = 0;
gcry_md_close (*r_md);
*r_md = NULL;
}
return err; return err;
} }
@ -391,7 +433,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
/* We simply ignore all errors. */ /* We simply ignore all errors. */
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
return -1; return err;
} }
@ -410,18 +452,27 @@ check_signature (ctrl_t ctrl,
int algo, cert_idx; int algo, cert_idx;
gcry_sexp_t s_hash; gcry_sexp_t s_hash;
ksba_cert_t cert; ksba_cert_t cert;
const char *s;
/* Create a suitable S-expression with the hash value of our response. */ /* Create a suitable S-expression with the hash value of our response. */
gcry_md_final (md); gcry_md_final (md);
algo = gcry_md_get_algo (md); algo = gcry_md_get_algo (md);
if (algo != GCRY_MD_SHA1 ) s = gcry_md_algo_name (algo);
if (algo && s && strlen (s) < 16)
{ {
log_error (_("only SHA-1 is supported for OCSP responses\n")); char hashalgostr[16+1];
return gpg_error (GPG_ERR_DIGEST_ALGO); int i;
for (i=0; s[i]; i++)
hashalgostr[i] = ascii_tolower (s[i]);
hashalgostr[i] = 0;
err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
hashalgostr,
(int)gcry_md_get_algo_dlen (algo),
gcry_md_read (md, algo));
} }
err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))", else
gcry_md_get_algo_dlen (algo), err = gpg_error (GPG_ERR_DIGEST_ALGO);
gcry_md_read (md, algo));
if (err) if (err)
{ {
log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err)); log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
@ -465,6 +516,7 @@ check_signature (ctrl_t ctrl,
{ {
cert_ref_t cref; cert_ref_t cref;
/* dump_cert ("from ocsp response", cert); */
cref = xtrymalloc (sizeof *cref); cref = xtrymalloc (sizeof *cref);
if (!cref) if (!cref)
log_error (_("allocating list item failed: %s\n"), log_error (_("allocating list item failed: %s\n"),
@ -500,8 +552,6 @@ check_signature (ctrl_t ctrl,
} }
log_printf ("not found\n"); log_printf ("not found\n");
} }
ksba_free (name);
ksba_free (keyid);
if (cert) if (cert)
{ {
@ -510,10 +560,24 @@ check_signature (ctrl_t ctrl,
ksba_cert_release (cert); ksba_cert_release (cert);
if (!err) if (!err)
{ {
ksba_free (name);
ksba_free (keyid);
gcry_sexp_release (s_hash); gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */ return 0; /* Successfully verified the signature. */
} }
log_error ("responder certificate ");
if (name)
log_printf ("'/%s' ", name);
if (keyid)
{
log_printf ("{");
dump_serial (keyid);
log_printf ("} ");
}
log_printf ("did not verify: %s\n", gpg_strerror (err));
} }
ksba_free (name);
ksba_free (keyid);
} }
gcry_sexp_release (s_hash); gcry_sexp_release (s_hash);
@ -588,8 +652,6 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
goto leave; goto leave;
} }
/* Figure out the OCSP responder to use. /* Figure out the OCSP responder to use.
1. Try to get the reponder from the certificate. 1. Try to get the reponder from the certificate.
We do only take http and https style URIs into account. We do only take http and https style URIs into account.
@ -646,14 +708,8 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
} }
/* Ask the OCSP responder. */ /* Ask the OCSP responder. */
err = gcry_md_open (&md, GCRY_MD_SHA1, 0); err = do_ocsp_request (ctrl, ocsp, url, cert, issuer_cert,
if (err) &sigval, produced_at, &md);
{
log_error (_("failed to establish a hashing context for OCSP: %s\n"),
gpg_strerror (err));
goto leave;
}
err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
if (err) if (err)
goto leave; goto leave;
@ -685,8 +741,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
} }
/* We got a useful answer, check that the answer has a valid signature. */ /* We got a useful answer, check that the answer has a valid signature. */
sigval = ksba_ocsp_get_sig_val (ocsp, produced_at); if (!sigval || !*produced_at || !md)
if (!sigval || !*produced_at)
{ {
err = gpg_error (GPG_ERR_INV_OBJ); err = gpg_error (GPG_ERR_INV_OBJ);
goto leave; goto leave;