]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/dnssec: conditionally ignore SHA1 DS, as SHOULD by RFC4509
authorVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 20 Jan 2022 18:43:40 +0000 (19:43 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 4 Feb 2022 14:31:56 +0000 (15:31 +0100)
We're a bit late with this ad-hoc rule; I think it was most useful
when SHA256 support in DS algorithms wasn't wide-spread yet.
(Note that DNSKEY algos have standardized no similar rule.)

Usage of SHA1 as DS algorithm is highly discouraged, but even at this
point it does *not* seem unsafe, in the sense of anyone publishing an
attack that would come anywhere close to breaking *this* usage of SHA1.

NEWS
lib/dnssec/signature.c

diff --git a/NEWS b/NEWS
index 4e6b0daa0886909c2f8827a933e6e8cb09ebda61..3cefde1b6fdb24a22b70e57c86419b704dae57ba 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Improvements
 - policy: log policy actions; useful for RPZ debugging (!1239)
 - policy: new action policy.IPTRACE for logging request origin (!1239)
 - prefill module: prepare for ZONEMD, improve performance (!1225)
+- validator: conditionally ignore SHA1 DS, as SHOULD by RFC4509 (!1251)
 
 Incompatible changes
 --------------------
index 6fcf3a42d0acbfc9181603aac3fab13e7db9b6e0..062067a0b969f52586334fe8e040c9da688df306 100644 (file)
@@ -47,18 +47,34 @@ int kr_authenticate_referral(const knot_rrset_t *ref, const dnssec_key_t *key)
        if (ref->type != KNOT_RRTYPE_DS)
                return kr_error(EINVAL);
 
-       /* Try all possible DS records */
-       int ret = 0;
+       /* Determine whether to ignore SHA1 digests, because:
+           https://datatracker.ietf.org/doc/html/rfc4509#section-3
+        * Now, the RFCs seem to only mention SHA1 and SHA256 (e.g. no SHA384),
+        * but the most natural extension is to make any other algorithm trump SHA1.
+        * (Note that the old GOST version is already unsupported by libdnssec.) */
+       bool skip_sha1 = false;
        knot_rdata_t *rd = ref->rrs.rdata;
-       for (uint16_t i = 0; i < ref->rrs.count; ++i) {
+       for (int i = 0; i < ref->rrs.count; ++i, rd = knot_rdataset_next(rd)) {
+               const uint8_t algo = knot_ds_digest_type(rd);
+               if (algo != DNSSEC_KEY_DIGEST_SHA1 && dnssec_algorithm_digest_support(algo)) {
+                       skip_sha1 = true;
+                       break;
+               }
+       }
+       /* But otherwise try all possible DS records. */
+       int ret = 0;
+       rd = ref->rrs.rdata;
+       for (int i = 0; i < ref->rrs.count; ++i, rd = knot_rdataset_next(rd)) {
+               const uint8_t algo = knot_ds_digest_type(rd);
+               if (skip_sha1 && algo == DNSSEC_KEY_DIGEST_SHA1)
+                       continue;
                dnssec_binary_t ds_rdata = {
                        .size = rd->len,
                        .data = rd->data
                };
-               ret = authenticate_ds(key, &ds_rdata, knot_ds_digest_type(rd));
+               ret = authenticate_ds(key, &ds_rdata, algo);
                if (ret == 0) /* Found a good DS */
                        return kr_ok();
-               rd = knot_rdataset_next(rd);
        }
 
        return kr_error(ret);