From: Mark Andrews Date: Wed, 21 May 2025 00:13:04 +0000 (+1000) Subject: Future: DS private algorithm support X-Git-Tag: v9.21.10~47^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10d094a289e43eb82425b03a1c23b91876de9205;p=thirdparty%2Fbind9.git Future: DS private algorithm support Add support for proposed DS digest types that encode the private algorithm identifier at the start of the DS digest as is done for DNSKEY and RRSIG. This allows a DS record to identify the specific DNSSEC algorithm, rather than a set of algorithms, when the algorithm field is set to PRIVATEDNS or PRIVATEOID. --- diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c index 3c7db4d0eda..1d8c25185a6 100644 --- a/bin/dnssec/dnssec-cds.c +++ b/bin/dnssec/dnssec-cds.c @@ -482,7 +482,7 @@ match_key_dsset(keyinfo_t *ki, dns_rdataset_t *dsset, strictness_t strictness) { } result = dns_ds_buildrdata(name, &ki->rdata, ds.digest_type, - dsbuf, &newdsrdata); + dsbuf, sizeof(dsbuf), &newdsrdata); if (result != ISC_R_SUCCESS) { vbprintf(3, "dns_ds_buildrdata(" @@ -769,7 +769,7 @@ ds_from_cdnskey(isc_buffer_t *buf, dns_rdata_t *ds, dns_dsdigest_t dt, return ISC_R_NOSPACE; } - result = dns_ds_buildrdata(name, cdnskey, dt, r.base, ds); + result = dns_ds_buildrdata(name, cdnskey, dt, r.base, r.length, ds); if (result == ISC_R_SUCCESS) { isc_buffer_add(buf, DNS_DS_BUFFERSIZE); } diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c index 6fd0d35dcb3..15acead6425 100644 --- a/bin/dnssec/dnssec-dsfromkey.c +++ b/bin/dnssec/dnssec-dsfromkey.c @@ -270,7 +270,7 @@ emit(dns_dsdigest_t dt, bool showall, bool cds, dns_rdata_t *rdata) { return; } - result = dns_ds_buildrdata(name, rdata, dt, buf, &ds); + result = dns_ds_buildrdata(name, rdata, dt, buf, sizeof(buf), &ds); if (result != ISC_R_SUCCESS) { fatal("can't build record"); } diff --git a/bin/dnssec/dnssec-ksr.c b/bin/dnssec/dnssec-ksr.c index b4a4e5736ab..14def762193 100644 --- a/bin/dnssec/dnssec-ksr.c +++ b/bin/dnssec/dnssec-ksr.c @@ -851,7 +851,7 @@ get_keymaterial(ksr_ctx_t *ksr, dns_kasp_t *kasp, isc_stdtime_t inception, dns_rdata_init(rdata2); CHECK(dns_ds_buildrdata(name, rdata, alg->digest, - cdsbuf, &cds)); + cdsbuf, sizeof(cdsbuf), &cds)); cds.type = dns_rdatatype_cds; dns_rdata_toregion(&cds, &rcds); isc_buffer_allocate(mctx, &newbuf2, rcds.length); diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index e2a01429e01..4ceb483bde1 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -1073,7 +1073,7 @@ loadds(dns_name_t *name, uint32_t ttl, dns_rdataset_t *dsset) { dns_rdata_t ds = DNS_RDATA_INIT; dns_rdataset_current(&keyset, &key); result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA256, - dsbuf, &ds); + dsbuf, sizeof(dsbuf), &ds); check_result(result, "dns_ds_buildrdata"); dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, ttl, &ds, @@ -3055,7 +3055,7 @@ writeset(const char *prefix, dns_rdatatype_t type) { if (type != dns_rdatatype_dnskey) { result = dns_ds_buildrdata(gorigin, &rdata, DNS_DSDIGEST_SHA256, dsbuf, - &ds); + sizeof(dsbuf), &ds); check_result(result, "dns_ds_buildrdata"); dns_difftuple_create(mctx, DNS_DIFFOP_ADDRESIGN, name, 0, &ds, &tuple); diff --git a/bin/named/server.c b/bin/named/server.c index 5a333cc937a..6cbfc245c8c 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -677,7 +677,7 @@ cleanup: static isc_result_t ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp, - unsigned char *digest, dns_rdata_ds_t *ds) { + unsigned char *digest, size_t digest_len, dns_rdata_ds_t *ds) { isc_result_t result; dns_rdata_dnskey_t keystruct; dns_rdata_t rdata = DNS_RDATA_INIT; @@ -805,7 +805,7 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp, keystruct.common.rdtype, &keystruct, &rrdatabuf)); CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, - digest, ds)); + digest, digest_len, ds)); break; case INIT_DS: @@ -844,6 +844,20 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp, CHECK(ISC_R_UNEXPECTEDEND); } break; +#if defined(DNS_DSDIGEST_SHA256PRIVATE) + case DNS_DSDIGEST_SHA256PRIVATE: + if (r.length < ISC_SHA256_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; +#endif +#if defined(DNS_DSDIGEST_SHA384PRIVATE) + case DNS_DSDIGEST_SHA384PRIVATE: + if (r.length < ISC_SHA384_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; +#endif default: cfg_obj_log(key, ISC_LOG_ERROR, "key '%s': " @@ -854,12 +868,46 @@ ta_fromconfig(const cfg_obj_t *key, bool *initialp, const char **namestrp, break; } + if (r.length > digest_len) { + CHECK(ISC_R_NOSPACE); + } ds->length = r.length; ds->digest = digest; - INSIST(r.length <= ISC_MAX_MD_SIZE); memmove(ds->digest, r.base, r.length); - if (!dst_algorithm_supported(ds->algorithm)) { + algorithm = ds->algorithm; + +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE) + /* + * Extract the private algorithm from the start + * of the hash field. + */ + switch (ds->digest_type) { + /* + * Digest types that do not encode the private DNSSEC algorithm + * at the start of the digest field. + */ + case DNS_DSDIGEST_SHA1: + case DNS_DSDIGEST_SHA256: + case DNS_DSDIGEST_SHA384: + break; + /* + * Digest types that encode the private DNSSEC algorithm + * at the start of the digest field. + */ + case DNS_DSDIGEST_SHA256PRIVATE: + case DNS_DSDIGEST_SHA384PRIVATE: + algorithm = dst_algorithm_fromdata( + ds->algorithm, ds->digest, ds->length); + break; + /* + * Unknown digest types. + */ + default: + break; + } +#endif + if (!dst_algorithm_supported(algorithm)) { CHECK(DST_R_UNSUPPORTEDALG); } @@ -902,10 +950,11 @@ process_key(const cfg_obj_t *key, dns_keytable_t *secroots, dns_rdata_ds_t ds; isc_result_t result; bool initializing = managed; - unsigned char digest[ISC_MAX_MD_SIZE]; + unsigned char digest[DNS_DS_BUFFERSIZE]; isc_buffer_t b; - result = ta_fromconfig(key, &initializing, &namestr, digest, &ds); + result = ta_fromconfig(key, &initializing, &namestr, digest, + sizeof(digest), &ds); switch (result) { case ISC_R_SUCCESS: diff --git a/bin/tests/system/feature-test.c b/bin/tests/system/feature-test.c index 8f58e133f11..73d0e73e660 100644 --- a/bin/tests/system/feature-test.c +++ b/bin/tests/system/feature-test.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -42,6 +43,7 @@ usage(void) { fprintf(stderr, "\t--edns-version\n"); fprintf(stderr, "\t--enable-dnstap\n"); fprintf(stderr, "\t--enable-querytrace\n"); + fprintf(stderr, "\t--extended-ds-digest\n"); fprintf(stderr, "\t--fips-provider\n"); fprintf(stderr, "\t--gethostname\n"); fprintf(stderr, "\t--gssapi\n"); @@ -93,6 +95,14 @@ main(int argc, char **argv) { #endif /* ifdef WANT_QUERYTRACE */ } + if (strcasecmp(argv[1], "--extended-ds-digest") == 0) { +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE) + return 0; +#else + return 1; +#endif + } + if (strcasecmp(argv[1], "--fips-provider") == 0) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L OSSL_PROVIDER *fips = OSSL_PROVIDER_load(NULL, "fips"); diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 6e73674d2b5..993168e3dc7 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -1841,7 +1841,8 @@ add_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr, dns_rdata_t cdsrdata = DNS_RDATA_INIT; dns_name_t *origin = dst_key_name(key->key); - r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata); + r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, + sizeof(dsbuf), &cdsrdata); if (r != ISC_R_SUCCESS) { char algbuf[DNS_DSDIGEST_FORMATSIZE]; dns_dsdigest_format(digesttype, algbuf, @@ -1876,7 +1877,8 @@ delete_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr, dns_rdata_t cdsrdata = DNS_RDATA_INIT; dns_name_t *origin = dst_key_name(key->key); - r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata); + r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, + sizeof(dsbuf), &cdsrdata); if (r != ISC_R_SUCCESS) { return r; } @@ -2364,7 +2366,7 @@ dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata, } result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf, - &newdsrdata); + sizeof(buf), &newdsrdata); if (result != ISC_R_SUCCESS) { continue; } diff --git a/lib/dns/ds.c b/lib/dns/ds.c index c56691bf19a..773a880127a 100644 --- a/lib/dns/ds.c +++ b/lib/dns/ds.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -32,11 +33,12 @@ isc_result_t dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, dns_dsdigest_t digest_type, unsigned char *digest, - dns_rdata_ds_t *dsrdata) { + size_t len, dns_rdata_ds_t *dsrdata) { isc_result_t result; dns_fixedname_t fname; dns_name_t *name; - unsigned int digestlen; + unsigned int digestlen = 0; + unsigned int privatelen = 0; isc_region_t r; isc_md_t *md; const isc_md_type_t *md_type = NULL; @@ -44,6 +46,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, REQUIRE(key != NULL); REQUIRE(key->type == dns_rdatatype_dnskey || key->type == dns_rdatatype_cdnskey); + REQUIRE(digest != NULL); if (!dst_ds_digest_supported(digest_type)) { return ISC_R_NOTIMPLEMENTED; @@ -55,10 +58,16 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, break; case DNS_DSDIGEST_SHA384: +#ifdef DNS_DSDIGEST_SHA384PRIVATE + case DNS_DSDIGEST_SHA384PRIVATE: +#endif md_type = ISC_MD_SHA384; break; case DNS_DSDIGEST_SHA256: +#ifdef DNS_DSDIGEST_SHA256PRIVATE + case DNS_DSDIGEST_SHA256PRIVATE: +#endif md_type = ISC_MD_SHA256; break; @@ -91,6 +100,64 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, goto end; } +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE) + /* + * Insert PRIVATE algorithm identify at start of digest. + */ + switch (digest_type) { + case DNS_DSDIGEST_SHA1: + case DNS_DSDIGEST_SHA256: + case DNS_DSDIGEST_SHA384: + break; + case DNS_DSDIGEST_SHA256PRIVATE: + case DNS_DSDIGEST_SHA384PRIVATE: + switch (r.base[3]) { + case DNS_KEYALG_PRIVATEDNS: { + isc_region_t r2 = r; + INSIST(r2.length >= 5); + isc_region_consume(&r2, 4); + dns_name_fromregion(name, &r2); + dns_name_toregion(name, &r2); + privatelen = r2.length; + if (r2.length > len) { + result = ISC_R_NOSPACE; + goto end; + } + memmove(digest, r2.base, privatelen); + digest += privatelen; + len -= privatelen; + break; + } + case DNS_KEYALG_PRIVATEOID: { + isc_region_t r2 = r; + INSIST(r2.length >= 5); + isc_region_consume(&r2, 4); + privatelen = r2.base[0] + 1; + if (r2.base[0] > len) { + result = ISC_R_NOSPACE; + goto end; + } + INSIST(r2.length >= privatelen); + memmove(digest, r2.base, privatelen); + digest += privatelen; + len -= privatelen; + break; + } + default: + break; + } + break; + default: + break; + } +#endif + + size_t mdsize = isc_md_get_size(md); + if (mdsize > len) { + result = ISC_R_NOSPACE; + goto end; + } + result = isc_md_final(md, digest, &digestlen); if (result != ISC_R_SUCCESS) { goto end; @@ -102,8 +169,8 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, dsrdata->algorithm = r.base[3]; dsrdata->key_tag = dst_region_computeid(&r); dsrdata->digest_type = digest_type; - dsrdata->digest = digest; - dsrdata->length = digestlen; + dsrdata->digest = digest - privatelen; + dsrdata->length = digestlen + privatelen; end: isc_md_free(md); @@ -112,14 +179,14 @@ end: isc_result_t dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, - dns_dsdigest_t digest_type, unsigned char *buffer, + dns_dsdigest_t digest_type, unsigned char *buffer, size_t len, dns_rdata_t *rdata) { isc_result_t result; unsigned char digest[ISC_MAX_MD_SIZE]; dns_rdata_ds_t ds; isc_buffer_t b; - result = dns_ds_fromkeyrdata(owner, key, digest_type, digest, &ds); + result = dns_ds_fromkeyrdata(owner, key, digest_type, digest, len, &ds); if (result != ISC_R_SUCCESS) { return result; } diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 19fd35d0ae7..4f8f9dc9583 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -233,7 +233,13 @@ dst_algorithm_supported(unsigned int alg) { bool dst_ds_digest_supported(unsigned int digest_type) { return digest_type == DNS_DSDIGEST_SHA1 || +#if defined(DNS_DSDIGEST_SHA256PRIVATE) + digest_type == DNS_DSDIGEST_SHA256PRIVATE || +#endif digest_type == DNS_DSDIGEST_SHA256 || +#if defined(DNS_DSDIGEST_SHA256PRIVATE) + digest_type == DNS_DSDIGEST_SHA384PRIVATE || +#endif digest_type == DNS_DSDIGEST_SHA384; } diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h index a1cad496833..734d93e6473 100644 --- a/lib/dns/include/dns/ds.h +++ b/lib/dns/include/dns/ds.h @@ -23,15 +23,25 @@ #define DNS_DSDIGEST_GOST2012 (5) #define DNS_DSDIGEST_SM3 (6) +#if TEST_PRIVATE_DSDIGEST /* - * Assuming SHA-384 digest type. + * Possible future digest types that encode the PRIVATEDNS and + * PRIVATEOID identifiers before the cryptographic digest value. */ -#define DNS_DS_BUFFERSIZE (52) +#define DNS_DSDIGEST_SHA256PRIVATE (7) +#define DNS_DSDIGEST_SHA384PRIVATE (8) +#define DNS_DSDIGEST_SM3PRIVATE (9) +#endif + +/* + * Assuming SHA-384 digest type + maximal PRIVATEDNS name. + */ +#define DNS_DS_BUFFERSIZE (52 + 255) isc_result_t dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, dns_dsdigest_t digest_type, unsigned char *digest, - dns_rdata_ds_t *dsrdata); + size_t len, dns_rdata_ds_t *dsrdata); /*%< * Build a DS rdata structure from a key. * @@ -43,7 +53,7 @@ dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, isc_result_t dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, - dns_dsdigest_t digest_type, unsigned char *buffer, + dns_dsdigest_t digest_type, unsigned char *buffer, size_t len, dns_rdata_t *rdata); /*%< * Similar to dns_ds_fromkeyrdata(), but copies the DS into a diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index 2caae9612c7..280740b9914 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -453,7 +453,7 @@ dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname, } result = dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256, - digest, &ds); + digest, sizeof(digest), &ds); if (result != ISC_R_SUCCESS) { goto finish; } diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c index f77daa41414..414a7915387 100644 --- a/lib/dns/rcode.c +++ b/lib/dns/rcode.c @@ -138,6 +138,20 @@ /* RFC3658, RFC4509, RFC5933, RFC6605, RFC9558, RFC9563 */ +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && \ + defined(DNS_DSDIGEST_SHA384PRIVATE) && \ + defined(DNS_DSDIGEST_SM3PRIVATE) +#define DSDIGESTPRIVATENAMES \ + { DNS_DSDIGEST_SHA256PRIVATE, "SHA-256-PRIVATE", 0 }, \ + { DNS_DSDIGEST_SHA256PRIVATE, "SHA256PRIVATE", 0 }, \ + { DNS_DSDIGEST_SHA384PRIVATE, "SHA-384-PRIVATE", 0 }, \ + { DNS_DSDIGEST_SHA384PRIVATE, "SHA384PRIVATE", 0 }, \ + { DNS_DSDIGEST_SM3PRIVATE, "SM3-PRIVATE", 0 }, \ + { DNS_DSDIGEST_SM3PRIVATE, "SM3PRIVATE", 0 }, +#else +#define DSDIGESTPRIVATENAMES +#endif + #define DSDIGESTNAMES \ { DNS_DSDIGEST_SHA1, "SHA-1", 0 }, { DNS_DSDIGEST_SHA1, "SHA1", 0 }, \ { DNS_DSDIGEST_SHA256, "SHA-256", 0 }, \ @@ -147,7 +161,8 @@ { DNS_DSDIGEST_SHA384, "SHA-384", 0 }, \ { DNS_DSDIGEST_SHA384, "SHA384", 0 }, \ { DNS_DSDIGEST_GOST2012, "GOST-2012", 0 }, \ - { DNS_DSDIGEST_GOST2012, "GOST2012", 0 }, SENTINEL + { DNS_DSDIGEST_GOST2012, "GOST2012", 0 }, \ + DSDIGESTPRIVATENAMES SENTINEL struct tbl { unsigned int value; diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 369b4316f37..82a839977ab 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -2030,6 +2030,8 @@ validate_dnskey_dsset(dns_validator_t *val) { isc_result_t result; dns_rdata_ds_t ds; dns_rdata_dnskey_t key; + unsigned char *data = 0; + unsigned int datalen = 0; dns_rdata_reset(&dsrdata); dns_rdataset_current(val->dsset, &dsrdata); @@ -2049,12 +2051,31 @@ validate_dnskey_dsset(dns_validator_t *val) { return DNS_R_BADALG; } - if (ds.algorithm != DNS_KEYALG_PRIVATEDNS && - ds.algorithm != DNS_KEYALG_PRIVATEOID) + switch (ds.algorithm) { + case DNS_KEYALG_PRIVATEDNS: + case DNS_KEYALG_PRIVATEOID: + switch (ds.digest_type) { +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE) + case DNS_DSDIGEST_SHA256PRIVATE: + case DNS_DSDIGEST_SHA384PRIVATE: + data = ds.digest; + datalen = ds.length; + break; +#endif + default: + break; + } + break; + default: + break; + } + + if (data != NULL || (ds.algorithm != DNS_KEYALG_PRIVATEDNS && + ds.algorithm != DNS_KEYALG_PRIVATEOID)) { if (!dns_resolver_algorithm_supported(val->view->resolver, val->name, ds.algorithm, - NULL, 0)) + data, datalen)) { if (val->unsupported_algorithm == 0) { val->unsupported_algorithm = ds.algorithm; @@ -2078,8 +2099,8 @@ validate_dnskey_dsset(dns_validator_t *val) { * found a matching dnskey. */ dns_rdata_tostruct(&keyrdata, &key, NULL); - if (ds.algorithm == DNS_KEYALG_PRIVATEDNS || - ds.algorithm == DNS_KEYALG_PRIVATEOID) + if (data == NULL && (ds.algorithm == DNS_KEYALG_PRIVATEDNS || + ds.algorithm == DNS_KEYALG_PRIVATEOID)) { if (!dns_resolver_algorithm_supported(val->view->resolver, val->name, key.algorithm, @@ -3020,6 +3041,13 @@ check_ds_algs(dns_validator_t *val, dns_name_t *name, ds.algorithm == DNS_KEYALG_PRIVATEDNS) { switch (ds.digest_type) { +#if defined(DNS_DSDIGEST_SHA256PRIVATE) && defined(DNS_DSDIGEST_SHA384PRIVATE) + case DNS_DSDIGEST_SHA256PRIVATE: + case DNS_DSDIGEST_SHA384PRIVATE: + data = ds.digest; + datalen = ds.length; + break; +#endif case DNS_DSDIGEST_SHA1: case DNS_DSDIGEST_SHA256: case DNS_DSDIGEST_SHA384: @@ -3065,11 +3093,12 @@ check_ds_algs(dns_validator_t *val, dns_name_t *name, * it would be raised already. * * If we have seen a private algorithm for which we couldn't find a - * DNSKEY we must assume the child zone is secure. With PRIVATEDNS and - * PRIVATEOID we can only make that determination if we match a DNSKEY - * for every DS with these algorithms. Since we don't know whether the - * private algorithm is unsupported or not, we are required to treat it - * as supported. + * DNSKEY nor extract it from the digest field we must assume the child + * zone is secure. With PRIVATEDNS and PRIVATEOID we can make that + * determination if we match a DNSKEY for every DS with these algorithms + * or extract the algorithm from the digest field. Since we don't know + * whether the private algorithm is unsupported or not, we are required + * to treat it as supported. */ if (seen_private) { char namebuf[DNS_NAME_FORMATSIZE]; diff --git a/lib/dns/view.c b/lib/dns/view.c index 12b02669e52..36619b2989a 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1648,9 +1648,9 @@ dns_view_istrusted(dns_view_t *view, const dns_name_t *keyname, goto finish; } - result = dns_ds_fromkeyrdata(keyname, &rdata, - DNS_DSDIGEST_SHA256, - digest, &ds); + result = dns_ds_fromkeyrdata( + keyname, &rdata, DNS_DSDIGEST_SHA256, digest, + sizeof(digest), &ds); if (result != ISC_R_SUCCESS) { goto finish; } @@ -2311,7 +2311,7 @@ dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype, isc_result_t result; dns_name_t *name = UNCONST(keyname); char rdatabuf[DST_KEY_MAXSIZE]; - unsigned char digest[ISC_MAX_MD_SIZE]; + unsigned char digest[DNS_DS_BUFFERSIZE]; dns_rdata_ds_t ds; dns_rdata_t rdata; isc_buffer_t b; @@ -2334,7 +2334,7 @@ dns_view_addtrustedkey(dns_view_t *view, dns_rdatatype_t rdtype, CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); } else { CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, - digest, &ds)); + digest, sizeof(digest), &ds)); } CHECK(dns_keytable_add(view->secroots_priv, false, false, name, &ds, diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 1e3ae54d18d..ffe1b658877 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -4433,7 +4433,7 @@ trust_key(dns_zone_t *zone, dns_name_t *keyname, dns_rdata_dnskey_t *dnskey, bool initial) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; - unsigned char data[4096], digest[ISC_MAX_MD_SIZE]; + unsigned char data[4096], digest[DNS_DS_BUFFERSIZE]; isc_buffer_t buffer; dns_keytable_t *sr = NULL; dns_rdata_ds_t ds; @@ -4448,7 +4448,7 @@ trust_key(dns_zone_t *zone, dns_name_t *keyname, dns_rdata_dnskey_t *dnskey, dns_rdata_fromstruct(&rdata, dnskey->common.rdclass, dns_rdatatype_dnskey, dnskey, &buffer); CHECK(dns_ds_fromkeyrdata(keyname, &rdata, DNS_DSDIGEST_SHA256, digest, - &ds)); + sizeof(digest), &ds)); CHECK(dns_keytable_add(sr, true, initial, keyname, &ds, sfd_add, zone->view)); @@ -16501,7 +16501,8 @@ cds_inuse(dns_zone_t *zone, dns_rdata_t *rdata, dns_dnsseckeylist_t *keylist, return result; } result = dns_ds_buildrdata(dns_zone_getorigin(zone), &dnskey, - cds.digest_type, cdsbuf, &cdsrdata); + cds.digest_type, cdsbuf, + sizeof(cdsbuf), &cdsrdata); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "dns_ds_buildrdata(keytag=%d, algo=%d, " @@ -21033,7 +21034,8 @@ checkds_done(void *arg) { /* Derive DS from DNSKEY, see if the rdata is equal. */ make_dnskey(key->key, keybuf, sizeof(keybuf), &dnskey); r = dns_ds_buildrdata(&zone->origin, &dnskey, - ds.digest_type, dsbuf, &dsrdata); + ds.digest_type, dsbuf, + sizeof(dsbuf), &dsrdata); if (r != ISC_R_SUCCESS) { continue; } diff --git a/lib/dns/zoneverify.c b/lib/dns/zoneverify.c index d6cce894ebb..9acab371e71 100644 --- a/lib/dns/zoneverify.c +++ b/lib/dns/zoneverify.c @@ -1521,7 +1521,7 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey, result = dns_ds_buildrdata(vctx->origin, keyrdata, ds.digest_type, buf, - &newdsrdata); + sizeof(buf), &newdsrdata); if (result != ISC_R_SUCCESS) { continue; } diff --git a/tests/dns/keytable_test.c b/tests/dns/keytable_test.c index 538a98bfebb..c125c18c65d 100644 --- a/tests/dns/keytable_test.c +++ b/tests/dns/keytable_test.c @@ -130,7 +130,7 @@ create_keystruct(uint16_t flags, uint8_t proto, uint8_t alg, const char *keystr, static void create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg, - const char *keystr, unsigned char *digest, + const char *keystr, unsigned char *digest, size_t digest_len, dns_rdata_ds_t *dsstruct) { isc_result_t result; unsigned char rrdata[4096]; @@ -156,7 +156,7 @@ create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg, * Build DS rdata struct. */ result = dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, digest, - dsstruct); + digest_len, dsstruct); assert_int_equal(result, ISC_R_SUCCESS); dns_rdata_freestruct(&dnskey); @@ -165,7 +165,7 @@ create_dsstruct(dns_name_t *name, uint16_t flags, uint8_t proto, uint8_t alg, /* Common setup: create a keytable and ntatable to test with a few keys */ static void create_tables(void) { - unsigned char digest[ISC_MAX_MD_SIZE]; + unsigned char digest[DNS_DS_BUFFERSIZE]; dns_rdata_ds_t ds; dns_fixedname_t fn; dns_name_t *keyname = dns_fixedname_name(&fn); @@ -179,14 +179,16 @@ create_tables(void) { /* Add a normal key */ dns_test_namefromstring("example.com.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); /* Add an initializing managed key */ dns_test_namefromstring("managed.com.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -220,7 +222,7 @@ destroy_tables(void) { ISC_LOOP_TEST_IMPL(add) { dns_keynode_t *keynode = NULL; dns_keynode_t *null_keynode = NULL; - unsigned char digest[ISC_MAX_MD_SIZE]; + unsigned char digest[DNS_DS_BUFFERSIZE]; dns_rdata_ds_t ds; dns_fixedname_t fn; dns_name_t *keyname = dns_fixedname_name(&fn); @@ -241,7 +243,8 @@ ISC_LOOP_TEST_IMPL(add) { * report success. */ dns_test_namefromstring("example.com.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -252,7 +255,8 @@ ISC_LOOP_TEST_IMPL(add) { /* Add another key (different keydata) */ dns_keynode_detach(&keynode); - create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -280,7 +284,8 @@ ISC_LOOP_TEST_IMPL(add) { * node, the node should *not* be marked as initializing. */ dns_test_namefromstring("managed.com.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -310,7 +315,8 @@ ISC_LOOP_TEST_IMPL(add) { * initializing key. */ dns_test_namefromstring("two.com.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, true, true, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -326,7 +332,8 @@ ISC_LOOP_TEST_IMPL(add) { * trust anchor for two.com and we haven't run dns_keynode_trust(), * the initialization status should not change. */ - create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, true, false, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -344,7 +351,8 @@ ISC_LOOP_TEST_IMPL(add) { &null_keynode), ISC_R_SUCCESS); dns_test_namefromstring("null.example.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr2, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr2, digest, sizeof(digest), + &ds); assert_int_equal(dns_keytable_add(keytable, false, false, keyname, &ds, NULL, NULL), ISC_R_SUCCESS); @@ -598,7 +606,7 @@ ISC_LOOP_TEST_IMPL(nta) { bool issecure, covered; dns_fixedname_t fn; dns_name_t *keyname = dns_fixedname_name(&fn); - unsigned char digest[ISC_MAX_MD_SIZE]; + unsigned char digest[DNS_DS_BUFFERSIZE]; dns_rdata_ds_t ds; dns_view_t *myview = NULL; isc_stdtime_t now = isc_stdtime_now(); @@ -616,7 +624,8 @@ ISC_LOOP_TEST_IMPL(nta) { assert_int_equal(result, ISC_R_SUCCESS); dns_test_namefromstring("example.", &fn); - create_dsstruct(keyname, 257, 3, 5, keystr1, digest, &ds); + create_dsstruct(keyname, 257, 3, 5, keystr1, digest, sizeof(digest), + &ds); result = dns_keytable_add(keytable, false, false, keyname, &ds, NULL, NULL), assert_int_equal(result, ISC_R_SUCCESS);