diff options
author | Werner Koch <[email protected]> | 2022-11-15 07:53:41 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2022-11-15 09:47:31 +0000 |
commit | 502d43ac30316fa6c0dc99f8e300d80e72a29071 (patch) | |
tree | 4d2f035128a17bb04fbe5dbf04ae191c67064ea3 | |
parent | gpgsm: Support signing using ECDSA. (diff) | |
download | gnupg-502d43ac30316fa6c0dc99f8e300d80e72a29071.tar.gz gnupg-502d43ac30316fa6c0dc99f8e300d80e72a29071.zip |
dirmngr: Support ECDSA for CRLs
* dirmngr/crlcache.c (finish_sig_check): Support ECDSA.
* dirmngr/validate.c (check_cert_sig): Ditto. Remove the never
used support for DSA.
(cherry picked from commit de87c8e1ead72ea67789ffa4375f9dd3e4f9e2fa)
-rw-r--r-- | dirmngr/crlcache.c | 61 | ||||
-rw-r--r-- | dirmngr/validate.c | 65 |
2 files changed, 114 insertions, 12 deletions
diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 238036903..29b8a06da 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -1625,8 +1625,21 @@ start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo, int *use_pss) } else *algo = gcry_md_map_name (algoid); + if (!*algo && algoid) + { + if (!strcmp (algoid, "1.2.840.10045.4.3.1")) + *algo = GCRY_MD_SHA224; /* ecdsa-with-sha224 */ + else if (!strcmp (algoid, "1.2.840.10045.4.3.2")) + *algo = GCRY_MD_SHA256; /* ecdsa-with-sha256 */ + else if (!strcmp (algoid, "1.2.840.10045.4.3.3")) + *algo = GCRY_MD_SHA384; /* ecdsa-with-sha384 */ + else if (!strcmp (algoid, "1.2.840.10045.4.3.4")) + *algo = GCRY_MD_SHA512; /* ecdsa-with-sha512 */ + } if (!*algo) { + log_debug ("XXXXX %s: %s <%s>\n", + __func__, gpg_strerror (err), gpg_strsource (err)); log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?"); return gpg_error (GPG_ERR_DIGEST_ALGO); } @@ -1660,6 +1673,7 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo, size_t n; gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL; unsigned int saltlen = 0; /* (used only with use_pss) */ + int pkalgo; /* This also stops debugging on the MD. */ gcry_md_final (md); @@ -1784,6 +1798,53 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo, gcry_md_read (md, algo), saltlen); } + else if ((pkalgo = 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"), + gcry_pk_algo_name (pkalgo), qbits0); + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + + /* Check if we're too short. */ + n = gcry_md_get_algo_dlen (algo); + if (n < qbits/8) + { + log_error (_("a %u bit hash is not valid for a %u bit %s key\n"), + (unsigned int)n*8, + qbits0, + gcry_pk_algo_name (pkalgo)); + if (n < 20) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + } + + /* Truncate. */ + if (n > qbits/8) + n = qbits/8; + + err = gcry_sexp_build (&s_hash, NULL, "%b", + (int)n, + gcry_md_read (md, algo)); + } else { err = gcry_sexp_build (&s_hash, NULL, diff --git a/dirmngr/validate.c b/dirmngr/validate.c index 901c165ec..103e82a45 100644 --- a/dirmngr/validate.c +++ b/dirmngr/validate.c @@ -231,7 +231,8 @@ allowed_ca (ksba_cert_t cert, int *chainlen) /* The German SigG Root CA's certificate does not flag itself as a CA; thus we relax this requirement if we trust a root CA. I think this is reasonable. Note, that - gpgsm implements a far stricter scheme here. */ + gpgsm implements a far stricter scheme here but also + features a "relax" flag in the trustlist.txt. */ if (chainlen) *chainlen = 3; /* That is what the SigG implements. */ if (opt.verbose) @@ -952,15 +953,24 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) int digestlen; unsigned char *digest; int use_pss = 0; - unsigned int saltlen; + unsigned int saltlen; /* (use is controlled by use_pss) */ /* Hash the target certificate using the algorithm from that certificate. */ algoid = ksba_cert_get_digest_algo (cert); algo = gcry_md_map_name (algoid); if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10")) use_pss = 1; + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.1")) + algo = GCRY_MD_SHA224; /* ecdsa-with-sha224 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.2")) + algo = GCRY_MD_SHA256; /* ecdsa-with-sha256 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.3")) + algo = GCRY_MD_SHA384; /* ecdsa-with-sha384 */ + else if (!algo && algoid && !strcmp (algoid, "1.2.840.10045.4.3.4")) + algo = GCRY_MD_SHA512; /* ecdsa-with-sha512 */ else if (!algo) { + log_debug ("XXXXX %s\n", __func__); log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?"); return gpg_error (GPG_ERR_GENERAL); } @@ -1106,19 +1116,48 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) digest, saltlen); } - else if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA) + else if (pk_algo_from_sexp (s_pkey) == GCRY_PK_ECC) { - /* NB.: We support only SHA-1 here because we had problems back - * then to get test data for DSA-2. Meanwhile DSA has been - * replaced by ECDSA which we do not yet support. */ - if (digestlen != 20) + 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 (digestlen < qbits/8) { - log_error ("DSA requires the use of a 160 bit hash algorithm\n"); - gcry_md_close (md); - gcry_sexp_release (s_sig); - gcry_sexp_release (s_pkey); - return gpg_error (GPG_ERR_INTERNAL); + log_error (_("a %u bit hash is not valid for a %u bit %s key\n"), + (unsigned int)digestlen*8, + qbits0, + "ECDSA"); + if (digestlen < 20) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } } + + /* Truncate. */ + if (digestlen > qbits/8) + digestlen = qbits/8; + err = gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))", (int)digestlen, digest); } @@ -1132,6 +1171,8 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) err = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (err)); + + leave: gcry_md_close (md); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); |