Commit a1ad78ae06 for bind

commit a1ad78ae0656c65026c609e6b3d1add5faed88cf
Author: Martin Basti <mbasti@isc.org>
Date:   Tue Sep 1 08:44:29 2026 +0000

    Use dst_algorithm_format for dnssec-policy and tool algorithms

    dnssec-keygen, dnssec-keyfromlabel, dnssec-ksr and the dnssec-policy
    nsec3 check format a dst_algorithm_t parsed by dst_algorithm_fromtext,
    so passing it to dns_secalg_format truncated PRIVATEOID based
    algorithms to 8 bits and printed the wrong name.

    Two existing dst_algorithm_format callers still sized their buffers
    with DNS_SECALG_FORMATSIZE; switch them to DST_ALG_FORMATSIZE so all
    callers share one size.

    Assisted-by: Claude:claude-fable-5

diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
index ac3871df96..4aeb58a5a4 100644
--- a/bin/dnssec/dnssec-keyfromlabel.c
+++ b/bin/dnssec/dnssec-keyfromlabel.c
@@ -35,7 +35,6 @@
 #include <dns/lib.h>
 #include <dns/name.h>
 #include <dns/rdataclass.h>
-#include <dns/secalg.h>

 #include <dst/dst.h>

@@ -521,8 +520,8 @@ main(int argc, char **argv) {
 	switch (alg) {
 	case DST_ALG_RSASHA1:
 	case DST_ALG_NSEC3RSASHA1: {
-		char algstr[DNS_SECALG_FORMATSIZE];
-		dns_secalg_format(alg, algstr, sizeof(algstr));
+		char algstr[DST_ALG_FORMATSIZE];
+		dst_algorithm_format(alg, algstr, sizeof(algstr));
 		fprintf(stderr,
 			"WARNING: DNSKEY algorithm '%s' is deprecated. Please "
 			"migrate to another algorithm\n",
@@ -553,9 +552,9 @@ main(int argc, char **argv) {

 	if (result != ISC_R_SUCCESS) {
 		char namestr[DNS_NAME_FORMATSIZE];
-		char algstr[DNS_SECALG_FORMATSIZE];
+		char algstr[DST_ALG_FORMATSIZE];
 		dns_name_format(name, namestr, sizeof(namestr));
-		dns_secalg_format(alg, algstr, sizeof(algstr));
+		dst_algorithm_format(alg, algstr, sizeof(algstr));
 		fatal("failed to get key %s/%s: %s", namestr, algstr,
 		      isc_result_totext(result));
 		UNREACHABLE();
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
index 4abf054823..ed307c6093 100644
--- a/bin/dnssec/dnssec-keygen.c
+++ b/bin/dnssec/dnssec-keygen.c
@@ -54,7 +54,6 @@
 #include <dns/lib.h>
 #include <dns/name.h>
 #include <dns/rdataclass.h>
-#include <dns/secalg.h>

 #include <dst/dst.h>

@@ -230,7 +229,7 @@ progress(int p) {
 static void
 keygen(keygen_ctx_t *ctx, const char *keyname) {
 	char filename[255];
-	char algstr[DNS_SECALG_FORMATSIZE];
+	char algstr[DST_ALG_FORMATSIZE];
 	uint16_t flags = 0;
 	bool conflict = false;
 	bool show_progress = false;
@@ -451,7 +450,7 @@ keygen(keygen_ctx_t *ctx, const char *keyname) {
 	switch (ctx->alg) {
 	case DST_ALG_RSASHA1:
 	case DST_ALG_NSEC3RSASHA1:
-		dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
+		dst_algorithm_format(ctx->alg, algstr, sizeof(algstr));
 		fprintf(stderr,
 			"WARNING: DNSKEY algorithm '%s' is deprecated. Please "
 			"migrate to another algorithm\n",
diff --git a/bin/dnssec/dnssec-ksr.c b/bin/dnssec/dnssec-ksr.c
index c43d520432..6346fe967b 100644
--- a/bin/dnssec/dnssec-ksr.c
+++ b/bin/dnssec/dnssec-ksr.c
@@ -304,7 +304,7 @@ create_key(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_kasp_key_t *kaspkey,
 	bool conflict = false;
 	bool freekey = false;
 	bool show_progress = true;
-	char algstr[DNS_SECALG_FORMATSIZE];
+	char algstr[DST_ALG_FORMATSIZE];
 	char filename[PATH_MAX + 1];
 	char timestr[26]; /* Minimal buf as per ctime_r() spec. */
 	dst_key_t *key = NULL;
@@ -530,7 +530,7 @@ print_rdata(dns_rdataset_t *rrset) {
 static isc_stdtime_t
 print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys,
 	      isc_stdtime_t inception, isc_stdtime_t next_inception) {
-	char algstr[DNS_SECALG_FORMATSIZE];
+	char algstr[DST_ALG_FORMATSIZE];
 	char timestr[26]; /* Minimal buf as per ctime_r() spec. */
 	dns_rdatalist_t *rdatalist = NULL;
 	dns_rdataset_t rdataset = DNS_RDATASET_INIT;
@@ -538,8 +538,8 @@ print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys,
 	isc_stdtime_t next_bundle = next_inception;

 	isc_stdtime_tostring(inception, timestr, sizeof(timestr));
-	dns_secalg_format(dns_kasp_key_algorithm(kaspkey), algstr,
-			  sizeof(algstr));
+	dst_algorithm_format(dns_kasp_key_algorithm(kaspkey), algstr,
+			     sizeof(algstr));

 	/* Fetch matching key pair. */
 	rdatalist = isc_mem_get(isc_g_mctx, sizeof(*rdatalist));
diff --git a/bin/tests/system/ksr/ns1/named.conf.j2 b/bin/tests/system/ksr/ns1/named.conf.j2
index 1dd240f972..d556b3d087 100644
--- a/bin/tests/system/ksr/ns1/named.conf.j2
+++ b/bin/tests/system/ksr/ns1/named.conf.j2
@@ -23,6 +23,14 @@ dnssec-policy "csk" {
 	};
 };

+dnssec-policy "privateoid" {
+	offline-ksk yes;
+	keys {
+		ksk lifetime unlimited algorithm RSASHA256OID 2048;
+		zsk lifetime P6M algorithm RSASHA256OID 2048;
+	};
+};
+
 dnssec-policy "unlimited" {
 	offline-ksk yes;
 	keys {
diff --git a/bin/tests/system/ksr/tests_ksr.py b/bin/tests/system/ksr/tests_ksr.py
index f8db9a81cf..b51f7805ad 100644
--- a/bin/tests/system/ksr/tests_ksr.py
+++ b/bin/tests/system/ksr/tests_ksr.py
@@ -36,6 +36,7 @@ pytestmark = pytest.mark.extra_artifacts(
         "ksk-roll.test.*",
         "last-bundle.test.*",
         "past.test.*",
+        "privateoid.test.*",
         "two-tone.test.*",
         "unlimited.test.*",
         "invalid-skr.test.*",
@@ -1565,3 +1566,54 @@ def test_ksr_oversize(ns1):

     # - check if named is still running
     ns1.rndc("status")
+
+
+def test_ksr_privateoid():
+    # A policy with a PRIVATEOID based algorithm: key files and error
+    # messages must use the full 16-bit DST algorithm, which used to be
+    # truncated to the 8-bit DNSSEC algorithm octet.
+    zone = "privateoid.test"
+    policy = "privateoid"
+    alg = 256  # DST_ALG_RSASHA256PRIVATEOID
+    size = 2048
+    n = 1
+
+    # create ksk
+    kskdir = "ns1/offline"
+    cmd = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
+    ksks = isctest.kasp.keystr_to_keylist(cmd.out, kskdir)
+    assert len(ksks) == 1
+    check_keys(ksks, None, CONFIG, alg=alg, size=size)
+
+    # check that 'dnssec-ksr keygen' pregenerates right amount of keys
+    zskdir = "ns1"
+    cmd = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
+    zsks = isctest.kasp.keystr_to_keylist(cmd.out, zskdir)
+    assert len(zsks) == 2
+    lifetime = timedelta(days=31 * 6)
+    check_keys(zsks, lifetime, CONFIG, alg=alg, size=size)
+
+    # check that 'dnssec-ksr request' creates correct ksr
+    now = zsks[0].get_timing("Created")
+    until = now + timedelta(days=365)
+    ksr_fname = f"{zone}.ksr.{n}"
+    ksr(
+        zone,
+        policy,
+        "request",
+        options=f"-K {zskdir} -i {now} -e +1y",
+        to_file=ksr_fname,
+    )
+    check_keysigningrequest(ksr_fname, zsks, now, until)
+
+    # check that 'dnssec-ksr request' errors if there are not enough
+    # keys, naming the private algorithm mnemonic
+    cmd = ksr(
+        zone,
+        policy,
+        "request",
+        options=f"-K {zskdir} -i {now} -e +2y",
+        raise_on_exception=False,
+    )
+    errmsg = f"dnssec-ksr: fatal: no {zone}/RSASHA256OID zsk key pair found for bundle"
+    assert errmsg in cmd.err
diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c
index 30f9bc0057..297fa2ed0d 100644
--- a/lib/isccfg/kaspconf.c
+++ b/lib/isccfg/kaspconf.c
@@ -28,7 +28,6 @@
 #include <dns/keystore.h>
 #include <dns/keyvalues.h>
 #include <dns/nsec3.h>
-#include <dns/secalg.h>
 #include <dns/ttl.h>

 #include <dst/dst.h>
@@ -441,8 +440,8 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
 	dns_kasp_thaw(kasp);

 	if (badalg > 0) {
-		char algstr[DNS_SECALG_FORMATSIZE];
-		dns_secalg_format((dns_secalg_t)badalg, algstr, sizeof(algstr));
+		char algstr[DST_ALG_FORMATSIZE];
+		dst_algorithm_format(badalg, algstr, sizeof(algstr));
 		if (log_errors) {
 			kaspcfg_log(obj, ISC_LOG_ERROR,
 				    "dnssec-policy: cannot use nsec3 with "