]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Enforce NSEC3 record consistency
authorMark Andrews <marka@isc.org>
Wed, 18 Feb 2026 01:30:22 +0000 (12:30 +1100)
committerOndřej Surý <ondrej@isc.org>
Tue, 24 Feb 2026 15:31:33 +0000 (16:31 +0100)
NSEC3 hashes are required to fit within a single DNS label.  Since there
are 5 bits per label byte without pad characters, the maximum hash size
is floor(63*5/8) (39 bytes).

This patch enforces this maximum length for unknown algorithms, while
strictly enforcing the exact expected digest length for known algorithms
like SHA-1.

(cherry picked from commit 3801d0ebbf8da69077af84dae7f7ec23718b839b)

bin/tests/system/checkzone/zones/crashzone.db
lib/dns/include/dns/nsec3.h
lib/dns/rdata/generic/nsec3_50.c
lib/isc/include/isc/iterated_hash.h

index 2a62e2a09d7bb6e10bef84d7e8313f7016863fc6..169cbe331e9e56d727bec1cade4ac8ceafb7bdec 100644 (file)
@@ -47,7 +47,6 @@ FQ7RBG86KRMACA1NAAKP2KQRQALBA0C7.dyn.example.net.  7200       RRSIG   NSEC3 7 4 7200 201
                                        577WZnTQemStx+diON9rEGXAGnU7C0KLjrFL
                                        VyhocnBnNtxJS8eRMSWvb9XuYCMNhYKOurtt
                                        Ar4qh4VW1+unmA== )
-I7A7A184GGMI35K1E3IR650LKO7NOB5R.dyn.example.net. 7200 IN NSEC3        1 0 10 76931F IMQ912BREQP1POLAH3RMONG;UED541AS A RRSIG
 IMQ912BREQP1POLAH3RMONG3UED541AS.dyn.example.net. 7200 IN NSEC3        1 0 10 76931F S3USV4M1HLVJ8F88EDSG8N9PVQRQ20N7 A RRSIG
                        7200    RRSIG   NSEC3 7 4 7200 20100227180048 (
                                        20100221180048 30323 dyn.example.net.
index e4da790b060a7160c2fcc2f1e284b6ccac05b293..4a2c1e1a6139b99ccade5e4daef7d6bbc5e8df66 100644 (file)
 #define DNS_NSEC3_SALTSIZE     255
 #define DNS_NSEC3_MAXITERATIONS 150U
 
+/*
+ * The maximum hash that can be encoded in a single label using
+ * base32hexnp.  floor(63*5/8)
+ */
+#define NSEC3_MAX_HASH_LENGTH 39
+
 /*
  * hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max)
  * hash length = 1, hash = 255 (max), bitmap = 8192 + 512 (max)
index e04587bd1bbf37bb13ec52192f34d2ab8d03a6de..b42ab29a5d955b906e74920faed607332eac78db 100644 (file)
@@ -35,6 +35,8 @@
 #include <isc/base32.h>
 #include <isc/iterated_hash.h>
 
+#include <dns/nsec3.h>
+
 #define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC
 
 static isc_result_t
@@ -96,8 +98,17 @@ fromtext_nsec3(ARGS_FROMTEXT) {
                                      false));
        isc_buffer_init(&b, buf, sizeof(buf));
        RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b));
-       if (isc_buffer_usedlength(&b) > 0xffU) {
-               RETTOK(ISC_R_RANGE);
+       switch (hashalg) {
+       case dns_hash_sha1:
+               if (isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
+                       RETTOK(ISC_R_RANGE);
+               }
+               break;
+       default:
+               if (isc_buffer_usedlength(&b) > NSEC3_MAX_HASH_LENGTH) {
+                       RETTOK(ISC_R_RANGE);
+               }
+               break;
        }
        RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target));
        RETERR(mem_tobuffer(target, &buf, isc_buffer_usedlength(&b)));
@@ -184,7 +195,7 @@ totext_nsec3(ARGS_TOTEXT) {
 static isc_result_t
 fromwire_nsec3(ARGS_FROMWIRE) {
        isc_region_t sr, rr;
-       unsigned int saltlen, hashlen;
+       unsigned int hash, saltlen, hashlen;
 
        REQUIRE(type == dns_rdatatype_nsec3);
 
@@ -200,6 +211,7 @@ fromwire_nsec3(ARGS_FROMWIRE) {
        if (sr.length < 5U) {
                RETERR(DNS_R_FORMERR);
        }
+       hash = sr.base[0];
        saltlen = sr.base[4];
        isc_region_consume(&sr, 5);
 
@@ -214,8 +226,19 @@ fromwire_nsec3(ARGS_FROMWIRE) {
        hashlen = sr.base[0];
        isc_region_consume(&sr, 1);
 
-       if (hashlen < 1 || sr.length < hashlen) {
-               RETERR(DNS_R_FORMERR);
+       switch (hash) {
+       case dns_hash_sha1:
+               if (hashlen != ISC_SHA1_DIGESTLENGTH || sr.length < hashlen) {
+                       RETERR(DNS_R_FORMERR);
+               }
+               break;
+       default:
+               if (hashlen < 1 || hashlen > NSEC3_MAX_HASH_LENGTH ||
+                   sr.length < hashlen)
+               {
+                       RETERR(DNS_R_FORMERR);
+               }
+               break;
        }
        isc_region_consume(&sr, hashlen);
 
index b5d6ab676ba22bee34f0e605936eb3ddba899ea3..ea96b335e13e5b4f724d2721b40d0d314fe9c2b8 100644 (file)
 
 #include <isc/lang.h>
 
-/*
- * The maximal hash length that can be encoded in a name
- * using base32hex.  floor(255/8)*5
- */
-#define NSEC3_MAX_HASH_LENGTH 155
-
-/*
- * The maximum has that can be encoded in a single label using
- * base32hex.  floor(63/8)*5
- */
-#define NSEC3_MAX_LABEL_HASH 35
-
 ISC_LANG_BEGINDECLS
 
 int