]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Support for DST_ALG_PRIVATEDNS and DST_ALG_PRIVATEOID
authorMark Andrews <marka@isc.org>
Wed, 16 Apr 2025 01:31:41 +0000 (11:31 +1000)
committerMark Andrews <marka@isc.org>
Wed, 18 Jun 2025 21:00:53 +0000 (07:00 +1000)
The algorithm values PRIVATEDNS and PRIVATEOID are placeholders,
signifying that the actual algorithm identifier is encoded into the
key data. Keys using this mechanism are now supported.

- The algorithm values PRIVATEDNS and PRIVATEOID cannot be used to
  build a key file name; dst_key_buildfilename() will assert if
  they are used.

- The DST key values for private algorithms are higher than 255.
  Since DST_ALG_MAXALG now exceeds 256, algorithm arrays that were
  previously hardcoded to size 256 have been resized.

- New mnemonic/text conversion functions have been added.
  dst_algorithm_{fromtext,totext,format} can handle algorithm
  identifiers encoded in PRIVATEDNS and PRIVATEOID keys, as well
  as the traditional algorithm identifiers. (Note: The existing
  dns_secalg_{fromtext,totext,format} functions are similar, but
  do *not* support PRIVATEDNS and PRIVATEOID. In most cases, the
  new functions have taken the place of the old ones, but in a few
  cases the old version is still appropriate.)

- dns_private{oid,dns}_{fromtext,totext,format} converts between
  DST algorithm values and the mnemonic strings for algorithms
  implemented using PRIVATEDNS or PRIVATEOID. (E.g., "RSASHA256OID").

- dst_algorithm_tosecalg() returns the DNSSEC algorithm identifier
  that applies for a given DST algorithm.  For PRIVATEDNS- or
  PRIVATEOID- based algorithms, the result will be PRIVATEDNS or
  PRIVATEOID, respectively.

- dst_algorithm_fromprivatedns() and dst_algorithm_fromprivateoid()
  return the DST algorithm identifier for an encoded algorithm in
  wire format, represented as in DNS name or an object identifier,
  respectively.

- dst_algorithm_fromdata() is a front-end for the above; it extracts
  the private algorithm identifier encoded at the begining of a
  block of key or signature data, and returns the matching DST
  algorithm number.

- dst_key_fromdns() and dst_key_frombuffer() now work with keys
  that have PRIVATEDNS and PRIVATEOID algorithm identifiers at the
  beginning.

lib/dns/dst_api.c
lib/dns/include/dst/dst.h
lib/dns/rcode.c
lib/dns/resolver.c
lib/dns/validator.c
lib/dns/zone.c
lib/dns/zoneverify.c
lib/isccfg/kaspconf.c

index 2851e3d0a7ea45e54715b55c65aaa50342d8ec51..4e0e3741d0b571d68ddffe8471b3980bc0072c28 100644 (file)
@@ -2107,6 +2107,8 @@ buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
        isc_result_t result;
 
        REQUIRE(out != NULL);
+       REQUIRE(alg != 0 && alg != DST_ALG_PRIVATEOID &&
+               alg != DST_ALG_PRIVATEDNS);
 
        if ((type & DST_TYPE_PRIVATE) != 0) {
                suffix = ".private";
@@ -2172,6 +2174,22 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
        REQUIRE(mctx != NULL);
        REQUIRE(keyp != NULL && *keyp == NULL);
 
+       if (alg == DNS_KEYALG_PRIVATEDNS) {
+               isc_buffer_t b = *source;
+               alg = dst_algorithm_fromprivatedns(&b);
+               if (alg == 0) {
+                       return DST_R_UNSUPPORTEDALG;
+               }
+       }
+
+       if (alg == DNS_KEYALG_PRIVATEOID) {
+               isc_buffer_t b = *source;
+               alg = dst_algorithm_fromprivateoid(&b);
+               if (alg == 0) {
+                       return DST_R_UNSUPPORTEDALG;
+               }
+       }
+
        key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
 
        if (isc_buffer_remaininglength(source) > 0) {
@@ -2636,3 +2654,67 @@ dst_hmac_algorithm_totext(dst_algorithm_t alg) {
                return "unknown";
        }
 }
+
+dns_secalg_t
+dst_algorithm_tosecalg(dst_algorithm_t dst_alg) {
+       static dns_secalg_t dns_alg[DST_MAX_ALGS] = { 0 };
+
+       if (dst_alg < 256) {
+               return dst_alg;
+       }
+       if (dst_alg < DST_MAX_ALGS) {
+               return dns_alg[dst_alg];
+       }
+       return 0;
+}
+
+dst_algorithm_t
+dst_algorithm_fromprivatedns(isc_buffer_t *buffer) {
+       dns_fixedname_t fixed;
+       dns_name_t *name = dns_fixedname_initname(&fixed);
+       isc_result_t result;
+
+       result = dns_name_fromwire(name, buffer, DNS_DECOMPRESS_DEFAULT, NULL);
+       if (result != ISC_R_SUCCESS) {
+               return 0;
+       }
+
+       /*
+        * Do name to dst_algorithm number mapping here.
+        */
+       return 0;
+}
+
+dst_algorithm_t
+dst_algorithm_fromprivateoid(isc_buffer_t *buffer) {
+       isc_region_t r;
+
+       isc_buffer_remainingregion(buffer, &r);
+
+       /*
+        * Do OID to dst_algorithm number mapping here.  There is a
+        * length byte followed by the OID of that length.
+        */
+       if (r.length > 0 && ((unsigned int)r.base[0] + 1) <= r.length) {
+               return 0;
+       }
+       return 0;
+}
+
+dst_algorithm_t
+dst_algorithm_fromdata(dns_secalg_t algorithm, unsigned char *data,
+                      unsigned int length) {
+       isc_buffer_t b;
+       switch (algorithm) {
+       case DNS_KEYALG_PRIVATEDNS:
+               isc_buffer_init(&b, data, length);
+               isc_buffer_add(&b, length);
+               return dst_algorithm_fromprivatedns(&b);
+       case DNS_KEYALG_PRIVATEOID:
+               isc_buffer_init(&b, data, length);
+               isc_buffer_add(&b, length);
+               return dst_algorithm_fromprivateoid(&b);
+       default:
+               return algorithm;
+       }
+}
index 0a9472b284e6c2705097db8d07c69dd97a83e03a..2e959461b48bcece15558a9892ad27058f655858 100644 (file)
@@ -110,7 +110,12 @@ typedef enum dst_algorithm {
        DST_ALG_HMAC_LAST = DST_ALG_HMACSHA512,
 
        DST_ALG_INDIRECT = 252,
-       DST_ALG_PRIVATE = 254,
+       DST_ALG_PRIVATEDNS = 253,
+       DST_ALG_PRIVATEOID = 254,
+       DST_ALG_RESERVED = 255,
+       /*
+        * Put PRIVATE DNS and PRIVATE OID identifiers here.
+        */
        DST_MAX_ALGS = 256,
 } dst_algorithm_t;
 
@@ -206,6 +211,20 @@ dst_algorithm_supported(unsigned int alg);
  * \li false
  */
 
+dst_algorithm_t
+dst_algorithm_fromprivateoid(isc_buffer_t *buffer);
+/*
+ * Extract the dst algorithm identifier that matches
+ * the OID value found at the start of 'buffer'.
+ */
+
+dst_algorithm_t
+dst_algorithm_fromprivatedns(isc_buffer_t *buf);
+/*
+ * Extract the dst algorithm identifier that matches
+ * the DNS name found at the start of 'buffer'.
+ */
+
 bool
 dst_ds_digest_supported(unsigned int digest_type);
 /*%<
@@ -1160,3 +1179,89 @@ dst_hmac_algorithm_totext(dst_algorithm_t alg);
  * Return the name associtated with the HMAC algorithm 'alg'
  * or return "unknown".
  */
+
+isc_result_t
+dst_algorithm_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a DST security algorithm value.
+ * The text may contain either a mnemonic algorithm name or a decimal algorithm
+ * number.  This supports more algorithms than 'dns_secalg_fromtext' as it
+ * supports private algorithms used with PRIVATEDNS and PRIVATEOID.
+ *
+ * Requires:
+ *\li   'algp' is a valid pointer.
+ *
+ *\li   'source' is a valid text region.
+ *
+ * Returns:
+ *\li   ISC_R_SUCCESS                   on success
+ *\li   ISC_R_RANGE                     numeric type is out of range
+ *\li   DNS_R_UNKNOWN                   mnemonic type is unknown
+ */
+
+isc_result_t
+dst_algorithm_totext(dst_algorithm_t alg, isc_buffer_t *target);
+/*%<
+ * Put a textual representation of DST security algorithm 'alg'
+ * into 'target'.  This supports a superset of dns_secalg_totext.
+ *
+ * Requires:
+ *\li   'alg' is a valid dst_algorithm_t.
+ *
+ *\li   'target' is a valid text buffer.
+ *
+ * Ensures,
+ *      if the result is success:
+ *\li           The used space in 'target' is updated.
+ *
+ * Returns:
+ *\li   ISC_R_SUCCESS                   on success
+ *\li   ISC_R_NOSPACE                   target buffer is too small
+ */
+
+#define DST_ALGORITHM_FORMATSIZE 20
+void
+dst_algorithm_format(dst_algorithm_t dst_alg, char *data, unsigned int length);
+/*%<
+ * Wrapper for dst_algorithm_totext(), writing text into 'cp'
+ */
+
+dns_secalg_t
+dst_algorithm_tosecalg(dst_algorithm_t dst_alg);
+/*%<
+ * Return the DNSSEC algorithm identifier that applies for the DST
+ * algorithm.  For PRIVATEDNS and PRIVATEOID based algorithms, this
+ * is PRIVATEDNS and PRIVATEOID respectively.
+ *
+ * Zero is returned when there is no mapping.
+ */
+
+isc_result_t
+dst_privatedns_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
+
+isc_result_t
+dns_privatedns_totext(dst_algorithm_t alg, isc_buffer_t *b);
+
+void
+dns_privatedns_format(dst_algorithm_t alg, char *buf, unsigned int size);
+
+isc_result_t
+dst_privateoid_fromtext(dst_algorithm_t *algp, isc_textregion_t *source);
+
+isc_result_t
+dns_privateoid_totext(dst_algorithm_t alg, isc_buffer_t *b);
+
+void
+dns_privateoid_format(dst_algorithm_t alg, char *buf, unsigned int size);
+
+dst_algorithm_t
+dst_algorithm_fromdata(dns_secalg_t algorithm, unsigned char *data,
+                      unsigned int length);
+/*%<
+ * If 'algorithm' is PRIVATEOID or PRIVATEDNS, extract the DNSSEC private
+ * algorithm encoded at the begining of data and return the DST algorithm
+ * number that corresponds to it; if the algorithm is unknown to DST,
+ * return 0.
+ *
+ * If 'algorithm' is any other value, return it directly.
+ */
index 8c803d7bb37eff3fcac0a5bdb0458949b47a2a46..f77daa414149c2c9a76f144bb8d10c5f5df86831 100644 (file)
@@ -36,6 +36,8 @@
 #include <dns/secalg.h>
 #include <dns/secproto.h>
 
+#include <dst/dst.h>
+
 #define RETERR(x)                        \
        do {                             \
                isc_result_t _r = (x);   \
                { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 },     \
                { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, SENTINEL
 
+/*
+ * PRIVATEDNS subtypes we support.
+ */
+#define PRIVATEDNSS /* currently empty */
+
+/*
+ * PRIVATEOID subtypes we support.
+ */
+#define PRIVATEOIDS /* currently empty */
+
 /* RFC2535 section 7.1 */
 
 #define SECPROTONAMES                                                     \
@@ -150,6 +162,9 @@ static struct tbl secalgs[] = { SECALGNAMES };
 static struct tbl secprotos[] = { SECPROTONAMES };
 static struct tbl hashalgs[] = { HASHALGNAMES };
 static struct tbl dsdigests[] = { DSDIGESTNAMES };
+static struct tbl privatednss[] = { PRIVATEDNSS SENTINEL };
+static struct tbl privateoids[] = { PRIVATEOIDS SENTINEL };
+static struct tbl dstalgorithms[] = { PRIVATEDNSS PRIVATEOIDS SECALGNAMES };
 
 static struct keyflag {
        const char *name;
@@ -353,6 +368,64 @@ dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
        }
 }
 
+isc_result_t
+dst_privatedns_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
+       unsigned int value;
+       RETERR(dns_mnemonic_fromtext(&value, source, privatednss, 0));
+       *dstalgp = value;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+dns_privatedns_totext(dst_algorithm_t alg, isc_buffer_t *target) {
+       return dns_mnemonic_totext(alg, target, privatednss);
+}
+
+void
+dns_privatedns_format(dst_algorithm_t alg, char *cp, unsigned int size) {
+       isc_buffer_t b;
+       isc_region_t r;
+       isc_result_t result;
+
+       REQUIRE(cp != NULL && size > 0);
+       isc_buffer_init(&b, cp, size - 1);
+       result = dns_privatedns_totext(alg, &b);
+       isc_buffer_usedregion(&b, &r);
+       r.base[r.length] = 0;
+       if (result != ISC_R_SUCCESS) {
+               r.base[0] = 0;
+       }
+}
+
+isc_result_t
+dst_privateoid_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
+       unsigned int value;
+       RETERR(dns_mnemonic_fromtext(&value, source, privateoids, 0));
+       *dstalgp = value;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+dns_privateoid_totext(dst_algorithm_t alg, isc_buffer_t *target) {
+       return dns_mnemonic_totext(alg, target, privateoids);
+}
+
+void
+dns_privateoid_format(dst_algorithm_t alg, char *cp, unsigned int size) {
+       isc_buffer_t b;
+       isc_region_t r;
+       isc_result_t result;
+
+       REQUIRE(cp != NULL && size > 0);
+       isc_buffer_init(&b, cp, size - 1);
+       result = dns_privateoid_totext(alg, &b);
+       isc_buffer_usedregion(&b, &r);
+       r.base[r.length] = 0;
+       if (result != ISC_R_SUCCESS) {
+               r.base[0] = 0;
+       }
+}
+
 isc_result_t
 dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
        unsigned int value;
@@ -579,3 +652,32 @@ dns_rdataclass_format(dns_rdataclass_t rdclass, char *array,
                strlcpy(array, "<unknown>", size);
        }
 }
+
+isc_result_t
+dst_algorithm_fromtext(dst_algorithm_t *dstalgp, isc_textregion_t *source) {
+       unsigned int value;
+       RETERR(dns_mnemonic_fromtext(&value, source, dstalgorithms, 255));
+       *dstalgp = value;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t
+dst_algorithm_totext(dst_algorithm_t alg, isc_buffer_t *target) {
+       return dns_mnemonic_totext(alg, target, dstalgorithms);
+}
+
+void
+dst_algorithm_format(dst_algorithm_t alg, char *cp, unsigned int size) {
+       isc_buffer_t b;
+       isc_region_t r;
+       isc_result_t result;
+
+       REQUIRE(cp != NULL && size > 0);
+       isc_buffer_init(&b, cp, size - 1);
+       result = dst_algorithm_totext(alg, &b);
+       isc_buffer_usedregion(&b, &r);
+       r.base[r.length] = 0;
+       if (result != ISC_R_SUCCESS) {
+               r.base[0] = 0;
+       }
+}
index 08f0533fe2b7bd086e9233dea6b4478779a653f6..93d19197961395e2cb7bbd822549a636dcf6659b 100644 (file)
@@ -10593,7 +10593,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name,
                               unsigned int alg) {
        REQUIRE(VALID_RESOLVER(resolver));
 
-       if (alg > 255) {
+       if (alg >= DST_MAX_ALGS) {
                return ISC_R_RANGE;
        }
 
index f2c8fb11be148d19153beac3ac08ba4fc1650de2..4882262b9512962a3971aaf36aa51a16f2b3830f 100644 (file)
@@ -2910,7 +2910,6 @@ check_ds_algs(dns_validator_t *val, dns_name_t *name,
                isc_result_t result;
                dns_rdata_t dsrdata = DNS_RDATA_INIT;
                dns_rdataset_current(rdataset, &dsrdata);
-
                result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
                RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
index edb2a9d12d6bf400c91f58b098d9aa77eb966137..ef14c483d836aebdda2d0dfbe0775bfacb4dc94b 100644 (file)
@@ -22804,7 +22804,7 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version) {
        isc_result_t result;
        dns_dbnode_t *node = NULL;
        dns_rdataset_t dnskey, cds, cdnskey;
-       unsigned char algorithms[256];
+       unsigned char algorithms[DST_MAX_ALGS];
        unsigned int i;
        bool empty = false;
 
index aeb010746acd3c779b94a2bc0d58e030aec0421c..fdd46f3bbe7668abe95e379a5ee463302977c95c 100644 (file)
@@ -68,14 +68,14 @@ typedef struct vctx {
        dns_rdataset_t nsecsigs;
        dns_rdataset_t nsec3paramset;
        dns_rdataset_t nsec3paramsigs;
-       unsigned char revoked_ksk[256];
-       unsigned char revoked_zsk[256];
-       unsigned char standby_ksk[256];
-       unsigned char standby_zsk[256];
-       unsigned char ksk_algorithms[256];
-       unsigned char zsk_algorithms[256];
-       unsigned char bad_algorithms[256];
-       unsigned char act_algorithms[256];
+       unsigned char revoked_ksk[DST_MAX_ALGS];
+       unsigned char revoked_zsk[DST_MAX_ALGS];
+       unsigned char standby_ksk[DST_MAX_ALGS];
+       unsigned char standby_zsk[DST_MAX_ALGS];
+       unsigned char ksk_algorithms[DST_MAX_ALGS];
+       unsigned char zsk_algorithms[DST_MAX_ALGS];
+       unsigned char bad_algorithms[DST_MAX_ALGS];
+       unsigned char act_algorithms[DST_MAX_ALGS];
        isc_heap_t *expected_chains;
        isc_heap_t *found_chains;
 } vctx_t;
@@ -792,7 +792,7 @@ verifynsec3s(const vctx_t *vctx, const dns_name_t *name,
 static isc_result_t
 verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
          dns_dbnode_t *node, dst_key_t **dstkeys, size_t nkeys) {
-       unsigned char set_algorithms[256] = { 0 };
+       unsigned char set_algorithms[DST_MAX_ALGS] = { 0 };
        char namebuf[DNS_NAME_FORMATSIZE];
        char algbuf[DNS_SECALG_FORMATSIZE];
        char typebuf[DNS_RDATATYPE_FORMATSIZE];
index 8b5bd53f6df02ba69b3f7a7618c96515d5348d59..0e29e8d39ec9a13a676f8c5706d6ac0bb467a9e8 100644 (file)
@@ -624,8 +624,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
 
        (void)confget(maps, "keys", &keys);
        if (keys != NULL) {
-               char role[256] = { 0 };
-               bool warn[256][2] = { { false } };
+               char role[DST_MAX_ALGS] = { 0 };
+               bool warn[DST_MAX_ALGS][2] = { { false } };
 
                CFG_LIST_FOREACH (keys, element) {
                        cfg_obj_t *kobj = cfg_listelt_value(element);