From: Evan Hunt Date: Thu, 19 Sep 2019 02:45:20 +0000 (-0700) Subject: add support for DS trust anchors in delv X-Git-Tag: v9.15.6~7^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=342cc9b168a8c260e51916b0e6b33a7fb4411e09;p=thirdparty%2Fbind9.git add support for DS trust anchors in delv --- diff --git a/bin/delv/delv.c b/bin/delv/delv.c index c02dfb99055..fb14aa05ba9 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -33,8 +33,10 @@ #include #include #include +#include #include #include +#include #include #ifdef WIN32 #include @@ -608,11 +610,12 @@ convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { static isc_result_t key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { - dns_rdata_dnskey_t keystruct; + dns_rdata_dnskey_t dnskey; + dns_rdata_ds_t ds; uint32_t n1, n2, n3; - const char *keystr, *keynamestr; - unsigned char keydata[4096]; - isc_buffer_t keydatabuf; + const char *datastr = NULL, *keynamestr = NULL, *atstr = NULL; + unsigned char data[4096]; + isc_buffer_t databuf; unsigned char rrdata[4096]; isc_buffer_t rrdatabuf; isc_region_t r; @@ -620,6 +623,13 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { dns_name_t *keyname; isc_result_t result; bool match_root = false; + enum { + INITIAL_KEY, + STATIC_KEY, + INITIAL_DS, + STATIC_DS, + TRUSTED + } anchortype; keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); CHECK(convert_name(&fkeyname, &keyname, keynamestr)); @@ -651,14 +661,26 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { /* if DNSKEY, algorithm; if DS, digest type */ n3 = cfg_obj_asuint32(cfg_tuple_get(key, "n3")); - keystruct.common.rdclass = dns_rdataclass_in; - keystruct.common.rdtype = dns_rdatatype_dnskey; - /* - * The key data in keystruct is not dynamically allocated. - */ - keystruct.mctx = NULL; + /* What type of trust anchor is this? */ + atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype")); + if (strcasecmp(atstr, "static-key") == 0) { + anchortype = STATIC_KEY; + } else if (strcasecmp(atstr, "static-ds") == 0) { + anchortype = STATIC_DS; + } else if (strcasecmp(atstr, "initial-key") == 0) { + anchortype = INITIAL_KEY; + } else if (strcasecmp(atstr, "initial-ds") == 0) { + anchortype = INITIAL_DS; + } else { + delv_log(ISC_LOG_ERROR, + "key '%s': invalid initialization method '%s'", + keynamestr, atstr); + result = ISC_R_FAILURE; + goto cleanup; + } - ISC_LINK_INIT(&keystruct.common, link); + isc_buffer_init(&databuf, data, sizeof(data)); + isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); if (n1 > 0xffff) { CHECK(ISC_R_RANGE); @@ -670,25 +692,78 @@ key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { CHECK(ISC_R_RANGE); } - keystruct.flags = (uint16_t)n1; - keystruct.protocol = (uint8_t)n2; - keystruct.algorithm = (uint8_t)n3; - - isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); - isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); + switch (anchortype) { + case STATIC_KEY: + case INITIAL_KEY: + case TRUSTED: + dnskey.common.rdclass = dns_rdataclass_in; + dnskey.common.rdtype = dns_rdatatype_dnskey; + dnskey.mctx = NULL; + + ISC_LINK_INIT(&dnskey.common, link); + + dnskey.flags = (uint16_t)n1; + dnskey.protocol = (uint8_t)n2; + dnskey.algorithm = (uint8_t)n3; + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_base64_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + dnskey.datalen = r.length; + dnskey.data = r.base; + + CHECK(dns_rdata_fromstruct(NULL, dnskey.common.rdclass, + dnskey.common.rdtype, + &dnskey, &rrdatabuf)); + CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_dnskey, + keyname, &rrdatabuf)); + break; + case INITIAL_DS: + case STATIC_DS: + ds.common.rdclass = dns_rdataclass_in; + ds.common.rdtype = dns_rdatatype_ds; + ds.mctx = NULL; + + ISC_LINK_INIT(&ds.common, link); + + ds.key_tag = (uint16_t)n1; + ds.algorithm = (uint8_t)n2; + ds.digest_type = (uint8_t)n3; + + datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); + CHECK(isc_hex_decodestring(datastr, &databuf)); + isc_buffer_usedregion(&databuf, &r); + + switch (ds.digest_type) { + case DNS_DSDIGEST_SHA1: + if (r.length != ISC_SHA1_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA256: + if (r.length != ISC_SHA256_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + case DNS_DSDIGEST_SHA384: + if (r.length != ISC_SHA384_DIGESTLENGTH) { + CHECK(ISC_R_UNEXPECTEDEND); + } + break; + } - keystr = cfg_obj_asstring(cfg_tuple_get(key, "data")); - CHECK(isc_base64_decodestring(keystr, &keydatabuf)); - isc_buffer_usedregion(&keydatabuf, &r); - keystruct.datalen = r.length; - keystruct.data = r.base; + ds.length = r.length; + ds.digest = r.base; - CHECK(dns_rdata_fromstruct(NULL, keystruct.common.rdclass, - keystruct.common.rdtype, - &keystruct, &rrdatabuf)); + CHECK(dns_rdata_fromstruct(NULL, ds.common.rdclass, + ds.common.rdtype, + &ds, &rrdatabuf)); + CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_ds, + keyname, &rrdatabuf)); + }; - CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, - keyname, &rrdatabuf)); num_keys++; cleanup: diff --git a/lib/dns/client.c b/lib/dns/client.c index 971c4e3af26..58da8506e42 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -69,6 +69,13 @@ #define RESOLVER_NTASKS 31 #endif /* TUNE_LARGE */ +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + /*% * DNS client object */ @@ -1482,12 +1489,19 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) { isc_result_t dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, - const dns_name_t *keyname, isc_buffer_t *keydatabuf) + dns_rdatatype_t rdtype, const dns_name_t *keyname, + isc_buffer_t *databuf) { isc_result_t result; dns_view_t *view = NULL; dst_key_t *dstkey = NULL; dns_keytable_t *secroots = NULL; + dns_name_t *name = NULL; + char dsbuf[DNS_DS_BUFFERSIZE]; + dns_rdata_ds_t ds; + dns_decompress_t dctx; + dns_rdata_t rdata; + isc_buffer_t b; REQUIRE(DNS_CLIENT_VALID(client)); @@ -1495,28 +1509,49 @@ dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, rdclass, &view); UNLOCK(&client->lock); - if (result != ISC_R_SUCCESS) - goto cleanup; + CHECK(result); - result = dns_view_getsecroots(view, &secroots); - if (result != ISC_R_SUCCESS) - goto cleanup; + CHECK(dns_view_getsecroots(view, &secroots)); - result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx, - &dstkey); - if (result != ISC_R_SUCCESS) - goto cleanup; + DE_CONST(keyname, name); + + switch (rdtype) { + case dns_rdatatype_dnskey: + result = dst_key_fromdns(keyname, rdclass, databuf, + client->mctx, &dstkey); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + CHECK(dns_keytable_add(secroots, false, false, + name, &dstkey, NULL)); + break; + case dns_rdatatype_ds: + isc_buffer_init(&b, dsbuf, sizeof(dsbuf)); + dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); + dns_rdata_init(&rdata); + isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf)); + CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, + databuf, &dctx, 0, &b)); + dns_decompress_invalidate(&dctx); + CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); + CHECK(dns_keytable_add(secroots, false, false, + name, NULL, &ds)); + break; - result = dns_keytable_add(secroots, false, false, - dst_key_name(dstkey), &dstkey, NULL); + default: + result = ISC_R_NOTIMPLEMENTED; + } cleanup: - if (dstkey != NULL) + if (dstkey != NULL) { dst_key_free(&dstkey); - if (view != NULL) + } + if (view != NULL) { dns_view_detach(&view); - if (secroots != NULL) + } + if (secroots != NULL) { dns_keytable_detach(&secroots); + } return (result); } diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index d661e2deba6..1740004892e 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -385,11 +385,13 @@ dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist); isc_result_t dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, - const dns_name_t *keyname, isc_buffer_t *keydatabuf); + dns_rdatatype_t rdtype, const dns_name_t *keyname, + isc_buffer_t *keydatabuf); /*%< * Add a DNSSEC trusted key for the 'rdclass' class. A view for the 'rdclass' - * class must be created beforehand. 'keyname' is the DNS name of the key, - * and 'keydatabuf' stores the resource data of the key. + * class must be created beforehand. 'rdtype' is the type of the RR data + * for the key, either DNSKEY or DS. 'keyname' is the DNS name of the key, + * and 'keydatabuf' stores the RR data. * * Requires: * diff --git a/lib/irs/context.c b/lib/irs/context.c index a359c1ee890..d1b71c42041 100644 --- a/lib/irs/context.c +++ b/lib/irs/context.c @@ -255,6 +255,7 @@ irs_context_create(irs_context_t **contextp) { trustedkey != NULL; trustedkey = ISC_LIST_NEXT(trustedkey, link)) { result = dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_dnskey, trustedkey->keyname, trustedkey->keydatabuf); if (result != ISC_R_SUCCESS) diff --git a/lib/samples/resolve.c b/lib/samples/resolve.c index 1715c5c89ea..587d159f443 100644 --- a/lib/samples/resolve.c +++ b/lib/samples/resolve.c @@ -162,6 +162,7 @@ set_key(dns_client_t *client, char *keynamestr, char *keystr, exit(1); } result = dns_client_addtrustedkey(client, dns_rdataclass_in, + dns_rdatatype_dnskey, keyname, &rrdatabuf); if (result != ISC_R_SUCCESS) { fprintf(stderr, "failed to add key for %s\n",