Commit b72f858b76 for bind
commit b72f858b76946ed6ae9728d76f4e712e52681bee
Author: Alessio Podda <alessio@isc.org>
Date: Mon Aug 31 12:12:33 2026 +0200
Add dns_fixedname_fromnsec3hash
Add a function that creates a fixedname directly from the origin
and the SHA1 hash, saving intermediate copies.
diff --git a/lib/dns/fixedname.c b/lib/dns/fixedname.c
index c9c3f28d36..f8d9a49480 100644
--- a/lib/dns/fixedname.c
+++ b/lib/dns/fixedname.c
@@ -13,6 +13,9 @@
/*! \file */
+#include <isc/base32.h>
+#include <isc/util.h>
+
#include <dns/fixedname.h>
void
@@ -37,3 +40,37 @@ dns_fixedname_initname(dns_fixedname_t *fixed) {
dns_fixedname_init(fixed);
return dns_fixedname_name(fixed);
}
+
+isc_result_t
+dns_fixedname_fromnsec3hash(dns_fixedname_t *fixed, const unsigned char *hash,
+ size_t hash_length, const dns_name_t *origin) {
+ isc_region_t origin_region;
+ isc_region_t source = {
+ .base = UNCONST(hash),
+ .length = (unsigned int)hash_length,
+ };
+
+ REQUIRE(fixed != NULL);
+ REQUIRE(hash != NULL);
+ REQUIRE(DNS_NAME_VALID(origin));
+
+ isc_buffer_clear(&fixed->buffer);
+ isc_buffer_putuint8(&fixed->buffer,
+ (uint8_t)((hash_length * 8U + 4U) / 5U));
+ RETERR(isc_base32hexnp_totext(&source, -1, "", &fixed->buffer));
+
+ dns_name_toregion(origin, &origin_region);
+ RETERR(isc_buffer_copyregion(&fixed->buffer, &origin_region));
+
+ fixed->name = (dns_name_t){
+ .magic = DNS_NAME_MAGIC,
+ .attributes = { .absolute = true },
+ .ndata = fixed->data,
+ .length = (uint8_t)isc_buffer_usedlength(&fixed->buffer),
+ .buffer = &fixed->buffer,
+ .link = ISC_LINK_INITIALIZER,
+ .list = ISC_LIST_INITIALIZER,
+ };
+
+ return ISC_R_SUCCESS;
+}
diff --git a/lib/dns/include/dns/fixedname.h b/lib/dns/include/dns/fixedname.h
index ce3e735177..2b5d7da3e8 100644
--- a/lib/dns/include/dns/fixedname.h
+++ b/lib/dns/include/dns/fixedname.h
@@ -74,3 +74,19 @@ dns_fixedname_name(dns_fixedname_t *fixed);
dns_name_t *
dns_fixedname_initname(dns_fixedname_t *fixed);
+
+isc_result_t
+dns_fixedname_fromnsec3hash(dns_fixedname_t *fixed, const unsigned char *hash,
+ size_t hash_length, const dns_name_t *origin);
+/*%<
+ * Initialize 'fixed' with an NSEC3 owner name made from the base32hex
+ * encoding of 'hash', followed by 'origin'.
+ *
+ * Requires:
+ *\li 'fixed' is initialized.
+ *\li 'hash' is non-NULL.
+ *\li 'origin' is a valid absolute name.
+ *
+ * Returns:
+ *\li #ISC_R_NOSPACE when the resulting name does not fit in 'fixed'.
+ */
diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h
index df8810caee..5751fd36d7 100644
--- a/lib/dns/include/dns/nsec3.h
+++ b/lib/dns/include/dns/nsec3.h
@@ -94,6 +94,11 @@ dns_nsec3_hashname(dns_fixedname_t *result,
/*%<
* Make a hashed domain name from an unhashed one. If rethash is not NULL
* the raw hash is stored there.
+ *
+ * Requires:
+ *\li 'result' is initialized.
+ *\li 'name' is a valid name.
+ *\li 'origin' is a valid absolute name.
*/
unsigned int
diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c
index 0906c7dd3d..9211026387 100644
--- a/lib/dns/nsec3.c
+++ b/lib/dns/nsec3.c
@@ -232,11 +232,8 @@ dns_nsec3_hashname(dns_fixedname_t *result,
unsigned int iterations, const unsigned char *salt,
size_t saltlength) {
unsigned char hash[NSEC3_MAX_HASH_LENGTH];
- unsigned char nametext[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixed;
dns_name_t *downcased;
- isc_buffer_t namebuffer;
- isc_region_t region;
size_t len;
if (rethash == NULL) {
@@ -258,16 +255,7 @@ dns_nsec3_hashname(dns_fixedname_t *result,
SET_IF_NOT_NULL(hash_length, len);
- /* convert the hash to base32hex non-padded */
- region.base = rethash;
- region.length = (unsigned int)len;
- isc_buffer_init(&namebuffer, nametext, sizeof nametext);
- isc_base32hexnp_totext(®ion, 1, "", &namebuffer);
-
- /* convert the hex to a domain name */
- dns_fixedname_init(result);
- return dns_name_fromtext(dns_fixedname_name(result), &namebuffer,
- origin, 0);
+ return dns_fixedname_fromnsec3hash(result, rethash, len, origin);
}
unsigned int
diff --git a/tests/dns/nsec3_test.c b/tests/dns/nsec3_test.c
index 87002c973e..319dda0f59 100644
--- a/tests/dns/nsec3_test.c
+++ b/tests/dns/nsec3_test.c
@@ -24,6 +24,7 @@
#include <cmocka.h>
#include <isc/lib.h>
+#include <isc/md.h>
#include <isc/string.h>
#include <isc/util.h>
@@ -254,10 +255,40 @@ ISC_RUN_TEST_IMPL(nsec3param_salttotext) {
}
}
+/* Check NSEC3 hash and owner-name generation against RFC 5155 Appendix A. */
+ISC_RUN_TEST_IMPL(hashname) {
+ static const unsigned char salt[] = { 0xaa, 0xbb, 0xcc, 0xdd };
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ dns_fixedname_t expected;
+ dns_fixedname_t name;
+ dns_fixedname_t origin;
+ dns_fixedname_t result;
+ size_t hash_length = 0;
+
+ UNUSED(state);
+
+ dns_test_namefromstring("example.", &name);
+ dns_test_namefromstring("example.", &origin);
+ dns_test_namefromstring("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.",
+ &expected);
+ dns_test_namefromstring("stale.example.", &result);
+
+ assert_int_equal(dns_nsec3_hashname(&result, hash, &hash_length,
+ dns_fixedname_name(&name),
+ dns_fixedname_name(&origin),
+ dns_hash_sha1, 12, salt,
+ sizeof(salt)),
+ ISC_R_SUCCESS);
+ assert_int_equal(hash_length, ISC_SHA1_DIGESTLENGTH);
+ assert_true(dns_name_equal(dns_fixedname_name(&result),
+ dns_fixedname_name(&expected)));
+}
+
ISC_TEST_LIST_START
ISC_TEST_ENTRY(activex)
ISC_TEST_ENTRY(max_iterations)
ISC_TEST_ENTRY(nsec3param_salttotext)
+ISC_TEST_ENTRY(hashname)
ISC_TEST_LIST_END
ISC_TEST_MAIN