]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
zonemd, fix to detect duplicate zonemd scheme and algo RRs.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Jan 2021 13:36:53 +0000 (14:36 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Jan 2021 13:36:53 +0000 (14:36 +0100)
services/authzone.c
testcode/unitzonemd.c
testdata/zonemd.example16.zone [new file with mode: 0644]

index b5b50c92c9b71254c57a57078ee4f104d0d8592b..4c31452a612929e92c747911d10240bf8d8e7f82 100644 (file)
@@ -1823,6 +1823,43 @@ static int zonemd_fetch_parameters(struct auth_rrset* zonemd_rrset, size_t i,
        return 1;
 }
 
+/**
+ * See if the ZONEMD scheme, hash occurs more than once.
+ * @param zonemd_rrset: the zonemd rrset to check with the RRs in it.
+ * @param index: index of the original, this is allowed to have that
+ *     scheme and hashalgo, but other RRs should not have it.
+ * @param scheme: the scheme to check for.
+ * @param hashalgo: the hash algorithm to check for.
+ * @return true if it occurs more than once.
+ */
+static int zonemd_is_duplicate_scheme_hash(struct auth_rrset* zonemd_rrset,
+       size_t index, int scheme, int hashalgo)
+{
+       size_t j;
+       for(j=0; j<zonemd_rrset->data->count; j++) {
+               uint32_t serial2 = 0;
+               int scheme2 = 0, hashalgo2 = 0;
+               uint8_t* hash2 = NULL;
+               size_t hashlen2 = 0;
+               if(index == j) {
+                       /* this is the original */
+                       continue;
+               }
+               if(!zonemd_fetch_parameters(zonemd_rrset, j, &serial2,
+                       &scheme2, &hashalgo2, &hash2, &hashlen2)) {
+                       /* malformed, skip it */
+                       continue;
+               }
+               if(scheme == scheme2 && hashalgo == hashalgo2) {
+                       /* duplicate scheme, hash */
+                       verbose(VERB_ALGO, "zonemd duplicate for scheme %d "
+                               "and hash %d", scheme, hashalgo);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 /**
  * Check ZONEMDs if present for the auth zone.  Depending on config
  * it can warn or fail on that.  Checks the hash of the ZONEMD.
@@ -1875,6 +1912,15 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
                        *reason = "ZONEMD rdata malformed";
                        continue;
                }
+               /* check for duplicates */
+               if(zonemd_is_duplicate_scheme_hash(zonemd_rrset, i, scheme,
+                       hashalgo)) {
+                       /* duplicate hash of the same scheme,hash
+                        * is not allowed. */
+                       *reason = "ZONEMD RRSet contains more than one RR "
+                               "with the same scheme and hash algorithm";
+                       continue;
+               }
                regional_free_all(region);
                if(serial != soa_serial) {
                        *reason = "ZONEMD serial is wrong";
@@ -7381,7 +7427,7 @@ static void add_rrlist_rrsigs_into_data(struct packed_rrset_data* data,
                        data->rr_len[*done] = rrlist[i]->data->rr_len[rrlist[i]->data->count + j];
                        data->rr_ttl[*done] = rrlist[i]->data->rr_ttl[rrlist[i]->data->count + j];
                        /* reference the rdata in the rrset, no need to
-                        * copy it, it is no longer need at the end of
+                        * copy it, it is no longer needed at the end of
                         * the routine */
                        data->rr_data[*done] = rrlist[i]->data->rr_data[rrlist[i]->data->count + j];
                        (*done)++;
index 82ab9076d19b60312c7cb0e3cda0f7e7afc640e7..07f97c316e4df74864e8f9f6cb6a4e96fd321f1e 100644 (file)
@@ -467,6 +467,13 @@ static void zonemd_verify_tests(void)
                /* okay date: "20201020135527", */
                "20221020135527",
                "verify DNSKEY RRset with trust anchor failed: signature expired");
+
+       /* duplicate zonemd with same scheme and algorithm */
+       zonemd_verify_test("example.com",
+               "testdata/zonemd.example16.zone",
+               NULL,
+               "20180302005009",
+               "ZONEMD RRSet contains more than one RR with the same scheme and hash algorithm");
 }
 
 /** zonemd unit tests */
diff --git a/testdata/zonemd.example16.zone b/testdata/zonemd.example16.zone
new file mode 100644 (file)
index 0000000..7520744
--- /dev/null
@@ -0,0 +1,11 @@
+example.com. IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600
+example.com. IN NS ns.example.com.
+; the ZONEMD that should be in this file, without DNSSEC
+example.com. IN ZONEMD 200154054 1 2 EFAA5B78B38AB1C45DE57B8167BCCE906451D0E72118E1F5E80B5F0C3CF04BFFC65D53C011185528EAD439D6F3A02F511961E090E5E4E0DFA013BD276D728B22
+; duplicate zonemd with same scheme and algorithm (different at end)
+example.com. IN ZONEMD 200154054 1 2 EFAA5B78B38AB1C45DE57B8167BCCE906451D0E72118E1F5E80B5F0C3CF04BFFC65D53C011185528EAD439D6F3A02F511961E090E5E4E0DFA013BD276D720000
+www.example.com. IN A 127.0.0.1
+ns.example.com. IN A 127.0.0.1
+bar.example.com. IN A 1.2.3.4
+ding.example.com. IN A 1.2.3.4
+foo.example.com. IN A 1.2.3.4