2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00
Files
bind/lib/dns/kasp.c
Matthijs Mekking 634c80ea12 Remove kasp mutex lock
Multiple zones should be able to read the same key and signing policy
at the same time. Since writing the kasp lock only happens during
reconfiguration, and the complete kasp list is being replaced, there
is actually no need for a lock. Reference counting ensures that a kasp
structure is not destroyed when still being attached to one or more
zones.

This significantly improves the load configuration time.
2023-12-19 14:53:51 +01:00

592 lines
11 KiB
C

/*
* 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>
#include <dst/dst.h>
/* Default TTLsig (maximum zone ttl) */
#define DEFAULT_TTLSIG 604800 /* one week */
isc_result_t
dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp) {
dns_kasp_t *kasp;
dns_kasp_t k = {
.magic = DNS_KASP_MAGIC,
.digests = ISC_LIST_INITIALIZER,
.keys = ISC_LIST_INITIALIZER,
.link = ISC_LINK_INITIALIZER,
};
REQUIRE(name != NULL);
REQUIRE(kaspp != NULL && *kaspp == NULL);
kasp = isc_mem_get(mctx, sizeof(*kasp));
*kasp = k;
kasp->mctx = NULL;
isc_mem_attach(mctx, &kasp->mctx);
kasp->name = isc_mem_strdup(mctx, name);
isc_refcount_init(&kasp->references, 1);
*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, *key_next;
dns_kasp_digest_t *digest, *digest_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));
for (digest = ISC_LIST_HEAD(kasp->digests); digest != NULL;
digest = digest_next)
{
digest_next = ISC_LIST_NEXT(digest, link);
ISC_LIST_UNLINK(kasp->digests, digest, link);
isc_mem_put(kasp->mctx, digest, sizeof(*digest));
}
INSIST(ISC_LIST_EMPTY(kasp->digests));
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;
}
bool
dns_kasp_inlinesigning(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->inline_signing);
}
void
dns_kasp_setinlinesigning(dns_kasp_t *kasp, bool value) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
kasp->inline_signing = value;
}
dns_ttl_t
dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
if (kasp->zone_max_ttl == 0 && fallback) {
return (DEFAULT_TTLSIG);
}
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;
}
bool
dns_kasp_cdnskey(dns_kasp_t *kasp) {
REQUIRE(kasp != NULL);
REQUIRE(kasp->frozen);
return kasp->cdnskey;
}
void
dns_kasp_setcdnskey(dns_kasp_t *kasp, bool cdnskey) {
REQUIRE(kasp != NULL);
REQUIRE(!kasp->frozen);
kasp->cdnskey = cdnskey;
}
dns_kasp_digestlist_t
dns_kasp_digests(dns_kasp_t *kasp) {
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(kasp->frozen);
return (kasp->digests);
}
void
dns_kasp_adddigest(dns_kasp_t *kasp, dns_dsdigest_t alg) {
dns_kasp_digest_t *digest;
REQUIRE(DNS_KASP_VALID(kasp));
REQUIRE(!kasp->frozen);
/* Suppress unsupported algorithms */
if (!dst_ds_digest_supported(alg)) {
return;
}
/* Suppress duplicates */
for (dns_kasp_digest_t *d = ISC_LIST_HEAD(kasp->digests); d != NULL;
d = ISC_LIST_NEXT(d, link))
{
if (d->digest == alg) {
return;
}
}
digest = isc_mem_get(kasp->mctx, sizeof(*digest));
digest->digest = alg;
ISC_LINK_INIT(digest, link);
ISC_LIST_APPEND(kasp->digests, digest, link);
}