mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
dirmngr: Support ECDSA for OCSP.
* dirmngr/validate.c (pk_algo_from_sexp): Make public. Support ECC. * dirmngr/ocsp.c (check_signature): Remove hash preparation out to ... (check_signature_core): here. This changes the arg s_hash to md. Support ECDSA. -- The test was done with my qualified signature certificate from the Telesec and their responder http://tqrca1.ocsp.telesec.de/ocspr . See also libksba commit rK24992a4a7a61d93759e1dbd104b845903d4589bf
This commit is contained in:
parent
335805e1d4
commit
890e9849b5
147
dirmngr/ocsp.c
147
dirmngr/ocsp.c
@ -406,32 +406,112 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helper for check_signature. */
|
/* Helper for check_signature. MD is the finalized hash context. */
|
||||||
static int
|
static gpg_error_t
|
||||||
check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
|
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;
|
gpg_error_t err;
|
||||||
ksba_sexp_t pubkey;
|
|
||||||
gcry_sexp_t s_pkey = NULL;
|
gcry_sexp_t s_pkey = NULL;
|
||||||
|
gcry_sexp_t s_hash = NULL;
|
||||||
|
const char *s;
|
||||||
|
int mdalgo, mdlen;
|
||||||
|
|
||||||
pubkey = ksba_cert_get_public_key (cert);
|
/* Get the public key as a gcrypt s-expression. */
|
||||||
if (!pubkey)
|
{
|
||||||
|
ksba_sexp_t pk = ksba_cert_get_public_key (cert);
|
||||||
|
if (!pk)
|
||||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||||
else
|
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)
|
|
||||||
{
|
{
|
||||||
gcry_sexp_release (s_pkey);
|
err = canon_sexp_to_gcry (pk, &s_pkey);
|
||||||
return 0; /* Successfully verified the signature. */
|
xfree (pk);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We simply ignore all errors. */
|
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;
|
||||||
|
|
||||||
|
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 = gpg_error (GPG_ERR_DIGEST_ALGO);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_log_debugsxp ("sig ", s_sig);
|
||||||
|
gcry_log_debugsxp ("hash", s_hash);
|
||||||
|
|
||||||
|
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);
|
gcry_sexp_release (s_pkey);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -449,35 +529,11 @@ check_signature (ctrl_t ctrl,
|
|||||||
fingerprint_list_t signer_fpr_list)
|
fingerprint_list_t signer_fpr_list)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
int algo, cert_idx;
|
int cert_idx;
|
||||||
gcry_sexp_t s_hash = NULL;
|
|
||||||
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);
|
|
||||||
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. */
|
/* Get rid of old OCSP specific certificate references. */
|
||||||
release_ctrl_ocsp_certs (ctrl);
|
release_ctrl_ocsp_certs (ctrl);
|
||||||
@ -492,13 +548,12 @@ check_signature (ctrl_t ctrl,
|
|||||||
cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
|
cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
|
||||||
if (cert)
|
if (cert)
|
||||||
{
|
{
|
||||||
err = check_signature_core (ctrl, cert, s_sig, s_hash,
|
err = check_signature_core (ctrl, cert, s_sig, md,
|
||||||
signer_fpr_list);
|
signer_fpr_list);
|
||||||
ksba_cert_release (cert);
|
ksba_cert_release (cert);
|
||||||
cert = NULL;
|
cert = NULL;
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
gcry_sexp_release (s_hash);
|
|
||||||
return 0; /* Successfully verified the signature. */
|
return 0; /* Successfully verified the signature. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,7 +589,6 @@ check_signature (ctrl_t ctrl,
|
|||||||
err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
|
err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
gcry_sexp_release (s_hash);
|
|
||||||
log_error (_("error getting responder ID: %s\n"),
|
log_error (_("error getting responder ID: %s\n"),
|
||||||
gcry_strerror (err));
|
gcry_strerror (err));
|
||||||
return err;
|
return err;
|
||||||
@ -556,14 +610,12 @@ check_signature (ctrl_t ctrl,
|
|||||||
|
|
||||||
if (cert)
|
if (cert)
|
||||||
{
|
{
|
||||||
err = check_signature_core (ctrl, cert, s_sig, s_hash,
|
err = check_signature_core (ctrl, cert, s_sig, md, signer_fpr_list);
|
||||||
signer_fpr_list);
|
|
||||||
ksba_cert_release (cert);
|
ksba_cert_release (cert);
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
ksba_free (name);
|
ksba_free (name);
|
||||||
ksba_free (keyid);
|
ksba_free (keyid);
|
||||||
gcry_sexp_release (s_hash);
|
|
||||||
return 0; /* Successfully verified the signature. */
|
return 0; /* Successfully verified the signature. */
|
||||||
}
|
}
|
||||||
log_error ("responder certificate ");
|
log_error ("responder certificate ");
|
||||||
@ -581,7 +633,6 @@ check_signature (ctrl_t ctrl,
|
|||||||
ksba_free (keyid);
|
ksba_free (keyid);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_sexp_release (s_hash);
|
|
||||||
log_error (_("no suitable certificate found to verify the OCSP response\n"));
|
log_error (_("no suitable certificate found to verify the OCSP response\n"));
|
||||||
return gpg_error (GPG_ERR_NO_PUBKEY);
|
return gpg_error (GPG_ERR_NO_PUBKEY);
|
||||||
}
|
}
|
||||||
|
@ -858,7 +858,7 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
|||||||
/* Return the public key algorithm id from the S-expression PKEY.
|
/* Return the public key algorithm id from the S-expression PKEY.
|
||||||
FIXME: libgcrypt should provide such a function. Note that this
|
FIXME: libgcrypt should provide such a function. Note that this
|
||||||
implementation uses the names as used by libksba. */
|
implementation uses the names as used by libksba. */
|
||||||
static int
|
int
|
||||||
pk_algo_from_sexp (gcry_sexp_t pkey)
|
pk_algo_from_sexp (gcry_sexp_t pkey)
|
||||||
{
|
{
|
||||||
gcry_sexp_t l1, l2;
|
gcry_sexp_t l1, l2;
|
||||||
@ -879,6 +879,8 @@ pk_algo_from_sexp (gcry_sexp_t pkey)
|
|||||||
algo = GCRY_PK_RSA;
|
algo = GCRY_PK_RSA;
|
||||||
else if (n==3 && !memcmp (name, "dsa", 3))
|
else if (n==3 && !memcmp (name, "dsa", 3))
|
||||||
algo = GCRY_PK_DSA;
|
algo = GCRY_PK_DSA;
|
||||||
|
else if (n==3 && !memcmp (name, "ecc", 3))
|
||||||
|
algo = GCRY_PK_ECC;
|
||||||
else if (n==13 && !memcmp (name, "ambiguous-rsa", 13))
|
else if (n==13 && !memcmp (name, "ambiguous-rsa", 13))
|
||||||
algo = GCRY_PK_RSA;
|
algo = GCRY_PK_RSA;
|
||||||
else
|
else
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
#define VALIDATE_FLAG_NOCRLCHECK 1024
|
#define VALIDATE_FLAG_NOCRLCHECK 1024
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper to get the public key algo from a public key. */
|
||||||
|
int pk_algo_from_sexp (gcry_sexp_t pkey);
|
||||||
|
|
||||||
/* Validate the certificate CHAIN up to the trust anchor. Optionally
|
/* Validate the certificate CHAIN up to the trust anchor. Optionally
|
||||||
return the closest expiration time in R_EXPTIME. */
|
return the closest expiration time in R_EXPTIME. */
|
||||||
gpg_error_t validate_cert_chain (ctrl_t ctrl,
|
gpg_error_t validate_cert_chain (ctrl_t ctrl,
|
||||||
|
@ -1670,6 +1670,8 @@ Description of some debug flags:
|
|||||||
- RFC-5280 :: X.509 PKI Certificate and CRL Profile
|
- RFC-5280 :: X.509 PKI Certificate and CRL Profile
|
||||||
- RFC-5652 :: CMS (STD0070)
|
- RFC-5652 :: CMS (STD0070)
|
||||||
- RFC-6818 :: Updates to the X.509 PKI Certificate and CRL Profile
|
- RFC-6818 :: Updates to the X.509 PKI Certificate and CRL Profile
|
||||||
|
- RFC-6960 :: Online Certificate Status Protocol - OCSP
|
||||||
|
- RFC-8954 :: Online Certificate Status Protocol (OCSP) Nonce Extension
|
||||||
- RFC-8398 :: Internationalized Email Addresses in X.509 Certificates.
|
- RFC-8398 :: Internationalized Email Addresses in X.509 Certificates.
|
||||||
- RFC-8399 :: Internationalization Updates to RFC 5280
|
- RFC-8399 :: Internationalization Updates to RFC 5280
|
||||||
- RFC-5480 :: ECC Subject Public Key Information
|
- RFC-5480 :: ECC Subject Public Key Information
|
||||||
|
Loading…
x
Reference in New Issue
Block a user