summaryrefslogtreecommitdiffstats
path: root/dirmngr/ocsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'dirmngr/ocsp.c')
-rw-r--r--dirmngr/ocsp.c153
1 files changed, 104 insertions, 49 deletions
diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c
index 3483ab9..5462449 100644
--- a/dirmngr/ocsp.c
+++ b/dirmngr/ocsp.c
@@ -224,7 +224,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
case 301:
case 302:
{
- const char *s = http_get_header (http, "Location");
+ const char *s = http_get_header (http, "Location", 0);
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
url, s?s:"[none]", http_get_status_code (http));
@@ -406,32 +406,115 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
}
-/* Helper for check_signature. */
-static int
+/* Helper for check_signature. MD is the finalized hash context. */
+static gpg_error_t
check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
- gcry_sexp_t s_hash, fingerprint_list_t signer_fpr_list)
+ gcry_md_hd_t md, fingerprint_list_t signer_fpr_list)
{
gpg_error_t err;
- ksba_sexp_t pubkey;
gcry_sexp_t s_pkey = NULL;
+ gcry_sexp_t s_hash = NULL;
+ const char *s;
+ int mdalgo, mdlen;
+
+ /* Get the public key as a gcrypt s-expression. */
+ {
+ ksba_sexp_t pk = ksba_cert_get_public_key (cert);
+ if (!pk)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ else
+ {
+ err = canon_sexp_to_gcry (pk, &s_pkey);
+ xfree (pk);
+ }
+ if (err)
+ goto leave;
+ }
+
+ mdalgo = gcry_md_get_algo (md);
+ mdlen = gcry_md_get_algo_dlen (mdalgo);
+
+ if (pk_algo_from_sexp (s_pkey) == GCRY_PK_ECC)
+ {
+ unsigned int qbits0, qbits;
+
+ qbits0 = gcry_pk_get_nbits (s_pkey);
+ qbits = qbits0 == 521? 512 : qbits0;
+
+ if ((qbits%8))
+ {
+ log_error ("ECDSA requires the hash length to be a"
+ " multiple of 8 bits\n");
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+
+ /* Don't allow any Q smaller than 160 bits. */
+ if (qbits < 160)
+ {
+ log_error (_("%s key uses an unsafe (%u bit) hash\n"),
+ "ECDSA", qbits0);
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+
+ /* Check if we're too short. */
+ if (mdlen < qbits/8)
+ {
+ log_error (_("a %u bit hash is not valid for a %u bit %s key\n"),
+ (unsigned int)mdlen*8,
+ qbits0,
+ "ECDSA");
+ if (mdlen < 20)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+ }
+
+ /* Truncate. */
+ if (mdlen > qbits/8)
+ mdlen = qbits/8;
+
+ err = gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))",
+ (int)mdlen, gcry_md_read (md, mdalgo));
+ }
+ else if (mdalgo && (s = gcry_md_algo_name (mdalgo)) && strlen (s) < 16)
+ {
+ /* Assume RSA */
+ char hashalgostr[16+1];
+ int i;
- pubkey = ksba_cert_get_public_key (cert);
- if (!pubkey)
- err = gpg_error (GPG_ERR_INV_OBJ);
+ 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)mdlen,
+ gcry_md_read (md, mdalgo));
+ }
else
- err = canon_sexp_to_gcry (pubkey, &s_pkey);
- xfree (pubkey);
- if (!err)
- err = gcry_pk_verify (s_sig, s_hash, s_pkey);
- if (!err)
- err = validate_responder_cert (ctrl, cert, signer_fpr_list);
- if (!err)
+ err = gpg_error (GPG_ERR_DIGEST_ALGO);
+ if (err)
+ {
+ log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
{
- gcry_sexp_release (s_pkey);
- return 0; /* Successfully verified the signature. */
+ gcry_log_debugsxp ("sig ", s_sig);
+ gcry_log_debugsxp ("hash", s_hash);
}
- /* We simply ignore all errors. */
+ err = gcry_pk_verify (s_sig, s_hash, s_pkey);
+ if (err)
+ goto leave;
+
+ err = validate_responder_cert (ctrl, cert, signer_fpr_list);
+
+ leave:
+ gcry_sexp_release (s_hash);
gcry_sexp_release (s_pkey);
return err;
}
@@ -449,35 +532,11 @@ check_signature (ctrl_t ctrl,
fingerprint_list_t signer_fpr_list)
{
gpg_error_t err;
- int algo, cert_idx;
- gcry_sexp_t s_hash;
+ int cert_idx;
ksba_cert_t cert;
- const char *s;
/* Create a suitable S-expression with the hash value of our response. */
gcry_md_final (md);
- algo = gcry_md_get_algo (md);
- s = gcry_md_algo_name (algo);
- if (algo && s && strlen (s) < 16)
- {
- char hashalgostr[16+1];
- 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));
- }
- else
- err = gpg_error (GPG_ERR_DIGEST_ALGO);
- if (err)
- {
- log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
- return err;
- }
/* Get rid of old OCSP specific certificate references. */
release_ctrl_ocsp_certs (ctrl);
@@ -492,13 +551,12 @@ check_signature (ctrl_t ctrl,
cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
if (cert)
{
- err = check_signature_core (ctrl, cert, s_sig, s_hash,
+ err = check_signature_core (ctrl, cert, s_sig, md,
signer_fpr_list);
ksba_cert_release (cert);
cert = NULL;
if (!err)
{
- gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */
}
}
@@ -558,14 +616,12 @@ check_signature (ctrl_t ctrl,
if (cert)
{
- err = check_signature_core (ctrl, cert, s_sig, s_hash,
- signer_fpr_list);
+ err = check_signature_core (ctrl, cert, s_sig, md, signer_fpr_list);
ksba_cert_release (cert);
if (!err)
{
ksba_free (name);
ksba_free (keyid);
- gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */
}
log_error ("responder certificate ");
@@ -583,7 +639,6 @@ check_signature (ctrl_t ctrl,
ksba_free (keyid);
}
- gcry_sexp_release (s_hash);
log_error (_("no suitable certificate found to verify the OCSP response\n"));
return gpg_error (GPG_ERR_NO_PUBKEY);
}