#include <dns/journal.h>
#include <dns/kasp.h>
#include <dns/keydata.h>
+#include <dns/keymgr.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/log.h>
isc_time_t now;
isc_time_t loadtime;
dns_db_t *db = NULL;
- bool rbt, hasraw;
+ bool rbt, hasraw, is_dynamic;
REQUIRE(DNS_ZONE_VALID(zone));
goto cleanup;
}
- if (zone->db != NULL && dns_zone_isdynamic(zone, false)) {
+ is_dynamic = dns_zone_isdynamic(zone, false) ||
+ dns_zone_getkasp(zone) != NULL;
+ if (zone->db != NULL && is_dynamic) {
/*
- * This is a slave, stub, or dynamically updated
- * zone being reloaded. Do nothing - the database
- * we already have is guaranteed to be up-to-date.
+ * This is a slave, stub, dynamically updated, or kasp enabled
+ * zone being reloaded. Do nothing - the database we already
+ * have is guaranteed to be up-to-date.
*/
if (zone->type == dns_zone_master && !hasraw)
result = DNS_R_DYNAMIC;
dns_db_t *db = NULL;
/* We only re-sign zones that can be dynamically updated */
- if (zone->update_disabled)
+ if (zone->update_disabled) {
return;
+ }
if (!inline_secure(zone) && (zone->type != dns_zone_master ||
(zone->ssutable == NULL &&
goto cleanup;
}
- resign = rdataset.resign - zone->sigresigninginterval;
+ resign = rdataset.resign - dns_zone_getsigresigninginterval(zone);
dns_rdataset_disassociate(&rdataset);
nanosecs = isc_random_uniform(1000000000);
isc_time_set(&zone->resigntime, resign, nanosecs);
+
cleanup:
dns_db_detach(&db);
return;
dns_rdata_t rdata = DNS_RDATA_INIT;
bool dynamic = (zone->type == dns_zone_master)
? dns_zone_isdynamic(zone, false) : false;
+ dynamic = dynamic || dns_zone_getkasp(zone);
dns_rdataset_init(&rdataset);
result = dns_db_findnode(db, &zone->origin, false, &node);
bool had_db = false;
unsigned int options;
dns_include_t *inc;
+ bool is_dynamic = false;
INSIST(LOCKED_ZONE(zone));
if (inline_raw(zone)) {
* journal file if it isn't, as we wouldn't be able to apply
* updates otherwise.
*/
- if (zone->journal != NULL && dns_zone_isdynamic(zone, true) &&
+ is_dynamic = dns_zone_isdynamic(zone, true) ||
+ dns_zone_getkasp(zone) != NULL;
+ if (zone->journal != NULL && is_dynamic &&
! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS))
{
uint32_t jserial;
if (zone->type == dns_zone_master &&
(zone->update_acl != NULL || zone->ssutable != NULL) &&
- zone->sigresigninginterval < (3 * refresh) &&
+ dns_zone_getsigresigninginterval(zone) < (3 * refresh) &&
dns_db_issecure(db))
{
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
resume_addnsec3chain(zone);
}
+ is_dynamic = dns_zone_isdynamic(zone, false) ||
+ dns_zone_getkasp(zone) != NULL;
if (zone->type == dns_zone_master &&
!DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_NORESIGN) &&
- dns_zone_isdynamic(zone, false) &&
- dns_db_issecure(db))
+ is_dynamic && dns_db_issecure(db))
{
dns_name_t *name;
dns_fixedname_t fixed;
"next resign: %s/%s "
"in %d seconds", namebuf, typebuf,
next.resign - timenow -
- zone->sigresigninginterval);
+ dns_zone_getsigresigninginterval(zone));
dns_rdataset_disassociate(&next);
} else {
dnssec_log(zone, ISC_LOG_WARNING,
zone->nincludes++;
}
- if (! dns_db_ispersistent(db)) {
+ if (!dns_db_ispersistent(db)) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
ISC_LOG_INFO, "loaded serial %u%s", serial,
dns_db_issecure(db) ? " (DNSSEC signed)" : "");
} else if (zone->type == dns_zone_master ||
zone->type == dns_zone_redirect)
{
- if (! (inline_secure(zone) && result == ISC_R_FILENOTFOUND)) {
+ if (!(inline_secure(zone) && result == ISC_R_FILENOTFOUND)) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD,
ISC_LOG_ERROR,
"not loaded due to errors.");
bool *warn)
{
unsigned int i = 0;
+ isc_result_t ret;
bool have_ksk = false, have_zsk = false;
bool have_pksk = false, have_pzsk = false;
for (i = 0; i < nkeys; i++) {
- if (rrsig_ptr->algorithm != dst_key_alg(keys[i]))
+ bool ksk, zsk;
+
+ if (have_pksk && have_ksk && have_pzsk && have_zsk) {
+ break;
+ }
+
+ if (rrsig_ptr->algorithm != dst_key_alg(keys[i])) {
continue;
- if (dst_key_isprivate(keys[i])) {
- if (KSK(keys[i]))
- have_ksk = have_pksk = true;
- else
- have_zsk = have_pzsk = true;
- } else {
- if (KSK(keys[i]))
- have_ksk = true;
- else
- have_zsk = true;
+ }
+
+ ret = dst_key_getbool(keys[i], DST_BOOL_KSK, &ksk);
+ if (ret != ISC_R_SUCCESS) {
+ ksk = KSK(keys[i]);
+ }
+ ret = dst_key_getbool(keys[i], DST_BOOL_ZSK, &zsk);
+ if (ret != ISC_R_SUCCESS) {
+ zsk = !KSK(keys[i]);
+ }
+
+ if (ksk) {
+ have_ksk = true;
+ if (dst_key_isprivate(keys[i])) {
+ have_pksk = true;
+ }
+ }
+ if (zsk) {
+ have_zsk = true;
+ if (dst_key_isprivate(keys[i])) {
+ have_pzsk = true;
+ }
}
}
{
isc_result_t result;
dns_dbnode_t *node = NULL;
+ dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_stats_t* dnssecsignstats;
dns_stats_t* dnssecrefreshstats;
dns_rdataset_t rdataset;
isc_buffer_t buffer;
unsigned int i, j;
+ if (kasp != NULL) {
+ check_ksk = false;
+ keyset_kskonly = true;
+ }
+
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
}
}
- if (both) {
+ if (kasp != NULL) {
+ /*
+ * A dnssec-policy is found. Check what RRsets this
+ * key should sign.
+ */
+ isc_result_t kresult;
+ bool ksk = false;
+ bool zsk = false;
+
+ kresult = dst_key_getbool(keys[i], DST_BOOL_KSK, &ksk);
+ if (kresult != ISC_R_SUCCESS) {
+ if (KSK(keys[i])) {
+ ksk = true;
+ }
+ }
+ kresult = dst_key_getbool(keys[i], DST_BOOL_ZSK, &zsk);
+ if (kresult != ISC_R_SUCCESS) {
+ if (!KSK(keys[i])) {
+ zsk = true;
+ }
+ }
+
+ if (type == dns_rdatatype_dnskey ||
+ type == dns_rdatatype_cdnskey ||
+ type == dns_rdatatype_cds)
+ {
+ /*
+ * DNSKEY RRset is signed with KSK.
+ * CDS and CDNSKEY RRsets too (RFC 7344, 4.1).
+ */
+ if (!ksk) {
+ continue;
+ }
+ } else if (!zsk) {
+ /*
+ * Other RRsets are signed with ZSK.
+ */
+ continue;
+ }
+
+ /*
+ * If this key is revoked, it may only sign the
+ * DNSKEY RRset.
+ */
+ if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey) {
+ continue;
+ }
+ } else if (both) {
/*
* CDS and CDNSKEY are signed with KSK (RFC 7344, 4.1).
*/
goto failure;
}
- sigvalidityinterval = zone->sigvalidityinterval;
+ sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
inception = now - 3600; /* Allow for clock skew. */
soaexpire = now + sigvalidityinterval;
expiryinterval = dns_zone_getsigresigninginterval(zone);
i = 0;
while (result == ISC_R_SUCCESS) {
- resign = rdataset.resign - zone->sigresigninginterval;
+ resign = rdataset.resign -
+ dns_zone_getsigresigninginterval(zone);
covers = rdataset.covers;
dns_rdataset_disassociate(&rdataset);
dns_dbnode_t *node, dns_dbversion_t *version,
bool build_nsec3, bool build_nsec, dst_key_t *key,
isc_stdtime_t inception, isc_stdtime_t expire,
- unsigned int minimum, bool is_ksk,
+ unsigned int minimum, bool is_ksk, bool is_zsk,
bool keyset_kskonly, bool is_bottom_of_zone,
dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx)
{
if (!is_ksk && keyset_kskonly) {
goto next_rdataset;
}
- } else if (is_ksk) {
+ } else if (!is_zsk) {
goto next_rdataset;
}
if (seen_ns && !seen_soa &&
if (signed_with_good_key(zone, db, node, version, rdataset.type, key)) {
goto next_rdataset;
}
+
/* Calculate the signature, creating a RRSIG RDATA. */
isc_buffer_clear(&buffer);
CHECK(dns_dnssec_sign(name, &rdataset, key, &inception,
dns__zonediff_t zonediff;
dns_fixedname_t fixed;
dns_fixedname_t nextfixed;
+ dns_kasp_t *kasp;
dns_name_t *name, *nextname;
dns_rdataset_t rdataset;
dns_signing_t *signing, *nextsigning;
dns_signinglist_t cleanup;
dst_key_t *zone_keys[DNS_MAXZONEKEYS];
int32_t signatures;
- bool check_ksk, keyset_kskonly, is_ksk;
+ bool check_ksk, keyset_kskonly, is_ksk, is_zsk;
bool with_ksk, with_zsk;
bool commit = false;
bool is_bottom_of_zone;
goto cleanup;
}
+ kasp = dns_zone_getkasp(zone);
+
sigvalidityinterval = dns_zone_getsigvalidityinterval(zone);
inception = now - 3600; /* Allow for clock skew. */
soaexpire = now + sigvalidityinterval;
signing = ISC_LIST_HEAD(zone->signing);
first = true;
- check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
- keyset_kskonly = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);
+ check_ksk = (kasp != NULL) ? false :
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+ keyset_kskonly = (kasp != NULL) ? true :
+ DNS_ZONE_OPTION(zone, DNS_ZONEOPT_DNSKEYKSKONLY);
/* Determine which type of chain to build */
CHECK(dns_private_chains(db, version, zone->privatetype,
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (signing->done || signing->db != zone->db) {
/*
- * The zone has been reloaded. We will have
+ * The zone has been reloaded. We will have to
* created new signings as part of the reload
* process so we can destroy this one.
*/
if (ALG(zone_keys[i]) == signing->algorithm &&
dst_key_id(zone_keys[i]) == signing->keyid)
{
- if (KSK(zone_keys[i]))
+ bool ksk = false;
+ isc_result_t ret = dst_key_getbool(
+ zone_keys[i], DST_BOOL_KSK, &ksk);
+ if (ret != ISC_R_SUCCESS) {
+ ksk = KSK(zone_keys[i]);
+ }
+ if (ksk) {
dst_key_free(&zone_keys[i]);
+ }
continue;
}
zone_keys[j] = zone_keys[i];
}
}
}
- if (both || REVOKE(zone_keys[i])) {
+ if (kasp != NULL) {
+ /*
+ * A dnssec-policy is found. Check what
+ * RRsets this key can sign.
+ */
+ isc_result_t kresult;
+ is_ksk = false;
+ kresult = dst_key_getbool(zone_keys[i],
+ DST_BOOL_KSK,
+ &is_ksk);
+ if (kresult != ISC_R_SUCCESS) {
+ if (KSK(zone_keys[i])) {
+ is_ksk = true;
+ }
+ }
+
+ is_zsk = false;
+ kresult = dst_key_getbool(zone_keys[i],
+ DST_BOOL_ZSK,
+ &is_zsk);
+ if (kresult != ISC_R_SUCCESS) {
+ if (!KSK(zone_keys[i])) {
+ is_zsk = true;
+ }
+ }
+ /* Treat as if we have both KSK and ZSK. */
+ both = true;
+ } else if (both || REVOKE(zone_keys[i])) {
is_ksk = KSK(zone_keys[i]);
+ is_zsk = !KSK(zone_keys[i]);
} else {
is_ksk = false;
+ is_zsk = true;
}
/*
* the RRset is still signed at least once by a
* KSK and a ZSK.
*/
- if (signing->deleteit && !is_ksk && with_zsk) {
+ if (signing->deleteit && is_zsk && with_zsk) {
continue;
}
CHECK(sign_a_node(db, zone, name, node, version,
build_nsec3, build_nsec,
zone_keys[i], inception, expire,
- zone->minimum, is_ksk,
+ zone->minimum, is_ksk, is_zsk,
(both && keyset_kskonly),
is_bottom_of_zone, zonediff.diff,
&signatures, zone->mctx));
if (!signing->deleteit) {
break;
}
- if (!is_ksk) {
+ if (is_zsk) {
with_zsk = true;
}
- if (KSK(zone_keys[i])) {
+ if (is_ksk) {
with_ksk = true;
}
}
dns_dnsseckeylist_t dnskeys, keys, rmkeys;
dns_dnsseckey_t *key = NULL;
dns_diff_t diff, _sig_diff;
+ dns_kasp_t *kasp;
dns__zonediff_t zonediff;
bool commit = false, newactive = false;
bool newalg = false;
dns_ttl_t ttl = 3600;
const char *dir = NULL;
isc_mem_t *mctx = NULL;
- isc_stdtime_t now;
+ isc_stdtime_t now, nexttime = 0;
isc_time_t timenow;
isc_interval_t ival;
char timebuf[80];
* True when called from "rndc sign". Indicates the zone should be
* fully signed now.
*/
+ kasp = dns_zone_getkasp(zone);
fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN);
result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx,
&keys);
+ if (result != ISC_R_SUCCESS) {
+ dnssec_log(zone, ISC_LOG_DEBUG(1),
+ "zone_rekey:dns_dnssec_findmatchingkeys failed: %s",
+ isc_result_totext(result));
+ }
+
+ if (kasp && (result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND)) {
+ result = dns_keymgr_run(&zone->origin, zone->rdclass, dir,
+ mctx, &keys, kasp, now, &nexttime);
+ if (result != ISC_R_SUCCESS) {
+ dnssec_log(zone, ISC_LOG_ERROR,
+ "zone_rekey:dns_dnssec_keymgr failed: %s",
+ isc_result_totext(result));
+ goto failure;
+ }
+ }
+
if (result == ISC_R_SUCCESS) {
- bool check_ksk;
- check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
&zone->origin, ttl, &diff,
mctx, dnssec_report);
/*
* This isn't a new algorithm; clear
* first_sign so we won't sign the
- * whole zone with this key later
+ * whole zone with this key later.
*/
key->first_sign = false;
} else {
isc_time_settoepoch(&zone->refreshkeytime);
+ /*
+ * If keymgr provided a next time, use the calculated next rekey time.
+ */
+ if (kasp != NULL && nexttime > 0) {
+ isc_time_t timenext;
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_TIME_ADD(&timenow, nexttime - now, &timenext);
+ zone->refreshkeytime = timenext;
+ UNLOCK_ZONE(zone);
+
+ zone_settimer(zone, &timenow);
+ isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
+ dnssec_log(zone, ISC_LOG_DEBUG(3),
+ "next key event in %u seconds: %s",
+ (nexttime - now), timebuf);
+ dnssec_log(zone, ISC_LOG_INFO, "next key event: %s", timebuf);
+ }
/*
* If we're doing key maintenance, set the key refresh timer to
* the next scheduled key event or to 'dnssec-loadkeys-interval'
* seconds in the future, whichever is sooner.
*/
- if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
+ else if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) {
isc_time_t timethen;
isc_stdtime_t then;
LOCK_ZONE(zone);
if (!inline_secure(zone)) {
- if (!dns_zone_isdynamic(zone, true)) {
+ if (!dns_zone_isdynamic(zone, true) &&
+ dns_zone_getkasp(zone) == NULL) {
result = DNS_R_NOTDYNAMIC;
goto failure;
}