From: Martin Basti Date: Tue, 28 Jul 2026 15:22:20 +0000 (+0000) Subject: Add unit test for dns_private_chains X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=72dc0f7895719b972b82dfdec8d45d38f850415a;p=thirdparty%2Fbind9.git Add unit test for dns_private_chains The private test only exercised dns_private_totext. Add coverage for dns_private_chains in the no-NSEC, no-NSEC3PARAM case: the old 5-octet signing record form, the new 7-octet form used for PRIVATE DNSSEC algorithms, records that must not trigger chain building (mismatched algorithm octet, completed signing), and the combination with a queued NSEC3 chain creation. The new-form case fails without the preceding dns_private_chains fix. Assisted-by: Claude:claude-fable-5 --- diff --git a/tests/dns/private_test.c b/tests/dns/private_test.c index c4669ced4e3..7c63420581f 100644 --- a/tests/dns/private_test.c +++ b/tests/dns/private_test.c @@ -27,10 +27,14 @@ #include #include +#include +#include #include #include #include #include +#include +#include #include #include @@ -57,19 +61,24 @@ typedef struct { } nsec3_testcase_t; static void -make_signing(signing_testcase_t *testcase, dns_rdata_t *private, - unsigned char *buf, size_t len) { +make_private(dns_rdata_t *private, unsigned char *buf, size_t len) { dns_rdata_init(private); + private->data = buf; + private->length = len; + private->type = privatetype; + private->rdclass = dns_rdataclass_in; +} + +static void +make_signing(signing_testcase_t *testcase, dns_rdata_t *private, + unsigned char *buf, size_t len) { buf[0] = testcase->alg; buf[1] = (testcase->keyid & 0xff00) >> 8; buf[2] = (testcase->keyid & 0xff); buf[3] = testcase->remove; buf[4] = testcase->complete; - private->data = buf; - private->length = len; - private->type = privatetype; - private->rdclass = dns_rdataclass_in; + make_private(private, buf, len); } static void @@ -191,9 +200,149 @@ ISC_RUN_TEST_IMPL(private_nsec3_totext) { } } +/* + * Run dns_private_chains() over a zone database whose apex holds the + * given private-type records (and no NSEC/NSEC3PARAM RRsets) and check + * the reported chain-building requirements. + */ +static void +check_private_chains(dns_rdata_t *privates, size_t nprivates, + bool expected_nsec, bool expected_nsec3) { + isc_result_t result; + dns_db_t *db = NULL; + dns_dbversion_t *ver = NULL; + bool build_nsec = !expected_nsec; + bool build_nsec3 = !expected_nsec3; + + result = dns_db_create(isc_g_mctx, ZONEDB_DEFAULT, dns_rootname, + dns_dbtype_zone, dns_rdataclass_in, 0, NULL, + &db); + assert_int_equal(result, ISC_R_SUCCESS); + dns_db_newversion(db, &ver); + assert_non_null(ver); + + if (nprivates > 0) { + dns_dbnode_t *node = NULL; + dns_rdatalist_t rdatalist; + dns_rdataset_t rdataset; + + dns_rdatalist_init(&rdatalist); + rdatalist.rdclass = dns_rdataclass_in; + rdatalist.type = privatetype; + for (size_t i = 0; i < nprivates; i++) { + ISC_LIST_APPEND(rdatalist.rdata, &privates[i], link); + } + dns_rdataset_init(&rdataset); + dns_rdatalist_tordataset(&rdatalist, &rdataset); + + result = dns_db_getoriginnode(db, &node); + assert_int_equal(result, ISC_R_SUCCESS); + result = dns_db_addrdataset(db, node, ver, 0, &rdataset, 0, + NULL); + assert_int_equal(result, ISC_R_SUCCESS); + dns_rdataset_disassociate(&rdataset); + dns_db_detachnode(&node); + } + + result = dns_private_chains(db, ver, privatetype, &build_nsec, + &build_nsec3); + assert_int_equal(result, ISC_R_SUCCESS); + assert_int_equal(build_nsec, expected_nsec); + assert_int_equal(build_nsec3, expected_nsec3); + + dns_db_closeversion(db, &ver, false); + dns_db_detach(&db); +} + +/* detect chain building requirements from private signing records */ +ISC_RUN_TEST_IMPL(private_chains) { + UNUSED(state); + + /* No private RRset at the apex. */ + check_private_chains(NULL, 0, false, false); + + { + /* Old form signing record, signing in progress. */ + signing_testcase_t testcase = { DST_ALG_RSASHA256, 12345, 0, + 0 }; + unsigned char data[5]; + dns_rdata_t private; + + make_signing(&testcase, &private, data, sizeof(data)); + check_private_chains(&private, 1, true, false); + } + + { + /* New form signing record for a PRIVATEOID algorithm. */ + unsigned char data[7] = { DNS_KEYALG_PRIVATEOID, + 0x30, + 0x39, + 0, + 0, + DST_ALG_RSASHA256PRIVATEOID >> 8, + DST_ALG_RSASHA256PRIVATEOID & 0xff }; + dns_rdata_t private; + + make_private(&private, data, sizeof(data)); + check_private_chains(&private, 1, true, false); + } + + { + /* + * New form record whose DNSSEC algorithm octet doesn't + * match its DST algorithm. + */ + unsigned char data[7] = { DNS_KEYALG_PRIVATEDNS, + 0x30, + 0x39, + 0, + 0, + DST_ALG_RSASHA256PRIVATEOID >> 8, + DST_ALG_RSASHA256PRIVATEOID & 0xff }; + dns_rdata_t private; + + make_private(&private, data, sizeof(data)); + check_private_chains(&private, 1, false, false); + } + + { + /* New form signing record, signing already complete. */ + unsigned char data[7] = { DNS_KEYALG_PRIVATEOID, + 0x30, + 0x39, + 0, + 1, + DST_ALG_RSASHA256PRIVATEOID >> 8, + DST_ALG_RSASHA256PRIVATEOID & 0xff }; + dns_rdata_t private; + + make_private(&private, data, sizeof(data)); + check_private_chains(&private, 1, false, false); + } + + { + /* New form signing record plus NSEC3 chain creation. */ + unsigned char sbuf[7] = { DNS_KEYALG_PRIVATEOID, + 0x30, + 0x39, + 0, + 0, + DST_ALG_RSASHA256PRIVATEOID >> 8, + DST_ALG_RSASHA256PRIVATEOID & 0xff }; + unsigned char nbuf[DNS_PRIVATE_BUFFERSIZE]; + nsec3_testcase_t nsec3case = { 1, 0, 10, 0xbeef, 0, 0, 0 }; + dns_rdata_t privates[2]; + + make_private(&privates[0], sbuf, sizeof(sbuf)); + make_nsec3(&nsec3case, &privates[1], nbuf, sizeof(nbuf)); + check_private_chains(privates, 2, false, true); + } +} + ISC_TEST_LIST_START ISC_TEST_ENTRY(private_signing_totext) ISC_TEST_ENTRY(private_nsec3_totext) +ISC_TEST_ENTRY(private_chains) ISC_TEST_LIST_END ISC_TEST_MAIN