diff --git a/bin/tests/system/checkconf/bad-kasp-keystore.conf b/bin/tests/system/checkconf/bad-kasp-keystore.conf new file mode 100644 index 0000000000..8bbe9a38e2 --- /dev/null +++ b/bin/tests/system/checkconf/bad-kasp-keystore.conf @@ -0,0 +1,19 @@ +/* + * 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. + */ + +// Bad dnssec-policy configuration because there is no key-store with this name. +dnssec-policy "bad" { + keys { + csk key-store "ks404" lifetime unlimited algorithm 13; + }; +}; diff --git a/bin/tests/system/checkconf/bad-keystore-key-directory.conf b/bin/tests/system/checkconf/bad-keystore-key-directory.conf new file mode 100644 index 0000000000..7007cf80f4 --- /dev/null +++ b/bin/tests/system/checkconf/bad-keystore-key-directory.conf @@ -0,0 +1,24 @@ +/* + * 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. + */ + +// Bad key-store configuration because the keyword 'key-directory' may not +// be used. +key-store "key-directory" { + directory "."; +}; + +dnssec-policy "bad" { + keys { + csk key-store "key-directory" lifetime unlimited algorithm 13; + }; +}; diff --git a/lib/dns/include/dns/kasp.h b/lib/dns/include/dns/kasp.h index 92bf406c98..288c754c9f 100644 --- a/lib/dns/include/dns/kasp.h +++ b/lib/dns/include/dns/kasp.h @@ -51,11 +51,11 @@ struct dns_kasp_key { ISC_LINK(struct dns_kasp_key) link; /* Configuration */ - char *keystore; - uint32_t lifetime; - uint8_t algorithm; - int length; - uint8_t role; + const char *keystore; + uint32_t lifetime; + uint8_t algorithm; + int length; + uint8_t role; }; struct dns_kasp_nsec3param { @@ -644,6 +644,21 @@ dns_kasp_key_lifetime(dns_kasp_key_t *key); * */ +const char * +dns_kasp_key_keystore(dns_kasp_key_t *key); +/*%< + * The keystore reference of this key. + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li Keystore of key, or NULL if zone's key-directory is used. + * + */ + bool dns_kasp_key_ksk(dns_kasp_key_t *key); /*%< diff --git a/lib/dns/include/dns/keystore.h b/lib/dns/include/dns/keystore.h index f898817f57..a5d5840aa1 100644 --- a/lib/dns/include/dns/keystore.h +++ b/lib/dns/include/dns/keystore.h @@ -57,6 +57,8 @@ struct dns_keystore { #define DNS_KEYSTORE_MAGIC ISC_MAGIC('K', 'E', 'Y', 'S') #define DNS_KEYSTORE_VALID(ks) ISC_MAGIC_VALID(ks, DNS_KEYSTORE_MAGIC) +#define DNS_KEYSTORE_KEYDIRECTORY "key-directory" + isc_result_t dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp); /*%< diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c index aa6637f594..de8d757fd4 100644 --- a/lib/dns/kasp.c +++ b/lib/dns/kasp.c @@ -408,7 +408,9 @@ dns_kasp_key_destroy(dns_kasp_key_t *key) { REQUIRE(key != NULL); if (key->keystore != NULL) { - isc_mem_free(key->mctx, key->keystore); + char *ks; + DE_CONST(key->keystore, ks); + isc_mem_free(key->mctx, ks); key->keystore = NULL; } isc_mem_putanddetach(&key->mctx, key, sizeof(*key)); @@ -472,6 +474,13 @@ dns_kasp_key_lifetime(dns_kasp_key_t *key) { return (key->lifetime); } +const char * +dns_kasp_key_keystore(dns_kasp_key_t *key) { + REQUIRE(key != NULL); + + return (key->keystore); +} + bool dns_kasp_key_ksk(dns_kasp_key_t *key) { REQUIRE(key != NULL); diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index c4e09f1c88..5929b27888 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -1187,6 +1188,39 @@ check_port(const cfg_obj_t *options, isc_log_t *logctx, const char *type, return (ISC_R_SUCCESS); } +static isc_result_t +check_keystore(const cfg_obj_t *obj, isc_log_t *logctx, dns_kasp_t *kasp, + dns_keystorelist_t *kslist) { + isc_result_t result = ISC_R_SUCCESS; + dns_kasp_key_t *kkey; + dns_keystore_t *ks = NULL; + + REQUIRE(kasp != NULL); + + dns_kasp_freeze(kasp); + + for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL; + kkey = ISC_LIST_NEXT(kkey, link)) + { + const char *keystore = dns_kasp_key_keystore(kkey); + if (keystore != NULL && strcmp("key-directory", keystore) != 0) + { + if (dns_keystorelist_find(kslist, keystore, &ks) == + ISC_R_SUCCESS) { + dns_keystore_detach(&ks); + } else { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "key-store '%s' not found", + keystore); + result = ISC_R_FAILURE; + } + } + } + + dns_kasp_thaw(kasp); + return (result); +} + static isc_result_t check_options(const cfg_obj_t *options, const cfg_obj_t *config, bool check_algorithms, isc_log_t *logctx, isc_mem_t *mctx, @@ -1200,6 +1234,8 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, const char *str; isc_buffer_t b; uint32_t lifetime = 3600; + dns_keystorelist_t kslist; + dns_keystore_t *ks = NULL, *ks_next = NULL; const char *ccalg = "siphash24"; cfg_aclconfctx_t *actx = NULL; static const char *sources[] = { @@ -1329,6 +1365,55 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, } } + /* + * Check key-store. + */ + ISC_LIST_INIT(kslist); + + obj = NULL; + (void)cfg_map_get(options, "key-store", &obj); + if (obj != NULL) { + if (optlevel != optlevel_config) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "may only be configured at the top level"); + if (result == ISC_R_SUCCESS) { + result = ISC_R_FAILURE; + } + } else if (cfg_obj_islist(obj)) { + for (element = cfg_list_first(obj); element != NULL; + element = cfg_list_next(element)) + { + isc_result_t ret; + const char *name; + cfg_obj_t *kconfig = cfg_listelt_value(element); + if (!cfg_obj_istuple(kconfig)) { + continue; + } + name = cfg_obj_asstring(cfg_tuple_get( + cfg_listelt_value(element), "name")); + if (strcmp(DNS_KEYSTORE_KEYDIRECTORY, name) == 0) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "name '%s' not allowed", + DNS_KEYSTORE_KEYDIRECTORY); + if (result == ISC_R_SUCCESS) { + result = ISC_R_FAILURE; + } + } + + ret = cfg_keystore_fromconfig( + kconfig, mctx, logctx, &kslist, &ks); + if (ret != ISC_R_SUCCESS) { + if (result == ISC_R_SUCCESS) { + result = ret; + } + } + if (ks != NULL) { + dns_keystore_detach(&ks); + } + } + } + } + /* * Check dnssec-policy. */ @@ -1367,6 +1452,12 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, ret = cfg_kasp_fromconfig( kconfig, NULL, check_algorithms, mctx, logctx, &list, &kasp); + if (ret == ISC_R_SUCCESS) { + /* Check key-stores of keys */ + ret = check_keystore( + obj, logctx, kasp, + &kslist); + } if (ret != ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) { result = ret; @@ -1407,6 +1498,18 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, } } + /* + * Cleanup key-store. + */ + for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) { + ks_next = ISC_LIST_NEXT(ks, link); + ISC_LIST_UNLINK(kslist, ks, link); + dns_keystore_detach(&ks); + } + + /* + * Other checks. + */ obj = NULL; cfg_map_get(options, "max-rsa-exponent-size", &obj); if (obj != NULL) {