From fc3dd703d8a70bd4f95d3f35503ef68b5197e36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 28 Jun 2018 13:38:39 +0200 Subject: [PATCH] Enable dns_zoneverify_dnssec() to check whether the zone was signed by a trust anchor Extend check_dnskey_sigs() so that, if requested, it checks whether the DNSKEY RRset at zone apex is signed by at least one trust anchor. The trust anchor table is passed as an argument to dns_zoneverify_dnssec() and passed around in the verification context structure. Neither dnssec-signzone nor dnssec-verify are yet modified to make use of that feature, though. --- bin/dnssec/dnssec-signzone.c | 2 +- bin/dnssec/dnssec-verify.c | 4 +- lib/dns/include/dns/zoneverify.h | 4 +- lib/dns/zoneverify.c | 81 ++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 15 deletions(-) diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index 2747c627fd..893ca3fa20 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -3916,7 +3916,7 @@ main(int argc, char *argv[]) { vresult = ISC_R_SUCCESS; } else { vresult = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin, - mctx, ignore_kskflag, + NULL, mctx, ignore_kskflag, keyset_kskonly); if (vresult != ISC_R_SUCCESS) { fprintf(output_stdout ? stderr : stdout, diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c index 3fb5fa2c49..7d087241a3 100644 --- a/bin/dnssec/dnssec-verify.c +++ b/bin/dnssec/dnssec-verify.c @@ -323,8 +323,8 @@ main(int argc, char *argv[]) { result = dns_db_newversion(gdb, &gversion); check_result(result, "dns_db_newversion()"); - result = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin, mctx, - ignore_kskflag, keyset_kskonly); + result = dns_zoneverify_dnssec(NULL, gdb, gversion, gorigin, NULL, + mctx, ignore_kskflag, keyset_kskonly); dns_db_closeversion(gdb, &gversion, ISC_FALSE); dns_db_detach(&gdb); diff --git a/lib/dns/include/dns/zoneverify.h b/lib/dns/include/dns/zoneverify.h index 0e491c23dd..594c6ecc08 100644 --- a/lib/dns/include/dns/zoneverify.h +++ b/lib/dns/include/dns/zoneverify.h @@ -33,8 +33,8 @@ ISC_LANG_BEGINDECLS */ isc_result_t dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, - dns_name_t *origin, isc_mem_t *mctx, - isc_boolean_t ignore_kskflag, + dns_name_t *origin, dns_keytable_t *secroots, + isc_mem_t *mctx, isc_boolean_t ignore_kskflag, isc_boolean_t keyset_kskonly); ISC_LANG_ENDDECLS diff --git a/lib/dns/zoneverify.c b/lib/dns/zoneverify.c index 52c37a72a7..cf130963e8 100644 --- a/lib/dns/zoneverify.c +++ b/lib/dns/zoneverify.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,7 @@ typedef struct vctx { dns_db_t * db; dns_dbversion_t * ver; dns_name_t * origin; + dns_keytable_t * secroots; isc_boolean_t goodksk; isc_boolean_t goodzsk; dns_rdataset_t keyset; @@ -1315,7 +1317,7 @@ verifyemptynodes(const vctx_t *vctx, const dns_name_t *name, static isc_result_t vctx_init(vctx_t *vctx, isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, - dns_dbversion_t *ver, dns_name_t *origin) + dns_dbversion_t *ver, dns_name_t *origin, dns_keytable_t *secroots) { isc_result_t result; @@ -1326,6 +1328,7 @@ vctx_init(vctx_t *vctx, isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, vctx->db = db; vctx->ver = ver; vctx->origin = origin; + vctx->secroots = secroots; vctx->goodksk = ISC_FALSE; vctx->goodzsk = ISC_FALSE; @@ -1491,17 +1494,21 @@ check_apex_rrsets(vctx_t *vctx) { * Update 'vctx' tables tracking active and standby key algorithms used in the * verified zone based on the signatures made using 'dnskey' (prepared from * 'rdata') found at zone apex. Set 'vctx->goodksk' or 'vctx->goodzsk' to true - * if 'dnskey' correctly signs the DNSKEY RRset at zone apex. + * if 'dnskey' correctly signs the DNSKEY RRset at zone apex and either + * 'vctx->secroots' is NULL or 'dnskey' is present in 'vctx->secroots'. * * The variables to update are chosen based on 'is_ksk', which is true when * 'dnskey' is a KSK and false otherwise. */ -static void +static isc_result_t check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey, dns_rdata_t *rdata, isc_boolean_t is_ksk) { unsigned char *active_keys, *standby_keys; + dns_keynode_t *keynode = NULL; isc_boolean_t *goodkey; + dst_key_t *key = NULL; + isc_result_t result; active_keys = (is_ksk ? vctx->ksk_algorithms : vctx->zsk_algorithms); standby_keys = (is_ksk ? vctx->standby_ksk : vctx->standby_zsk); @@ -1513,7 +1520,6 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey, if (active_keys[dnskey->algorithm] != 255) { active_keys[dnskey->algorithm]++; } - *goodkey = ISC_TRUE; } else if (!is_ksk && dns_dnssec_signs(rdata, vctx->origin, &vctx->soaset, &vctx->soasigs, ISC_FALSE, vctx->mctx)) @@ -1521,11 +1527,65 @@ check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey, if (active_keys[dnskey->algorithm] != 255) { active_keys[dnskey->algorithm]++; } + return (ISC_R_SUCCESS); } else { if (standby_keys[dnskey->algorithm] != 255) { standby_keys[dnskey->algorithm]++; } + return (ISC_R_SUCCESS); } + + /* + * If a trust anchor table was not supplied, a correctly self-signed + * DNSKEY RRset is good enough. + */ + if (vctx->secroots == NULL) { + *goodkey = ISC_TRUE; + return (ISC_R_SUCCESS); + } + + /* + * Look up the supplied key in the trust anchor table. + */ + result = dns_dnssec_keyfromrdata(vctx->origin, rdata, vctx->mctx, + &key); + if (result != ISC_R_SUCCESS) { + return (result); + } + result = dns_keytable_findkeynode(vctx->secroots, vctx->origin, + dst_key_alg(key), dst_key_id(key), + &keynode); + switch (result) { + case ISC_R_SUCCESS: + /* + * The supplied key is a trust anchor. + */ + dns_keytable_detachkeynode(vctx->secroots, &keynode); + *goodkey = ISC_TRUE; + break; + case DNS_R_PARTIALMATCH: + case ISC_R_NOTFOUND: + /* + * The supplied key is not present in the trust anchor table, + * but other keys signing the DNSKEY RRset may be, so this is + * not an error, we just do not set 'vctx->good[kz]sk'. + */ + result = ISC_R_SUCCESS; + break; + default: + /* + * An error occurred while searching the trust anchor table, + * return it to the caller. + */ + break; + } + + /* + * Clean up. + */ + dst_key_free(&key); + + return (result); } /*% @@ -1914,14 +1974,15 @@ print_summary(const vctx_t *vctx, isc_boolean_t keyset_kskonly) { isc_result_t dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, - dns_name_t *origin, isc_mem_t *mctx, - isc_boolean_t ignore_kskflag, + dns_name_t *origin, dns_keytable_t *secroots, + isc_mem_t *mctx, isc_boolean_t ignore_kskflag, isc_boolean_t keyset_kskonly) { + const char *keydesc = (secroots == NULL ? "self-signed" : "trusted"); isc_result_t result, vresult = ISC_R_UNSET; vctx_t vctx; - result = vctx_init(&vctx, mctx, zone, db, ver, origin); + result = vctx_init(&vctx, mctx, zone, db, ver, origin, secroots); if (result != ISC_R_SUCCESS) { return (result); } @@ -1938,13 +1999,13 @@ dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, if (ignore_kskflag) { if (!vctx.goodksk && !vctx.goodzsk) { - zoneverify_log_error(&vctx, - "No self-signed DNSKEY found"); + zoneverify_log_error(&vctx, "No %s DNSKEY found", + keydesc); result = ISC_R_FAILURE; goto done; } } else if (!vctx.goodksk) { - zoneverify_log_error(&vctx, "No self-signed KSK DNSKEY found"); + zoneverify_log_error(&vctx, "No %s KSK DNSKEY found", keydesc); result = ISC_R_FAILURE; goto done; }