Commit c4dc71ed25 for bind

commit c4dc71ed258aa38f0765bb34f759d4c25370259f
Author: Evan Hunt <each@isc.org>
Date:   Wed Sep 17 03:54:51 2025 -0700

    Add more ADT flag support in dnssec tools

    An ADT flag in a DNSSEC key will be used to indicate to validators
    that they must check for the nonexistence of a DELEG record before
    accepting an NS delegation.

    The flag can now be set using the "-fA" option in dnssec-keygen or
    dnssec-keyfromlabel.  (It was already possible to set the flag with a
    dnssec-policy statement, either inside named or or via "dnssec-keygen -k".)

diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
index fc2f5b549a..eba45b1afc 100644
--- a/bin/dnssec/dnssec-keyfromlabel.c
+++ b/bin/dnssec/dnssec-keyfromlabel.c
@@ -112,7 +112,7 @@ main(int argc, char **argv) {
 	dst_key_t *key = NULL;
 	dns_fixedname_t fname;
 	dns_name_t *name;
-	uint16_t flags = 0, kskflag = 0, revflag = 0;
+	uint16_t flags = 0, kskflag = 0, revflag = 0, adtflag = 0;
 	dst_algorithm_t alg;
 	int ch;
 	isc_result_t result;
@@ -171,6 +171,8 @@ main(int argc, char **argv) {
 				kskflag = DNS_KEYFLAG_KSK;
 			} else if (toupper(c) == 'R') {
 				revflag = DNS_KEYFLAG_REVOKE;
+			} else if (toupper(c) == 'A') {
+				adtflag = DNS_KEYFLAG_ADT;
 			} else {
 				fatal("unknown flag '%s'",
 				      isc_commandline_argument);
@@ -544,6 +546,7 @@ main(int argc, char **argv) {
 		flags |= DNS_KEYOWNER_ZONE; /* DNSKEY: name type ZONE */
 		flags |= kskflag;
 		flags |= revflag;
+		flags |= adtflag;
 	}

 	isc_buffer_init(&buf, filename, sizeof(filename) - 1);
diff --git a/bin/dnssec/dnssec-keyfromlabel.rst b/bin/dnssec/dnssec-keyfromlabel.rst
index 8fb5672931..1bcad8faa0 100644
--- a/bin/dnssec/dnssec-keyfromlabel.rst
+++ b/bin/dnssec/dnssec-keyfromlabel.rst
@@ -82,7 +82,8 @@ Options
 .. option:: -f flag

    This option sets the specified flag in the ``flag`` field of the KEY/DNSKEY record.
-   The only recognized flags are KSK (Key-Signing Key) and REVOKE.
+   The only recognized flags are KSK (Key-Signing Key), ADT (Authoritative
+   Delegation Types), and REVOKE.

 .. option:: -G

diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
index 57dbf4d25a..e2cb16d4e7 100644
--- a/bin/dnssec/dnssec-keygen.c
+++ b/bin/dnssec/dnssec-keygen.c
@@ -90,6 +90,7 @@ struct keygen_ctx {
 	bool wantzsk;
 	bool wantksk;
 	bool wantrev;
+	bool wantadt;
 	dst_algorithm_t alg;
 	/* timing data */
 	int prepub;
@@ -165,7 +166,8 @@ usage(int ret) {
 			"        algorithm and usage (ZSK or KSK)\n");
 	fprintf(stderr, "    -c <class>: (default: IN)\n");
 	fprintf(stderr, "    -d <digest bits> (0 => max, default)\n");
-	fprintf(stderr, "    -f <keyflag>: ZSK | KSK | REVOKE\n");
+	fprintf(stderr, "    -f <keyflag>: [-]ZSK | [-]KSK | [-]ADT | "
+			"[-]REVOKE\n");
 	fprintf(stderr, "    -F: FIPS mode\n");
 	fprintf(stderr, "    -L <ttl>: default key TTL\n");
 	fprintf(stderr, "    -M <min>:<max>: allowed Key ID range\n");
@@ -717,10 +719,10 @@ int
 main(int argc, char **argv) {
 	char *algname = NULL, *freeit = NULL;
 	char *classname = NULL;
-	char *endp;
+	char *endp = NULL;
 	isc_result_t result;
 	isc_textregion_t r;
-	unsigned char c;
+	uint8_t c;
 	int ch;

 	keygen_ctx_t ctx = {
@@ -794,13 +796,15 @@ main(int argc, char **argv) {
 			fatal("%s", isc_result_totext(DST_R_NOENGINE));
 			break;
 		case 'f':
-			c = (unsigned char)(isc_commandline_argument[0]);
+			c = (uint8_t)(isc_commandline_argument[0]);
 			if (toupper(c) == 'K') {
 				ctx.wantksk = true;
 			} else if (toupper(c) == 'Z') {
 				ctx.wantzsk = true;
 			} else if (toupper(c) == 'R') {
 				ctx.wantrev = true;
+			} else if (toupper(c) == 'A') {
+				ctx.wantadt = true;
 			} else {
 				fatal("unknown flag '%s'",
 				      isc_commandline_argument);
@@ -1138,6 +1142,9 @@ main(int argc, char **argv) {
 			if (ctx.wantrev) {
 				ctx.flags |= DNS_KEYFLAG_REVOKE;
 			}
+			if (ctx.wantadt) {
+				ctx.flags |= DNS_KEYFLAG_ADT;
+			}
 		}

 		keygen(&ctx, argv[isc_commandline_index]);
diff --git a/bin/dnssec/dnssec-keygen.rst b/bin/dnssec/dnssec-keygen.rst
index 9efea3ea67..19b3e93f1f 100644
--- a/bin/dnssec/dnssec-keygen.rst
+++ b/bin/dnssec/dnssec-keygen.rst
@@ -83,14 +83,21 @@ Options

 .. option:: -f flag

-   This option sets the specified flag in the flag field of the KEY/DNSKEY record.
-   The only recognized flags are ZSK (Zone-Signing Key), KSK (Key-Signing Key)
-   and REVOKE.
+   This option sets (or unsets) the specified flag in the flag field of the
+   KEY/DNSKEY record.  The only recognized flags are ZSK (Zone-Signing
+   Key), KSK (Key-Signing Key), ADT (Authoritative Delegation Types), and
+   REVOKE.

-   Note that ZSK is not a physical flag in the DNSKEY record, it is merely used
-   to explicitly tell that you want to create a ZSK. Setting :option:`-f` in
-   conjunction with :option:`-k` will result in generating keys that only
-   match the given role set with this option.
+   Flags are case-insensitive and can be abbreviated to a single letter.
+   Note that only one flag can be specified per ``-f`` option. For example,
+   ``-fa -fk`` sets ADT and KSK, but ``-fak`` only sets ADT and has no
+   effect on KSK.
+
+   ZSK is not a physical flag in the DNSKEY record, it is merely used
+   to explicitly state that you want to create a ZSK.
+
+   Setting :option:`-f` in conjunction with :option:`-k` will result in
+   generating keys that only match the given role set with this option.

 .. option:: -F

@@ -114,13 +121,13 @@ Options

 .. option:: -k policy

-   This option creates keys for a specific ``dnssec-policy``. If a policy uses multiple keys,
-   :program:`dnssec-keygen` generates multiple keys. This also
-   creates a ".state" file to keep track of the key state.
+   This option creates keys for a specific ``dnssec-policy``. If a policy
+   uses multiple keys, :program:`dnssec-keygen` generates multiple keys.
+   This also creates a ".state" file to keep track of the key state.

-   This option creates keys according to the ``dnssec-policy`` configuration, hence
-   it cannot be used at the same time as many of the other options that
-   :program:`dnssec-keygen` provides.
+   This option creates keys according to the ``dnssec-policy``
+   configuration, hence it cannot be used at the same time as many of the
+   other options that :program:`dnssec-keygen` provides.

 .. option:: -L ttl

diff --git a/bin/named/server.c b/bin/named/server.c
index f588dbe363..143ff506a2 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -14457,7 +14457,9 @@ mkey_dumpzone(dns_view_t *view, isc_buffer_t *text) {
 			CHECK(putstr(text, buf));

 			revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
-			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
+			snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s%s",
+				 ((kd.flags & DNS_KEYFLAG_ADT) != 0) ? " ADT"
+								     : "",
 				 revoked ? " REVOKE" : "",
 				 ((kd.flags & DNS_KEYFLAG_KSK) != 0) ? " SEP"
 								     : "",
diff --git a/bin/tests/system/dnssectools/tests.sh b/bin/tests/system/dnssectools/tests.sh
index 8170a329ff..c23cd3604d 100644
--- a/bin/tests/system/dnssectools/tests.sh
+++ b/bin/tests/system/dnssectools/tests.sh
@@ -1126,5 +1126,21 @@ test $(wc -l <dsfromkey.out.test$n) -eq 1 || ret=1
 n=$((n + 1))
 test "$ret" -eq 0 || echo_i "failed"

+echo_i "check dnssec-keygen flag options ($n)"
+ret=0
+zone=example
+key=$("$KEYGEN" -K signer -f ZSK -q -a $DEFAULT_ALGORITHM "$zone")
+grep -q 256 "signer/${key}.key" || ret=1
+key=$("$KEYGEN" -K signer -f KSK -q -a $DEFAULT_ALGORITHM "$zone")
+grep -q 257 "signer/${key}.key" || ret=1
+key=$("$KEYGEN" -K signer -f ADT -q -a $DEFAULT_ALGORITHM "$zone")
+grep -q 258 "signer/${key}.key" || ret=1
+key=$("$KEYGEN" -K signer -f ADT -f KSK -q -a $DEFAULT_ALGORITHM "$zone")
+grep -q 259 "signer/${key}.key" || ret=1
+key=$("$KEYGEN" -K signer -f KSK -f REVOKE -q -a $DEFAULT_ALGORITHM "$zone")
+grep -q 385 "signer/${key}.key" || ret=1
+n=$((n + 1))
+test "$ret" -eq 0 || echo_i "failed"
+
 echo_i "exit status: $status"
 [ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py
index 5a749f230e..fae5c9e2cd 100644
--- a/bin/tests/system/isctest/kasp.py
+++ b/bin/tests/system/isctest/kasp.py
@@ -191,7 +191,7 @@ class KeyProperties:
         legacy: bool = False,
         role: str = "csk",
         ttl: int = 3600,
-        flags: int = 257,
+        flags: int = KEYFLAG_SEP | KEYFLAG_ZONE,
         keytag_min: int = 0,
         keytag_max: int = 65535,
         offset: timedelta | int = 0,
diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h
index 322db9b06f..ef3ded5d2e 100644
--- a/lib/dns/include/dns/keyvalues.h
+++ b/lib/dns/include/dns/keyvalues.h
@@ -33,7 +33,12 @@
 enum {
 	DNS_KEYOWNER_ZONE = 1 << 8,  /* zone key (mandatory for DNSKEY). */
 	DNS_KEYFLAG_REVOKE = 1 << 7, /* key revoked (per rfc5011) */
-	DNS_KEYFLAG_ADT = 1 << 1,    /* DELEG */
+	DNS_KEYFLAG_ADT = 1 << 1,    /* authoritative delegation types:
+					zone may contain DELEG.
+					this tells validators that a
+					nonexistence proof for a DELEG
+					record will be included with NS
+					referrals and must be verified. */
 	DNS_KEYFLAG_KSK = 1 << 0,    /* key signing key */
 };

diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c
index a3737ee40c..80a3a033a0 100644
--- a/lib/dns/keymgr.c
+++ b/lib/dns/keymgr.c
@@ -484,7 +484,6 @@ keymgr_keyid_conflict(dst_key_t *newkey, uint16_t min, uint16_t max,
  * Create a new key for 'origin' given the kasp key configuration 'kkey'.
  * This will check for key id collisions with keys in 'keylist'.
  * The created key will be stored in 'dst_key'.
- *
  */
 static isc_result_t
 keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
index 290d0528f8..b58b330d75 100644
--- a/lib/dns/rcode.c
+++ b/lib/dns/rcode.c
@@ -197,6 +197,8 @@ static struct keyflag {
 		 { "FLAG9", 0x0040, 0x0040 },
 		 { "FLAG10", 0x0020, 0x0020 },
 		 { "FLAG11", 0x0010, 0x0010 },
+		 { "FLAG12", 0x0008, 0x0008 },
+		 { "FLAG13", 0x0004, 0x0004 },
 		 { "SIG0", 0x0000, 0x000F },
 		 { "SIG1", 0x0001, 0x000F },
 		 { "SIG2", 0x0002, 0x000F },
@@ -213,6 +215,7 @@ static struct keyflag {
 		 { "SIG13", 0x000D, 0x000F },
 		 { "SIG14", 0x000E, 0x000F },
 		 { "SIG15", 0x000F, 0x000F },
+		 { "ADT", DNS_KEYFLAG_ADT, DNS_KEYFLAG_ADT },
 		 { "KSK", DNS_KEYFLAG_KSK, DNS_KEYFLAG_KSK },
 		 { NULL, 0, 0 } };