Commit 3715b80b6b for bind
commit 3715b80b6bbe53980c727b1cfc2bbd5cf6092917
Author: Matthijs Mekking <matthijs@isc.org>
Date: Fri Oct 9 11:40:22 2026 +0200
Add configuration to set key flags
This adds an optional parameter to 'keys' inside dnssec-policy to set
specific key flags. The only two bits that can be set are SEP and ADT.
For example:
keys {
csk lifetime unlimited algorithm 13 flags sep adt;
};
diff --git a/bin/tests/system/checkconf/bad-kasp-key5.conf b/bin/tests/system/checkconf/bad-kasp-key5.conf
new file mode 100644
index 0000000000..3afc60f9b8
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp-key5.conf
@@ -0,0 +1,11 @@
+dnssec-policy "badflags" {
+ keys {
+ csk lifetime unlimited algorithm 13 flags foo;
+ };
+};
+
+zone "example.net" {
+ type primary;
+ file "example.db";
+ dnssec-policy "badflags";
+};
diff --git a/bin/tests/system/checkconf/bad-kasp-key6.conf b/bin/tests/system/checkconf/bad-kasp-key6.conf
new file mode 100644
index 0000000000..4880947351
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp-key6.conf
@@ -0,0 +1,11 @@
+dnssec-policy "badflags" {
+ keys {
+ csk lifetime unlimited algorithm 13 flags { sep; };
+ };
+};
+
+zone "example.net" {
+ type primary;
+ file "example.db";
+ dnssec-policy "badflags";
+};
diff --git a/bin/tests/system/checkconf/good-kasp.conf b/bin/tests/system/checkconf/good-kasp.conf
index 98e80c7009..06ea31ddac 100644
--- a/bin/tests/system/checkconf/good-kasp.conf
+++ b/bin/tests/system/checkconf/good-kasp.conf
@@ -11,9 +11,11 @@ dnssec-policy "test" {
dnskey-ttl 3600;
inline-signing yes;
keys {
- ksk key-directory lifetime P1Y algorithm ecdsa256;
- zsk lifetime P30D algorithm 13;
- csk key-store "hsm" lifetime unlimited algorithm rsasha256 2048;
+ ksk key-directory lifetime P1Y algorithm ecdsa256 flags sep adt;
+ zsk lifetime P30D algorithm 13 flags adt;
+ csk key-store "hsm" lifetime unlimited algorithm rsasha256 2048 flags adt sep;
+ ksk key-directory lifetime P1Y algorithm 14 tag-range 0 1000 flags ;
+ zsk key-directory lifetime unlimited algorithm ecdsa384 tag-range 1000 9999;
};
max-zone-ttl 86400;
nsec3param iterations 0 optout no salt-length 8;
diff --git a/bin/tests/system/checkconf/good.conf.j2 b/bin/tests/system/checkconf/good.conf.j2
index 412204e7ff..675ef1dc5b 100644
--- a/bin/tests/system/checkconf/good.conf.j2
+++ b/bin/tests/system/checkconf/good.conf.j2
@@ -10,9 +10,9 @@ dnssec-policy "test" {
};
dnskey-ttl 3600;
keys {
- ksk key-directory lifetime P1Y algorithm 13 tag-range 0 32767;
- zsk lifetime P30D algorithm 13;
- csk key-store "hsm" lifetime P30D algorithm 8 2048;
+ ksk key-directory lifetime P1Y algorithm 13 tag-range 0 32767 flags sep adt;
+ zsk lifetime P30D algorithm 13 tag-range 0 100;
+ csk key-store "hsm" lifetime P30D algorithm 8 2048 flags adt sep;
};
manual-mode no;
max-zone-ttl 86400;
diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst
index a09e71f02f..d51a64a843 100644
--- a/doc/arm/reference.rst
+++ b/doc/arm/reference.rst
@@ -6490,6 +6490,12 @@ keys
Each KSK/ZSK pair must have the same algorithm. A CSK combines the
functionality of a ZSK and a KSK.
+ You can optionally set one or more key flags with ``flags``.
+ Two keywords are allowed, ``sep`` and ``adt``, and they will set the
+ corresponding key flags. If ``flags`` is not set, any KASP key with
+ the role ``csk`` or ``ksk`` will have the SEP bit set, and none of
+ the keys will have the ADT bit set.
+
.. note:: When changing the ``key-directory`` or the ``key-store``, BIND will
be unable to find existing key files. Be sure to copy key files to the
new directory before changing the path used in the configuration file.
diff --git a/doc/misc/options b/doc/misc/options
index e5a58cabf5..eadf175850 100644
--- a/doc/misc/options
+++ b/doc/misc/options
@@ -15,7 +15,7 @@ dnssec-policy <string> {
cds-digest-types { <string>; ... };
dnskey-ttl <duration>;
inline-signing <boolean>;
- keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ tag-range <integer> <integer> ] [ <integer> ]; ... };
+ keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ tag-range <integer> <integer> ] [ <integer> ] [ flags ( sep | adt ) ... ]; ... };
manual-mode <boolean>;
max-zone-ttl <duration>;
nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
diff --git a/lib/dns/include/dns/kasp.h b/lib/dns/include/dns/kasp.h
index 0b354a45cd..888848168a 100644
--- a/lib/dns/include/dns/kasp.h
+++ b/lib/dns/include/dns/kasp.h
@@ -70,6 +70,7 @@ struct dns_kasp_key {
dst_algorithm_t algorithm;
int length;
uint8_t role;
+ uint16_t flags;
uint16_t tag_min;
uint16_t tag_max;
};
@@ -711,6 +712,16 @@ dns_kasp_key_zsk(dns_kasp_key_t *key);
*
*/
+uint16_t
+dns_kasp_key_flags(dns_kasp_key_t *key);
+/*%<
+ * Returns the key flags to use.
+ *
+ * Requires:
+ *
+ *\li key != NULL
+ */
+
uint16_t
dns_kasp_key_tagmin(dns_kasp_key_t *key);
/*%<
diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h
index 0562a8085d..322db9b06f 100644
--- a/lib/dns/include/dns/keyvalues.h
+++ b/lib/dns/include/dns/keyvalues.h
@@ -33,6 +33,7 @@
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_KSK = 1 << 0, /* key signing key */
};
diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c
index cd4e8cdfc1..4fb48012fb 100644
--- a/lib/dns/kasp.c
+++ b/lib/dns/kasp.c
@@ -493,6 +493,12 @@ dns_kasp_key_zsk(dns_kasp_key_t *key) {
return key->role & DNS_KASP_KEY_ROLE_ZSK;
}
+uint16_t
+dns_kasp_key_flags(dns_kasp_key_t *key) {
+ REQUIRE(key != NULL);
+ return key->flags;
+}
+
uint16_t
dns_kasp_key_tagmin(dns_kasp_key_t *key) {
REQUIRE(key != NULL);
diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h
index 2021232575..1046735ae2 100644
--- a/lib/isccfg/include/isccfg/grammar.h
+++ b/lib/isccfg/include/isccfg/grammar.h
@@ -475,6 +475,9 @@ cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
void
cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type);
+void
+cfg_doc_enum_list(cfg_printer_t *pctx, const cfg_type_t *type);
+
isc_result_t
cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret);
diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c
index 3156bb13a7..cb702d3713 100644
--- a/lib/isccfg/kaspconf.c
+++ b/lib/isccfg/kaspconf.c
@@ -151,6 +151,7 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
isc_result_t result;
dns_kasp_key_t *key = NULL;
const cfg_obj_t *tagrange = NULL;
+ const cfg_obj_t *keyflags = NULL;
uint32_t min_lifetime = UINT32_MAX;
/* Create a new key reference. */
@@ -163,6 +164,7 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
key->lifetime = 0; /* unlimited */
key->algorithm = DST_ALG_ECDSA256;
key->length = -1;
+ key->flags = DNS_KEYOWNER_ZONE | DNS_KEYFLAG_KSK;
CHECK(dns_keystorelist_find(keystorelist,
DNS_KEYSTORE_KEYDIRECTORY,
&key->keystore));
@@ -367,6 +369,28 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
key->length = size;
}
+ key->flags = DNS_KEYOWNER_ZONE;
+ keyflags = cfg_tuple_get(config, "flags");
+ if (cfg_obj_islist(keyflags)) {
+ const cfg_listelt_t *element = NULL;
+
+ for (element = cfg_list_first(keyflags);
+ element != NULL; element = cfg_list_next(element))
+ {
+ const cfg_obj_t *flagobj =
+ cfg_listelt_value(element);
+ const char *flag = cfg_obj_asstring(flagobj);
+
+ if (strcasecmp(flag, "sep") == 0) {
+ key->flags |= DNS_KEYFLAG_KSK;
+ } else if (strcasecmp(flag, "adt") == 0) {
+ key->flags |= DNS_KEYFLAG_ADT;
+ }
+ }
+ } else if ((key->role & DNS_KASP_KEY_ROLE_KSK) != 0) {
+ key->flags |= DNS_KEYFLAG_KSK;
+ }
+
tagrange = cfg_tuple_get(config, "tag-range");
if (cfg_obj_istuple(tagrange)) {
uint32_t tag_min = 0, tag_max = 0xffff;
@@ -835,6 +859,7 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
new_key->lifetime = dns_kasp_key_lifetime(key);
new_key->algorithm = dns_kasp_key_algorithm(key);
new_key->length = dns_kasp_key_size(key);
+ new_key->flags = dns_kasp_key_flags(key);
result = dns_keystorelist_find(
keystorelist, DNS_KEYSTORE_KEYDIRECTORY,
&new_key->keystore);
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index 8e29044f52..446bf4e8f9 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -635,7 +635,7 @@ static cfg_type_t cfg_type_lifetime = { "lifetime", parse_keyvalue,
print_keyvalue, doc_keyvalue,
&cfg_rep_duration, &lifetime_kw };
/*
- *
+ * Keytag range.
*/
static void
print_tagrange(cfg_printer_t *pctx, const cfg_obj_t *obj) {
@@ -695,6 +695,30 @@ static cfg_type_t cfg_type_optional_tagrange = {
doc_optionaltagrange, &cfg_rep_tuple, &tagrange_kw
};
+/*
+ * Key flags.
+ */
+static const char *keyflag_enums[] = { "sep", "adt", NULL };
+
+static cfg_type_t cfg_type_keyflag = { "keyflag", cfg_parse_enum,
+ cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, keyflag_enums };
+
+static cfg_type_t cfg_type_keyflaglist = {
+ "keyflaglist", cfg_parse_spacelist, cfg_print_spacelist,
+ cfg_doc_enum_list, &cfg_rep_list, &cfg_type_keyflag
+};
+
+static keyword_type_t keyflags_kw = { "flags", &cfg_type_keyflaglist };
+
+static cfg_type_t cfg_type_optional_keyflags = {
+ "optional_keyflags", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_list, &keyflags_kw
+};
+
+/*
+ * KASP key.
+ */
static cfg_tuplefielddef_t kaspkey_fields[] = {
{ "role", &cfg_type_dnsseckeyrole, 0 },
{ "keystorage", &cfg_type_optional_keystore, 0 },
@@ -702,6 +726,7 @@ static cfg_tuplefielddef_t kaspkey_fields[] = {
{ "algorithm", &cfg_type_algorithm, 0 },
{ "tag-range", &cfg_type_optional_tagrange, 0 },
{ "length", &cfg_type_optional_uint32, 0 },
+ { "flags", &cfg_type_optional_keyflags, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_kaspkey = { "kaspkey", cfg_parse_tuple,
@@ -3388,6 +3413,9 @@ doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_print_cstr(pctx, " ]");
}
+/*
+ * NOTIFY.
+ */
static const char *notify_enums[] = { "explicit", "master-only", "primary-only",
NULL };
static isc_result_t
diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c
index d21de76e64..79bde3e1b8 100644
--- a/lib/isccfg/parser.c
+++ b/lib/isccfg/parser.c
@@ -2187,6 +2187,15 @@ cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_print_cstr(pctx, "; ... }");
}
+void
+cfg_doc_enum_list(cfg_printer_t *pctx, const cfg_type_t *type) {
+ REQUIRE(pctx != NULL);
+ REQUIRE(type != NULL);
+
+ cfg_doc_obj(pctx, type->of);
+ cfg_print_cstr(pctx, " ...");
+}
+
/*
* Parse a homogeneous list whose elements are of type 'elttype'
* and where elements are separated by space. The list ends