2019-09-11 10:58:44 +02:00
|
|
|
/*
|
|
|
|
* 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
|
2020-09-14 16:20:40 -07:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2019-09-11 10:58:44 +02:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/print.h>
|
2020-02-06 12:13:20 -08:00
|
|
|
#include <isc/region.h>
|
2019-09-11 10:58:44 +02:00
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/kasp.h>
|
|
|
|
#include <dns/keyvalues.h>
|
|
|
|
#include <dns/log.h>
|
2020-02-06 12:13:20 -08:00
|
|
|
#include <dns/result.h>
|
|
|
|
#include <dns/secalg.h>
|
2019-09-11 10:58:44 +02:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <isccfg/cfg.h>
|
|
|
|
#include <isccfg/kaspconf.h>
|
|
|
|
#include <isccfg/namedconf.h>
|
2019-09-11 10:58:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Utility function for getting a configuration option.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
confget(cfg_obj_t const *const *maps, const char *name, const cfg_obj_t **obj) {
|
2019-09-11 10:58:44 +02:00
|
|
|
for (size_t i = 0;; i++) {
|
|
|
|
if (maps[i] == NULL) {
|
|
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
}
|
|
|
|
if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Utility function for configuring durations.
|
|
|
|
*/
|
2019-10-30 17:40:08 +01:00
|
|
|
static uint32_t
|
2020-02-13 14:44:37 -08:00
|
|
|
get_duration(const cfg_obj_t **maps, const char *option, uint32_t dfl) {
|
2019-09-11 10:58:44 +02:00
|
|
|
const cfg_obj_t *obj;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2019-09-11 10:58:44 +02:00
|
|
|
obj = NULL;
|
|
|
|
|
|
|
|
result = confget(maps, option, &obj);
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
return (dfl);
|
|
|
|
}
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
return (cfg_obj_asduration(obj));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new kasp key derived from configuration.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-06 12:13:20 -08:00
|
|
|
cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_log_t *logctx) {
|
|
|
|
isc_result_t result;
|
2019-09-11 10:58:44 +02:00
|
|
|
dns_kasp_key_t *key = NULL;
|
|
|
|
|
|
|
|
/* Create a new key reference. */
|
2019-11-04 16:26:39 +01:00
|
|
|
result = dns_kasp_key_create(kasp, &key);
|
2019-09-11 10:58:44 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
|
|
|
}
|
2020-02-06 17:43:54 +01:00
|
|
|
|
2019-09-11 10:58:44 +02:00
|
|
|
if (config == NULL) {
|
|
|
|
/* We are creating a key reference for the default kasp. */
|
|
|
|
key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
|
2020-02-06 15:41:47 +01:00
|
|
|
key->lifetime = 0; /* unlimited */
|
2019-09-11 10:58:44 +02:00
|
|
|
key->algorithm = DNS_KEYALG_ECDSA256;
|
|
|
|
key->length = -1;
|
|
|
|
} else {
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *rolestr = NULL;
|
|
|
|
const cfg_obj_t *obj = NULL;
|
2020-02-06 12:13:20 -08:00
|
|
|
isc_consttextregion_t alg;
|
2019-09-11 10:58:44 +02:00
|
|
|
|
|
|
|
rolestr = cfg_obj_asstring(cfg_tuple_get(config, "role"));
|
|
|
|
if (strcmp(rolestr, "ksk") == 0) {
|
|
|
|
key->role |= DNS_KASP_KEY_ROLE_KSK;
|
|
|
|
} else if (strcmp(rolestr, "zsk") == 0) {
|
|
|
|
key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
|
|
|
} else if (strcmp(rolestr, "csk") == 0) {
|
|
|
|
key->role |= DNS_KASP_KEY_ROLE_KSK;
|
|
|
|
key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
|
|
|
}
|
2020-02-06 15:41:47 +01:00
|
|
|
|
|
|
|
key->lifetime = 0; /* unlimited */
|
|
|
|
obj = cfg_tuple_get(config, "lifetime");
|
|
|
|
if (cfg_obj_isduration(obj)) {
|
|
|
|
key->lifetime = cfg_obj_asduration(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = cfg_tuple_get(config, "algorithm");
|
2020-02-06 12:13:20 -08:00
|
|
|
alg.base = cfg_obj_asstring(obj);
|
|
|
|
alg.length = strlen(alg.base);
|
|
|
|
result = dns_secalg_fromtext(&key->algorithm,
|
2020-02-12 13:59:18 +01:00
|
|
|
(isc_textregion_t *)&alg);
|
2020-02-06 12:13:20 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
|
|
|
|
"dnssec-policy: bad algorithm %s",
|
|
|
|
alg.base);
|
|
|
|
result = DNS_R_BADALG;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2020-02-06 15:41:47 +01:00
|
|
|
|
2019-09-11 10:58:44 +02:00
|
|
|
obj = cfg_tuple_get(config, "length");
|
|
|
|
if (cfg_obj_isuint32(obj)) {
|
2020-02-06 17:43:54 +01:00
|
|
|
uint32_t min, size;
|
|
|
|
size = cfg_obj_asuint32(obj);
|
|
|
|
|
|
|
|
switch (key->algorithm) {
|
|
|
|
case DNS_KEYALG_RSASHA1:
|
|
|
|
case DNS_KEYALG_NSEC3RSASHA1:
|
|
|
|
case DNS_KEYALG_RSASHA256:
|
|
|
|
case DNS_KEYALG_RSASHA512:
|
|
|
|
min = DNS_KEYALG_RSASHA512 ? 1024 : 512;
|
|
|
|
if (size < min || size > 4096) {
|
2020-02-12 13:59:18 +01:00
|
|
|
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
|
2020-02-06 17:43:54 +01:00
|
|
|
"dnssec-policy: key with "
|
2020-02-06 12:13:20 -08:00
|
|
|
"algorithm %s has invalid "
|
|
|
|
"key length %u",
|
|
|
|
alg.base, size);
|
|
|
|
result = ISC_R_RANGE;
|
|
|
|
goto cleanup;
|
2020-02-06 17:43:54 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DNS_KEYALG_ECDSA256:
|
|
|
|
case DNS_KEYALG_ECDSA384:
|
|
|
|
case DNS_KEYALG_ED25519:
|
|
|
|
case DNS_KEYALG_ED448:
|
|
|
|
cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
|
2020-02-06 12:13:20 -08:00
|
|
|
"dnssec-policy: key algorithm %s "
|
2020-02-06 17:43:54 +01:00
|
|
|
"has predefined length; ignoring "
|
2020-02-12 13:59:18 +01:00
|
|
|
"length value %u",
|
|
|
|
alg.base, size);
|
2020-02-06 17:43:54 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
key->length = size;
|
2019-09-11 10:58:44 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-06 17:43:54 +01:00
|
|
|
|
2019-11-04 16:26:39 +01:00
|
|
|
dns_kasp_addkey(kasp, key);
|
2020-02-06 12:13:20 -08:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
|
|
dns_kasp_key_destroy(key);
|
2019-09-11 10:58:44 +02:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-02-06 17:43:54 +01:00
|
|
|
cfg_kasp_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *logctx,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_kasplist_t *kasplist, dns_kasp_t **kaspp) {
|
|
|
|
isc_result_t result;
|
|
|
|
const cfg_obj_t *maps[2];
|
|
|
|
const cfg_obj_t *koptions = NULL;
|
|
|
|
const cfg_obj_t *keys = NULL;
|
2019-09-11 10:58:44 +02:00
|
|
|
const cfg_listelt_t *element = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *kaspname = NULL;
|
|
|
|
dns_kasp_t *kasp = NULL;
|
|
|
|
int i = 0;
|
2019-09-11 10:58:44 +02:00
|
|
|
|
|
|
|
REQUIRE(kaspp != NULL && *kaspp == NULL);
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
kaspname = (config != NULL)
|
|
|
|
? cfg_obj_asstring(cfg_tuple_get(config, "name"))
|
|
|
|
: "default";
|
2019-09-11 10:58:44 +02:00
|
|
|
|
2019-11-05 17:22:35 +01:00
|
|
|
REQUIRE(strcmp(kaspname, "none") != 0);
|
|
|
|
|
2019-09-11 10:58:44 +02:00
|
|
|
result = dns_kasplist_find(kasplist, kaspname, &kasp);
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
return (ISC_R_EXISTS);
|
|
|
|
}
|
|
|
|
if (result != ISC_R_NOTFOUND) {
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No kasp with configured name was found in list, create new one. */
|
|
|
|
INSIST(kasp == NULL);
|
|
|
|
result = dns_kasp_create(mctx, kaspname, &kasp);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
INSIST(kasp != NULL);
|
|
|
|
|
|
|
|
/* Now configure. */
|
|
|
|
INSIST(DNS_KASP_VALID(kasp));
|
|
|
|
|
|
|
|
if (config != NULL) {
|
|
|
|
koptions = cfg_tuple_get(config, "options");
|
|
|
|
maps[i++] = koptions;
|
|
|
|
}
|
|
|
|
maps[i] = NULL;
|
|
|
|
|
|
|
|
/* Configuration: Signatures */
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_kasp_setsigrefresh(kasp, get_duration(maps, "signatures-refresh",
|
|
|
|
DNS_KASP_SIG_REFRESH));
|
|
|
|
dns_kasp_setsigvalidity(kasp, get_duration(maps, "signatures-validity",
|
|
|
|
DNS_KASP_SIG_VALIDITY));
|
|
|
|
dns_kasp_setsigvalidity_dnskey(
|
|
|
|
kasp, get_duration(maps, "signatures-validity-dnskey",
|
|
|
|
DNS_KASP_SIG_VALIDITY_DNSKEY));
|
2019-09-11 10:58:44 +02:00
|
|
|
|
|
|
|
/* Configuration: Keys */
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_kasp_setdnskeyttl(
|
|
|
|
kasp, get_duration(maps, "dnskey-ttl", DNS_KASP_KEY_TTL));
|
|
|
|
dns_kasp_setpublishsafety(kasp, get_duration(maps, "publish-safety",
|
|
|
|
DNS_KASP_PUBLISH_SAFETY));
|
|
|
|
dns_kasp_setretiresafety(kasp, get_duration(maps, "retire-safety",
|
|
|
|
DNS_KASP_RETIRE_SAFETY));
|
2019-09-11 10:58:44 +02:00
|
|
|
|
|
|
|
(void)confget(maps, "keys", &keys);
|
|
|
|
if (keys == NULL) {
|
2020-02-06 17:43:54 +01:00
|
|
|
result = cfg_kaspkey_fromconfig(NULL, kasp, logctx);
|
2019-09-11 10:58:44 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (element = cfg_list_first(keys); element != NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
element = cfg_list_next(element))
|
|
|
|
{
|
2019-09-11 10:58:44 +02:00
|
|
|
cfg_obj_t *kobj = cfg_listelt_value(element);
|
2020-02-06 17:43:54 +01:00
|
|
|
result = cfg_kaspkey_fromconfig(kobj, kasp, logctx);
|
2019-09-11 10:58:44 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-06 10:28:53 -08:00
|
|
|
INSIST(!(dns_kasp_keylist_empty(kasp)));
|
2019-09-11 10:58:44 +02:00
|
|
|
|
2019-10-16 18:36:38 +02:00
|
|
|
/* Configuration: Zone settings */
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_kasp_setzonemaxttl(
|
|
|
|
kasp, get_duration(maps, "max-zone-ttl", DNS_KASP_ZONE_MAXTTL));
|
|
|
|
dns_kasp_setzonepropagationdelay(
|
|
|
|
kasp, get_duration(maps, "zone-propagation-delay",
|
|
|
|
DNS_KASP_ZONE_PROPDELAY));
|
2019-10-16 18:36:38 +02:00
|
|
|
|
|
|
|
/* Configuration: Parent settings */
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_kasp_setdsttl(kasp,
|
|
|
|
get_duration(maps, "parent-ds-ttl", DNS_KASP_DS_TTL));
|
|
|
|
dns_kasp_setparentpropagationdelay(
|
|
|
|
kasp, get_duration(maps, "parent-propagation-delay",
|
|
|
|
DNS_KASP_PARENT_PROPDELAY));
|
2019-10-16 18:36:38 +02:00
|
|
|
|
2020-02-06 10:28:53 -08:00
|
|
|
/* TODO: Rest of the configuration */
|
2019-09-11 10:58:44 +02:00
|
|
|
|
2019-11-05 13:38:00 +11:00
|
|
|
/* Append it to the list for future lookups. */
|
|
|
|
ISC_LIST_APPEND(*kasplist, kasp, link);
|
2020-02-06 10:28:53 -08:00
|
|
|
INSIST(!(ISC_LIST_EMPTY(*kasplist)));
|
2019-11-05 13:38:00 +11:00
|
|
|
|
2019-09-11 10:58:44 +02:00
|
|
|
/* Success: Attach the kasp to the pointer and return. */
|
|
|
|
dns_kasp_attach(kasp, kaspp);
|
2020-02-06 10:28:53 -08:00
|
|
|
|
2019-11-05 13:38:00 +11:00
|
|
|
/* Don't detach as kasp is on '*kasplist' */
|
2019-09-11 10:58:44 +02:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
|
|
/* Something bad happened, detach (destroys kasp) and return error. */
|
|
|
|
dns_kasp_detach(&kasp);
|
|
|
|
return (result);
|
|
|
|
}
|