diff options
Diffstat (limited to '')
-rw-r--r-- | lib/dns/kasp.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c new file mode 100644 index 0000000..09c6810 --- /dev/null +++ b/lib/dns/kasp.c @@ -0,0 +1,527 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include <string.h> + +#include <isc/assertions.h> +#include <isc/buffer.h> +#include <isc/file.h> +#include <isc/hex.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/util.h> + +#include <dns/kasp.h> +#include <dns/keyvalues.h> +#include <dns/log.h> + +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; + kasp->purge_keys = DNS_KASP_PURGE_KEYS; + + kasp->zone_max_ttl = DNS_KASP_ZONE_MAXTTL; + kasp->zone_propagation_delay = DNS_KASP_ZONE_PROPDELAY; + + kasp->parent_ds_ttl = DNS_KASP_DS_TTL; + kasp->parent_propagation_delay = DNS_KASP_PARENT_PROPDELAY; + + kasp->nsec3 = false; + + 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 void +destroy(dns_kasp_t *kasp) { + dns_kasp_key_t *key; + dns_kasp_key_t *key_next; + + REQUIRE(!ISC_LINK_LINKED(kasp, link)); + + 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); + } + INSIST(ISC_LIST_EMPTY(kasp->keys)); + + isc_mutex_destroy(&kasp->lock); + 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); + } +} + +const char * +dns_kasp_getname(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + + return (kasp->name); +} + +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; +} + +uint32_t +dns_kasp_signdelay(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->signatures_validity - kasp->signatures_refresh); +} + +uint32_t +dns_kasp_sigrefresh(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->signatures_refresh); +} + +void +dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->signatures_refresh = value; +} + +uint32_t +dns_kasp_sigvalidity(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->signatures_validity); +} + +void +dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->signatures_validity = value; +} + +uint32_t +dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->signatures_validity_dnskey); +} + +void +dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->signatures_validity_dnskey = value; +} + +dns_ttl_t +dns_kasp_dnskeyttl(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->dnskey_ttl); +} + +void +dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->dnskey_ttl = ttl; +} + +uint32_t +dns_kasp_purgekeys(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->purge_keys); +} + +void +dns_kasp_setpurgekeys(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->purge_keys = value; +} + +uint32_t +dns_kasp_publishsafety(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->publish_safety); +} + +void +dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->publish_safety = value; +} + +uint32_t +dns_kasp_retiresafety(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->retire_safety); +} + +void +dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->retire_safety = value; +} + +dns_ttl_t +dns_kasp_zonemaxttl(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->zone_max_ttl); +} + +void +dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->zone_max_ttl = ttl; +} + +uint32_t +dns_kasp_zonepropagationdelay(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->zone_propagation_delay); +} + +void +dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->zone_propagation_delay = value; +} + +dns_ttl_t +dns_kasp_dsttl(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->parent_ds_ttl); +} + +void +dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->parent_ds_ttl = ttl; +} + +uint32_t +dns_kasp_parentpropagationdelay(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->parent_propagation_delay); +} + +void +dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->parent_propagation_delay = value; +} + +isc_result_t +dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp) { + dns_kasp_t *kasp = NULL; + + REQUIRE(kaspp != NULL && *kaspp == NULL); + + if (list == NULL) { + return (ISC_R_NOTFOUND); + } + + 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); +} + +dns_kasp_keylist_t +dns_kasp_keys(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return (kasp->keys); +} + +bool +dns_kasp_keylist_empty(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + + return (ISC_LIST_EMPTY(kasp->keys)); +} + +void +dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + REQUIRE(key != NULL); + + ISC_LIST_APPEND(kasp->keys, key, link); +} + +isc_result_t +dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp) { + dns_kasp_key_t *key; + + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(keyp != NULL && *keyp == NULL); + + key = isc_mem_get(kasp->mctx, sizeof(*key)); + key->mctx = NULL; + isc_mem_attach(kasp->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)); +} + +uint32_t +dns_kasp_key_algorithm(dns_kasp_key_t *key) { + REQUIRE(key != NULL); + + return (key->algorithm); +} + +unsigned int +dns_kasp_key_size(dns_kasp_key_t *key) { + unsigned int size = 0; + unsigned int min = 0; + + REQUIRE(key != NULL); + + switch (key->algorithm) { + case DNS_KEYALG_RSASHA1: + case DNS_KEYALG_NSEC3RSASHA1: + case DNS_KEYALG_RSASHA256: + case DNS_KEYALG_RSASHA512: + min = (key->algorithm == DNS_KEYALG_RSASHA512) ? 1024 : 512; + if (key->length > -1) { + size = (unsigned int)key->length; + if (size < min) { + size = min; + } + if (size > 4096) { + size = 4096; + } + } else { + size = 2048; + } + break; + case DNS_KEYALG_ECDSA256: + size = 256; + break; + case DNS_KEYALG_ECDSA384: + size = 384; + break; + case DNS_KEYALG_ED25519: + size = 256; + break; + case DNS_KEYALG_ED448: + size = 456; + break; + default: + /* unsupported */ + break; + } + return (size); +} + +uint32_t +dns_kasp_key_lifetime(dns_kasp_key_t *key) { + REQUIRE(key != NULL); + + return (key->lifetime); +} + +bool +dns_kasp_key_ksk(dns_kasp_key_t *key) { + REQUIRE(key != NULL); + + return (key->role & DNS_KASP_KEY_ROLE_KSK); +} + +bool +dns_kasp_key_zsk(dns_kasp_key_t *key) { + REQUIRE(key != NULL); + + return (key->role & DNS_KASP_KEY_ROLE_ZSK); +} + +uint8_t +dns_kasp_nsec3iter(dns_kasp_t *kasp) { + REQUIRE(kasp != NULL); + REQUIRE(kasp->frozen); + REQUIRE(kasp->nsec3); + + return (kasp->nsec3param.iterations); +} + +uint8_t +dns_kasp_nsec3flags(dns_kasp_t *kasp) { + REQUIRE(kasp != NULL); + REQUIRE(kasp->frozen); + REQUIRE(kasp->nsec3); + + if (kasp->nsec3param.optout) { + return (0x01); + } + return (0x00); +} + +uint8_t +dns_kasp_nsec3saltlen(dns_kasp_t *kasp) { + REQUIRE(kasp != NULL); + REQUIRE(kasp->frozen); + REQUIRE(kasp->nsec3); + + return (kasp->nsec3param.saltlen); +} + +bool +dns_kasp_nsec3(dns_kasp_t *kasp) { + REQUIRE(kasp != NULL); + REQUIRE(kasp->frozen); + + return kasp->nsec3; +} + +void +dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3) { + REQUIRE(kasp != NULL); + REQUIRE(!kasp->frozen); + + kasp->nsec3 = nsec3; +} + +void +dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout, + uint8_t saltlen) { + REQUIRE(kasp != NULL); + REQUIRE(!kasp->frozen); + REQUIRE(kasp->nsec3); + + kasp->nsec3param.iterations = iter; + kasp->nsec3param.optout = optout; + kasp->nsec3param.saltlen = saltlen; +} |