From 6f6d0001034cd2f08f08ba9ffe673166df11a8bd Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 19 Jun 2024 12:27:58 +0200 Subject: [PATCH] Apply SKR bundle on rekey When a zone has a skr structure, lookup the currently active bundle that contains the right key and signature material. (cherry picked from commit 63e058c29e9711f9603e5c8a2cd5170899097a0f) --- lib/dns/zone.c | 132 +++++++++++++++++++++++++++++++++-- lib/isc/include/isc/result.h | 2 + lib/isc/result.c | 4 ++ 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index f7dc498871..856a2c669e 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -21901,6 +21901,71 @@ update_ttl(dns_rdataset_t *rdataset, dns_name_t *name, dns_ttl_t ttl, return (ISC_R_SUCCESS); } +static void +remove_rdataset(dns_zone_t *zone, dns_diff_t *diff, dns_rdataset_t *rdataset) { + if (!dns_rdataset_isassociated(rdataset)) { + return; + } + + for (isc_result_t result = dns_rdataset_first(rdataset); + result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_difftuple_t *tuple = NULL; + + dns_rdataset_current(rdataset, &rdata); + dns_difftuple_create(zone->mctx, DNS_DIFFOP_DEL, &zone->origin, + rdataset->ttl, &rdata, &tuple); + dns_diff_append(diff, &tuple); + } + return; +} + +static void +add_tuple(dns_diff_t *diff, dns_difftuple_t *tuple) { + dns_difftuple_t *copy = NULL; + + dns_difftuple_copy(tuple, ©); + dns_diff_appendminimal(diff, ©); +} + +static void +zone_apply_skrbundle(dns_zone_t *zone, dns_skrbundle_t *bundle, + dns_rdataset_t *dnskeyset, dns_rdataset_t *cdsset, + dns_rdataset_t *cdnskeyset, dns_diff_t *diff) { + dns_kasp_t *kasp = zone->kasp; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(DNS_SKRBUNDLE_VALID(bundle)); + + /* Remove existing DNSKEY, CDS, and CDNSKEY records. */ + remove_rdataset(zone, diff, dnskeyset); + remove_rdataset(zone, diff, cdsset); + remove_rdataset(zone, diff, cdnskeyset); + + /* Add the records from the bundle. */ + dns_difftuple_t *tuple = ISC_LIST_HEAD(bundle->diff.tuples); + while (tuple != NULL) { + switch (tuple->rdata.type) { + case dns_rdatatype_dnskey: + add_tuple(diff, tuple); + break; + case dns_rdatatype_cdnskey: + case dns_rdatatype_cds: + add_tuple(diff, tuple); + break; + case dns_rdatatype_rrsig: + /* Not interested in right now */ + break; + default: + INSIST(0); + } + + tuple = ISC_LIST_NEXT(tuple, link); + } +} + static void zone_rekey(dns_zone_t *zone) { isc_result_t result; @@ -21912,10 +21977,13 @@ zone_rekey(dns_zone_t *zone) { dns_dnsseckey_t *key = NULL; dns_diff_t diff, _sig_diff; dns_kasp_t *kasp; + dns_skrbundle_t *bundle = NULL; dns__zonediff_t zonediff; bool commit = false, newactive = false; bool newalg = false; bool fullsign; + bool offlineksk = false; + uint32_t sigval = 0; dns_ttl_t ttl = 3600; const char *dir = NULL; isc_mem_t *mctx = NULL; @@ -21958,14 +22026,13 @@ zone_rekey(dns_zone_t *zone) { ttl = soaset.ttl; dns_rdataset_disassociate(&soaset); - /* - * Only update DNSKEY TTL if we have a policy. - */ if (kasp != NULL) { ttl = dns_kasp_dnskeyttl(kasp); + offlineksk = dns_kasp_offlineksk(kasp); + sigval = dns_kasp_sigvalidity_dnskey(kasp); } - /* Get the DNSKEY rdataset */ + /* Get the current DNSKEY rdataset */ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, dns_rdatatype_none, 0, &keyset, &keysigs); if (result == ISC_R_SUCCESS) { @@ -22007,7 +22074,7 @@ zone_rekey(dns_zone_t *zone) { goto failure; } - /* Get the CDS rdataset */ + /* Get the current CDS rdataset */ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cds, dns_rdatatype_none, 0, &cdsset, NULL); if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdsset)) { @@ -22026,7 +22093,7 @@ zone_rekey(dns_zone_t *zone) { cdsset.ttl = ttl; } - /* Get the CDNSKEY rdataset */ + /* Get the current CDNSKEY rdataset */ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_cdnskey, dns_rdatatype_none, 0, &cdnskeyset, NULL); if (result != ISC_R_SUCCESS && dns_rdataset_isassociated(&cdnskeyset)) { @@ -22054,6 +22121,59 @@ zone_rekey(dns_zone_t *zone) { */ fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN); + if (offlineksk) { + /* Lookup the correct bundle in the SKR. */ + LOCK_ZONE(zone); + if (zone->skr == NULL) { + UNLOCK_ZONE(zone); + dnssec_log(zone, ISC_LOG_DEBUG(1), + "zone_rekey:dns_skr_lookup failed: " + "no SKR available"); + result = DNS_R_NOSKRFILE; + goto failure; + } + bundle = dns_skr_lookup(zone->skr, now, sigval); + zone->skrbundle = bundle; + UNLOCK_ZONE(zone); + + if (bundle == NULL) { + char nowstr[26]; /* Minimal buf per ctime_r() spec. */ + char utc[sizeof("YYYYMMDDHHSSMM")]; + isc_buffer_t b; + isc_region_t r; + isc_buffer_init(&b, utc, sizeof(utc)); + + isc_stdtime_tostring(now, nowstr, sizeof(nowstr)); + (void)dns_time32_totext(now, &b); + isc_buffer_usedregion(&b, &r); + dnssec_log(zone, ISC_LOG_DEBUG(1), + "zone_rekey:dns_skr_lookup failed: " + "no available SKR bundle for time " + "%.*s (%s)", + (int)r.length, r.base, nowstr); + result = DNS_R_NOSKRBUNDLE; + goto failure; + } + + zone_apply_skrbundle(zone, bundle, &keyset, &cdsset, + &cdnskeyset, &diff); + + dns_skrbundle_t *next = ISC_LIST_NEXT(bundle, link); + if (next != NULL) { + if (nexttime == 0) { + nexttime = next->inception; + } + } else { + dnssec_log(zone, ISC_LOG_WARNING, + "zone_rekey: last bundle in skr, please " + "import new skr file"); + } + } + + /* + * DNSSEC Key and Signing Policy + */ + KASP_LOCK(kasp); dns_zone_lock_keyfiles(zone); diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h index 4d2aedcc77..d359924177 100644 --- a/lib/isc/include/isc/result.h +++ b/lib/isc/include/isc/result.h @@ -226,6 +226,8 @@ typedef enum isc_result { DNS_R_HAVEPARMKEYS, DNS_R_NOALPN, DNS_R_NODOHPATH, + DNS_R_NOSKRFILE, + DNS_R_NOSKRBUNDLE, DST_R_UNSUPPORTEDALG, DST_R_CRYPTOFAILURE, diff --git a/lib/isc/result.c b/lib/isc/result.c index 765105ab55..8caa32274d 100644 --- a/lib/isc/result.c +++ b/lib/isc/result.c @@ -225,6 +225,8 @@ static const char *description[ISC_R_NRESULTS] = { [DNS_R_HAVEPARMKEYS] = "unexpected service parameter keys", [DNS_R_NOALPN] = "no ALPN", [DNS_R_NODOHPATH] = "no DOHPATH", + [DNS_R_NOSKRFILE] = "no SKR file", + [DNS_R_NOSKRBUNDLE] = "no available SKR bundle", [DST_R_UNSUPPORTEDALG] = "algorithm is unsupported", [DST_R_CRYPTOFAILURE] = "crypto failure", @@ -477,6 +479,8 @@ static const char *identifier[ISC_R_NRESULTS] = { [DNS_R_HAVEPARMKEYS] = "DNS_R_HAVEPARMKEYS", [DNS_R_NOALPN] = "DNS_R_NOALPN", [DNS_R_NODOHPATH] = "DNS_R_NODOHPATH", + [DNS_R_NOSKRFILE] = "DNS_R_NOSKRFILE", + [DNS_R_NOSKRBUNDLE] = "DNS_R_NOSKRBUNDLE", [DST_R_UNSUPPORTEDALG] = "DST_R_UNSUPPORTEDALG", [DST_R_CRYPTOFAILURE] = "DST_R_CRYPTOFAILURE",