From: Mark Andrews Date: Wed, 16 Apr 2025 01:31:41 +0000 (+1000) Subject: Support for DST_ALG_PRIVATEDNS and DST_ALG_PRIVATEOID X-Git-Tag: v9.21.10~47^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6fe09d85ab0bfffac0f9555e3b153fd1964b7a1f;p=thirdparty%2Fbind9.git Support for DST_ALG_PRIVATEDNS and DST_ALG_PRIVATEOID 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. --- diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 2851e3d0a7e..4e0e3741d0b 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -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; + } +} diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 0a9472b284e..2e959461b48 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -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. + */ diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index 8c803d7bb37..f77daa41414 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -36,6 +36,8 @@ #include #include +#include + #define RETERR(x) \ do { \ isc_result_t _r = (x); \ @@ -115,6 +117,16 @@ { 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, "", 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; + } +} diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 08f0533fe2b..93d19197961 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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; } diff --git a/lib/dns/validator.c b/lib/dns/validator.c index f2c8fb11be1..4882262b951 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -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); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index edb2a9d12d6..ef14c483d83 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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; diff --git a/lib/dns/zoneverify.c b/lib/dns/zoneverify.c index aeb010746ac..fdd46f3bbe7 100644 --- a/lib/dns/zoneverify.c +++ b/lib/dns/zoneverify.c @@ -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]; diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 8b5bd53f6df..0e29e8d39ec 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -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);