diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index d99b54919a58e7b5dbc77c5e590b36379bf25a57..4e28fe4b3349594d84209956008668e749b21b28 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -64,7 +64,7 @@ DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \ db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \ dlz.@O@ dns64.@O@ dnsrps.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ \ ecs.@O@ fixedname.@O@ forward.@O@ \ - ipkeylist.@O@ iptable.@O@ journal.@O@ keydata.@O@ \ + ipkeylist.@O@ iptable.@O@ journal.@O@ kasp.@O@ keydata.@O@ \ keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \ master.@O@ masterdump.@O@ message.@O@ \ name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ nta.@O@ \ @@ -101,8 +101,8 @@ DNSSRCS = acl.c adb.c badcache. byaddr.c \ db.c dbiterator.c dbtable.c diff.c dispatch.c \ dlz.c dns64.c dnsrps.c dnssec.c ds.c dyndb.c \ ecs.c fixedname.c forward.c \ - ipkeylist.c iptable.c journal.c keydata.c keytable.c lib.c \ - log.c lookup.c master.c masterdump.c message.c \ + ipkeylist.c iptable.c journal.c kasp.c keydata.c keytable.c \ + lib.c log.c lookup.c master.c masterdump.c message.c \ name.c ncache.c nsec.c nsec3.c nta.c \ order.c peer.c portlist.c \ rbt.c rbtdb.c rcode.c rdata.c rdatalist.c \ diff --git a/lib/dns/include/dns/kasp.h b/lib/dns/include/dns/kasp.h new file mode 100644 index 0000000000000000000000000000000000000000..12998d46ff33c7cb6e82546ef23ff629aa5b7b08 --- /dev/null +++ b/lib/dns/include/dns/kasp.h @@ -0,0 +1,246 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#ifndef DNS_KASP_H +#define DNS_KASP_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file dns/kasp.h + * \brief + * DNSSEC Key and Signing Policy (KASP) + * + * A "kasp" is a DNSSEC policy, that determines how a zone should be + * signed and maintained. + */ + +#include + +#include +#include +#include +#include + +#include + +ISC_LANG_BEGINDECLS + +/* Stores a KASP key */ +struct dns_kasp_key { + isc_mem_t* mctx; + + /* Locked by themselves. */ + isc_refcount_t references; + + /* Under owner's locking control. */ + ISC_LINK(struct dns_kasp_key) link; + + /* Configuration */ + time_t lifetime; + uint32_t algorithm; + int length; + uint8_t role; +}; + +/* Stores a DNSSEC policy */ +struct dns_kasp { + unsigned int magic; + isc_mem_t* mctx; + char* name; + + /* Internals. */ + isc_mutex_t lock; + bool frozen; + + /* Locked by themselves. */ + isc_refcount_t references; + + /* Under owner's locking control. */ + ISC_LINK(struct dns_kasp) link; + + /* Configuration: signatures */ + uint32_t signatures_refresh; + uint32_t signatures_validity; + uint32_t signatures_validity_dnskey; + + /* Configuration: Keys */ + dns_kasp_keylist_t keys; + uint32_t dnskey_ttl; + + /* Configuration: Timings */ + uint32_t publish_safety; + uint32_t retire_safety; + + // TODO: The rest of the KASP configuration +}; + +#define DNS_KASP_MAGIC ISC_MAGIC('K','A','S','P') +#define DNS_KASP_VALID(kasp) ISC_MAGIC_VALID(kasp, DNS_KASP_MAGIC) + +/* Defaults */ +#define DNS_KASP_SIG_REFRESH (86400*5) +#define DNS_KASP_SIG_VALIDITY (86400*14) +#define DNS_KASP_SIG_VALIDITY_DNSKEY (86400*14) +#define DNS_KASP_KEY_TTL (3600) +#define DNS_KASP_PUBLISH_SAFETY (300) +#define DNS_KASP_RETIRE_SAFETY (300) + +/* Key roles */ +#define DNS_KASP_KEY_ROLE_KSK 0x01 +#define DNS_KASP_KEY_ROLE_ZSK 0x02 + +isc_result_t +dns_kasp_create(isc_mem_t *mctx, const char* name, dns_kasp_t **kaspp); +/*%< + * Create a KASP. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'name' is a valid C string. + * + *\li kaspp != NULL && *kaspp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +void +dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + * + *\li 'source' is a valid, frozen kasp. + * + *\li 'targetp' points to a NULL dns_kasp_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + * + *\li While *targetp is attached, the kasp will not shut down. + */ + +void +dns_kasp_detach(dns_kasp_t **kaspp); +/*%< + * Detach KASP. + * + * Requires: + * + *\li 'kaspp' points to a valid dns_kasp_t * + * + * Ensures: + * + *\li *kaspp is NULL. + */ + +void +dns_kasp_freeze(dns_kasp_t *kasp); +/*%< + * Freeze kasp. No changes can be made to kasp configuration while frozen. + * + * Requires: + * + *\li 'kasp' is a valid, unfrozen kasp. + * + * Ensures: + * + *\li 'kasp' is frozen. + */ + +void +dns_kasp_thaw(dns_kasp_t *kasp); +/*%< + * Thaw kasp. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Ensures: + * + *\li 'kasp' is no longer frozen. + */ + +const char* +dns_kasp_getname(dns_kasp_t *kasp); +/*%< + * Get kasp name. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li name of 'kasp'. + */ + +isc_result_t +dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp); +/*%< + * Search for a kasp with name 'name' in 'list'. + * If found, '*kaspp' is (strongly) attached to it. + * + * Requires: + * + *\li 'kaspp' points to a NULL dns_kasp_t *. + * + * Returns: + * + *\li #ISC_R_SUCCESS A matching kasp was found. + *\li #ISC_R_NOTFOUND No matching kasp was found. + */ + +isc_result_t +dns_kasp_key_create(isc_mem_t* mctx, dns_kasp_key_t **keyp); +/*%< + * Create a key inside a KASP. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li keyp != NULL && *keyp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +void +dns_kasp_key_destroy(dns_kasp_key_t* key); +/*%< + * Destroy a KASP key. + * + * Requires: + * + *\li 'key' is a valid KASP key. + * + *\li kasp != NULL && key != NULL + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_KASP_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 329ee7d277706c9177ad44816e17e7450f792bbb..728fb0c0a1ff80ede8934a00353bd98ec45cb6ba 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -91,6 +91,10 @@ typedef struct dns_fwdtable dns_fwdtable_t; typedef struct dns_geoip_databases dns_geoip_databases_t; typedef struct dns_iptable dns_iptable_t; typedef uint32_t dns_iterations_t; +typedef struct dns_kasp dns_kasp_t; +typedef ISC_LIST(dns_kasp_t) dns_kasplist_t; +typedef struct dns_kasp_key dns_kasp_key_t; +typedef ISC_LIST(dns_kasp_key_t) dns_kasp_keylist_t; typedef uint16_t dns_keyflags_t; typedef struct dns_keynode dns_keynode_t; typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t; diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 0ad20356db6e2448f1dcf6122830ab7daf77860f..a80301f917cc4d22c34cb621151de939547184cc 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -665,6 +665,24 @@ dns_zone_unload(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +dns_kasp_t* +dns_zone_getkasp(dns_zone_t *zone); +/*%< + * Returns the current kasp. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setkasp(dns_zone_t *zone, dns_kasp_t* kasp); +/*%< + * Set kasp for zone. If a kasp is already set, it will be detached. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + void dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option, bool value); diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c new file mode 100644 index 0000000000000000000000000000000000000000..ce401cdb6ad0dbaff942f72b98f4e0158e94f39f --- /dev/null +++ b/lib/dns/kasp.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +isc_result_t +dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp) +{ + dns_kasp_t *kasp; + + REQUIRE(name != NULL); + REQUIRE(kaspp != NULL && *kaspp == NULL); + + kasp = isc_mem_get(mctx, sizeof(*kasp)); + kasp->mctx = NULL; + isc_mem_attach(mctx, &kasp->mctx); + + kasp->name = isc_mem_strdup(mctx, name); + isc_mutex_init(&kasp->lock); + kasp->frozen = false; + + isc_refcount_init(&kasp->references, 1); + + ISC_LINK_INIT(kasp, link); + + kasp->signatures_refresh = DNS_KASP_SIG_REFRESH; + kasp->signatures_validity = DNS_KASP_SIG_VALIDITY; + kasp->signatures_validity_dnskey = DNS_KASP_SIG_VALIDITY_DNSKEY; + + ISC_LIST_INIT(kasp->keys); + + kasp->dnskey_ttl = DNS_KASP_KEY_TTL; + kasp->publish_safety = DNS_KASP_PUBLISH_SAFETY; + kasp->retire_safety = DNS_KASP_RETIRE_SAFETY; + + // TODO: The rest of the KASP configuration + + kasp->magic = DNS_KASP_MAGIC; + *kaspp = kasp; + + return (ISC_R_SUCCESS); +} + +void +dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp) { + REQUIRE(DNS_KASP_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + isc_refcount_increment(&source->references); + *targetp = source; +} + +static inline void +destroy(dns_kasp_t *kasp) { + dns_kasp_key_t *key; + dns_kasp_key_t *key_next; + + for (key = ISC_LIST_HEAD(kasp->keys); key != NULL; key = key_next) { + key_next = ISC_LIST_NEXT(key, link); + ISC_LIST_UNLINK(kasp->keys, key, link); + dns_kasp_key_destroy(key); + } + ISC_INSIST(ISC_LIST_EMPTY(kasp->keys)); + + isc_mem_free(kasp->mctx, kasp->name); + isc_mem_putanddetach(&kasp->mctx, kasp, sizeof(*kasp)); +} + +void +dns_kasp_detach(dns_kasp_t **kaspp) { + REQUIRE(kaspp != NULL && DNS_KASP_VALID(*kaspp)); + dns_kasp_t *kasp = *kaspp; + *kaspp = NULL; + + if (isc_refcount_decrement(&kasp->references) == 1) { + destroy(kasp); + } +} + +void +dns_kasp_freeze(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + kasp->frozen = true; +} + +void +dns_kasp_thaw(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + kasp->frozen = false; +} + +const char* +dns_kasp_getname(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + return kasp->name; +} + +isc_result_t +dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp) +{ + dns_kasp_t *kasp; + + if (list == NULL) { + return (ISC_R_NOTFOUND); + } + INSIST(list != NULL); + + for (kasp = ISC_LIST_HEAD(*list); kasp != NULL; + kasp = ISC_LIST_NEXT(kasp, link)) + { + if (strcmp(kasp->name, name) == 0) { + break; + } + } + if (kasp == NULL) { + return (ISC_R_NOTFOUND); + } + dns_kasp_attach(kasp, kaspp); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_kasp_key_create(isc_mem_t* mctx, dns_kasp_key_t **keyp) +{ + dns_kasp_key_t *key; + + REQUIRE(keyp != NULL && *keyp == NULL); + + key = isc_mem_get(mctx, sizeof(*key)); + key->mctx = NULL; + isc_mem_attach(mctx, &key->mctx); + + ISC_LINK_INIT(key, link); + + key->lifetime = 0; + key->algorithm = 0; + key->length = -1; + key->role = 0; + *keyp = key; + return (ISC_R_SUCCESS); +} + +void +dns_kasp_key_destroy(dns_kasp_key_t* key) +{ + REQUIRE(key != NULL); + isc_mem_putanddetach(&key->mctx, key, sizeof(*key)); +} diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index a3c7a90af5a8a1ff4de3feac44716a0f5e6430bf..ce6e55b00c16f6178edb595587c835542b72401c 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -413,6 +413,15 @@ dns_journal_rollforward dns_journal_set_sourceserial dns_journal_write_transaction dns_journal_writediff +dns_kasp_create +dns_kasp_attach +dns_kasp_detach +dns_kasp_freeze +dns_kasp_getname +dns_kasp_key_create +dns_kasp_key_destroy +dns_kasp_thaw +dns_kasplist_find dns_keydata_fromdnskey dns_keydata_todnskey dns_keyflags_fromtext @@ -1154,6 +1163,7 @@ dns_zone_getidleout dns_zone_getincludes dns_zone_getjournal dns_zone_getjournalsize +dns_zone_getkasp dns_zone_getkeydirectory dns_zone_getkeyopts dns_zone_getkeyvalidityinterval @@ -1255,6 +1265,7 @@ dns_zone_setidleout dns_zone_setisself dns_zone_setjournal dns_zone_setjournalsize +dns_zone_setkasp dns_zone_setkeydirectory dns_zone_setkeyopt dns_zone_setkeyvalidityinterval diff --git a/lib/dns/win32/libdns.vcxproj.filters.in b/lib/dns/win32/libdns.vcxproj.filters.in index 56f12aeba2bce094d8c58adb12f1149e72a514a0..b06e21792b134c9d8c9610f0c9294d67192b8b8e 100644 --- a/lib/dns/win32/libdns.vcxproj.filters.in +++ b/lib/dns/win32/libdns.vcxproj.filters.in @@ -116,6 +116,9 @@ Library Source Files + + Library Source Files + Library Source Files @@ -449,6 +452,9 @@ Library Header Files + + Library Header Files + Library Header Files diff --git a/lib/dns/win32/libdns.vcxproj.in b/lib/dns/win32/libdns.vcxproj.in index 43c3acef8a1af4472f48f259bd1e9157e63bdf0c..9a749d28e6853881ad62c6ba68a6bd77a8d1812e 100644 --- a/lib/dns/win32/libdns.vcxproj.in +++ b/lib/dns/win32/libdns.vcxproj.in @@ -150,6 +150,7 @@ + @@ -265,6 +266,7 @@ + diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 6d5417955774be7ce5f4f9c49cd4faa9eb733650..720df2807a37a10d9b22bb4215aa027792408497 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -303,6 +304,7 @@ struct dns_zone { uint32_t sigresigninginterval; dns_view_t *view; dns_view_t *prev_view; + dns_kasp_t *kasp; dns_checkmxfunc_t checkmx; dns_checksrvfunc_t checksrv; dns_checknsfunc_t checkns; @@ -1014,6 +1016,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->sigvalidityinterval = 30 * 24 * 3600; zone->keyvalidityinterval = 0; zone->sigresigninginterval = 7 * 24 * 3600; + zone->kasp = NULL; zone->view = NULL; zone->prev_view = NULL; zone->checkmx = NULL; @@ -1184,6 +1187,9 @@ zone_free(dns_zone_t *zone) { isc_mem_free(zone->mctx, zone->keydirectory); } zone->keydirectory = NULL; + if (zone->kasp != NULL) { + dns_kasp_detach(&zone->kasp); + } zone->journalsize = -1; if (zone->journal != NULL) { isc_mem_free(zone->mctx, zone->journal); @@ -5537,6 +5543,29 @@ dns_zone_setflag(dns_zone_t *zone, unsigned int flags, bool value) { } } +void +dns_zone_setkasp(dns_zone_t *zone, dns_kasp_t* kasp) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->kasp != NULL) { + dns_kasp_t* oldkasp = zone->kasp; + zone->kasp = NULL; + dns_kasp_detach(&oldkasp); + } + zone->kasp = kasp; + UNLOCK_ZONE(zone); +} + +dns_kasp_t* +dns_zone_getkasp(dns_zone_t *zone) +{ + REQUIRE(DNS_ZONE_VALID(zone)); + + return (zone->kasp); +} + void dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option, bool value) diff --git a/util/copyrights b/util/copyrights index 1f7fef1d1dff8c7f5d9e348a0aeb48b8b2dba9ea..cff1a45fc0435ea09d219b59d8f968b8ef923dc2 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1677,6 +1677,7 @@ ./lib/dns/include/dns/ipkeylist.h C 2016,2018,2019 ./lib/dns/include/dns/iptable.h C 2007,2012,2014,2016,2018,2019 ./lib/dns/include/dns/journal.h C 1999,2000,2001,2004,2005,2006,2007,2008,2009,2011,2013,2016,2017,2018,2019 +./lib/dns/include/dns/kasp.h C 2019 ./lib/dns/include/dns/keydata.h C 2009,2016,2018,2019 ./lib/dns/include/dns/keyflags.h C 1999,2000,2001,2004,2005,2006,2007,2016,2018,2019 ./lib/dns/include/dns/keytable.h C 2000,2001,2004,2005,2007,2009,2010,2014,2015,2016,2017,2018,2019 @@ -1744,6 +1745,7 @@ ./lib/dns/ipkeylist.c C 2016,2018,2019 ./lib/dns/iptable.c C 2007,2008,2009,2013,2014,2016,2017,2018,2019 ./lib/dns/journal.c C 1999,2000,2001,2002,2004,2005,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019 +./lib/dns/kasp.c C 2019 ./lib/dns/key.c C 2001,2004,2005,2006,2007,2011,2016,2018,2019 ./lib/dns/keydata.c C 2009,2014,2016,2018,2019 ./lib/dns/keytable.c C 2000,2001,2004,2005,2007,2009,2010,2013,2014,2015,2016,2017,2018,2019