mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 05:57:52 +00:00
Merge branch '1129-hsm-kasp' into 'main'
HSM support for dnssec-policy Closes #1129 See merge request isc-projects/bind9!5924
This commit is contained in:
commit
b51d8f2c5d
@ -946,7 +946,7 @@ gcc:ossl3:sid:amd64:
|
||||
<<: *build_job
|
||||
|
||||
system:gcc:ossl3:sid:amd64:
|
||||
# Set up environment variables to run pkcs11-provider system tests
|
||||
# Set up environment variables to run pkcs11-provider based system tests
|
||||
variables:
|
||||
OPENSSL_CONF: "/var/tmp/etc/openssl-provider.cnf"
|
||||
SOFTHSM2_CONF: "/var/tmp/softhsm2/softhsm2.conf"
|
||||
|
5
CHANGES
5
CHANGES
@ -1,3 +1,8 @@
|
||||
6329. [func] Add HSM support for dnssec-policy. You can now
|
||||
configure keys with a key-store that allows you to
|
||||
set the directory to store key files and to set a
|
||||
PKCS #11 URI string. [GL #1129]
|
||||
|
||||
6328. [doc] Update ZSK minimum lifetime documentation in ARM, also
|
||||
depends on signing delay. [GL #4510]
|
||||
|
||||
|
@ -124,7 +124,7 @@ generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize,
|
||||
|
||||
DO("generate key",
|
||||
dst_key_generate(dns_rootname, alg, keysize, 0, 0, DNS_KEYPROTO_ANY,
|
||||
dns_rdataclass_in, mctx, &key, NULL));
|
||||
dns_rdataclass_in, NULL, mctx, &key, NULL));
|
||||
|
||||
isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
|
||||
|
||||
|
@ -92,6 +92,7 @@ struct keygen_ctx {
|
||||
const char *policy;
|
||||
const char *configfile;
|
||||
const char *directory;
|
||||
dns_keystore_t *keystore;
|
||||
char *algname;
|
||||
char *nametype;
|
||||
char *type;
|
||||
@ -255,14 +256,42 @@ progress(int p) {
|
||||
|
||||
static void
|
||||
kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
||||
dns_kasp_t **kaspp) {
|
||||
const char *keydir, const char *engine, dns_kasp_t **kaspp) {
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
const cfg_listelt_t *element;
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
dns_kasp_t *kasp = NULL, *kasp_next;
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
dns_kasplist_t kasplist;
|
||||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystore_t *ks = NULL, *ks_next;
|
||||
dns_keystorelist_t kslist;
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
|
||||
(void)cfg_map_get(config, "key-store", &keystores);
|
||||
for (element = cfg_list_first(keystores); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
ks = NULL;
|
||||
result = cfg_keystore_fromconfig(kconfig, mctx, lctx, engine,
|
||||
&kslist, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to configure key-store '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
/* Default key-directory key store. */
|
||||
ks = NULL;
|
||||
(void)cfg_keystore_fromconfig(NULL, mctx, lctx, engine, &kslist, &ks);
|
||||
INSIST(ks != NULL);
|
||||
if (keydir != NULL) {
|
||||
/* '-K keydir' takes priority */
|
||||
dns_keystore_setdirectory(ks, keydir);
|
||||
}
|
||||
dns_keystore_detach(&ks);
|
||||
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
for (element = cfg_list_first(kasps); element != NULL;
|
||||
@ -277,7 +306,7 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
||||
}
|
||||
|
||||
result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, lctx,
|
||||
&kasplist, &kasp);
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to configure dnssec-policy '%s': %s",
|
||||
cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
|
||||
@ -298,6 +327,15 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
|
||||
ISC_LIST_UNLINK(kasplist, kasp, link);
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup keystore list.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -655,16 +693,27 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
||||
|
||||
if (!ctx->quiet && show_progress) {
|
||||
fprintf(stderr, "Generating key pair.");
|
||||
}
|
||||
|
||||
if (ctx->keystore != NULL && ctx->policy != NULL) {
|
||||
ret = dns_keystore_keygen(
|
||||
ctx->keystore, name, ctx->policy, ctx->rdclass,
|
||||
mctx, ctx->alg, ctx->size, flags, &key);
|
||||
} else if (!ctx->quiet && show_progress) {
|
||||
ret = dst_key_generate(name, ctx->alg, ctx->size, param,
|
||||
flags, ctx->protocol,
|
||||
ctx->rdclass, mctx, &key,
|
||||
ctx->rdclass, NULL, mctx, &key,
|
||||
&progress);
|
||||
putc('\n', stderr);
|
||||
fflush(stderr);
|
||||
} else {
|
||||
ret = dst_key_generate(name, ctx->alg, ctx->size, param,
|
||||
flags, ctx->protocol,
|
||||
ctx->rdclass, mctx, &key, NULL);
|
||||
ctx->rdclass, NULL, mctx, &key,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!ctx->quiet && show_progress) {
|
||||
putc('\n', stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
@ -860,6 +909,18 @@ keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_keystore_options(keygen_ctx_t *ctx) {
|
||||
ctx->directory = dns_keystore_directory(ctx->keystore, NULL);
|
||||
if (ctx->directory != NULL) {
|
||||
isc_result_t ret = try_dir(ctx->directory);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
fatal("cannot open directory %s: %s", ctx->directory,
|
||||
isc_result_totext(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
char *algname = NULL, *freeit = NULL;
|
||||
@ -1269,7 +1330,8 @@ main(int argc, char **argv) {
|
||||
ctx.policy, ctx.configfile);
|
||||
}
|
||||
|
||||
kasp_from_conf(config, mctx, ctx.policy, &kasp);
|
||||
kasp_from_conf(config, mctx, ctx.policy, ctx.directory,
|
||||
engine, &kasp);
|
||||
if (kasp == NULL) {
|
||||
fatal("failed to load dnssec-policy '%s'",
|
||||
ctx.policy);
|
||||
@ -1295,7 +1357,10 @@ main(int argc, char **argv) {
|
||||
ctx.ksk = dns_kasp_key_ksk(kaspkey);
|
||||
ctx.zsk = dns_kasp_key_zsk(kaspkey);
|
||||
ctx.lifetime = dns_kasp_key_lifetime(kaspkey);
|
||||
|
||||
ctx.keystore = dns_kasp_key_keystore(kaspkey);
|
||||
if (ctx.keystore != NULL) {
|
||||
check_keystore_options(&ctx);
|
||||
}
|
||||
keygen(&ctx, mctx, argc, argv);
|
||||
|
||||
kaspkey = ISC_LIST_NEXT(kaspkey, link);
|
||||
|
@ -2639,7 +2639,7 @@ loadzonekeys(bool preserve_keys, bool load_public) {
|
||||
|
||||
/* Load keys corresponding to the existing DNSKEY RRset. */
|
||||
result = dns_dnssec_keylistfromrdataset(
|
||||
gorigin, directory, mctx, &rdataset, &keysigs, &soasigs,
|
||||
gorigin, NULL, directory, mctx, &rdataset, &keysigs, &soasigs,
|
||||
preserve_keys, load_public, &keylist);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("failed to load the zone keys: %s",
|
||||
@ -2830,8 +2830,8 @@ findkeys:
|
||||
/*
|
||||
* Find keys that match this zone in the key repository.
|
||||
*/
|
||||
result = dns_dnssec_findmatchingkeys(gorigin, directory, now, mctx,
|
||||
&matchkeys);
|
||||
result = dns_dnssec_findmatchingkeys(gorigin, NULL, directory, NULL,
|
||||
now, mctx, &matchkeys);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
@ -498,7 +498,8 @@ key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
|
||||
alg = dst_key_alg(dstkey);
|
||||
|
||||
ISC_LIST_INIT(matchkeys);
|
||||
result = dns_dnssec_findmatchingkeys(name, dir, now, mctx, &matchkeys);
|
||||
result = dns_dnssec_findmatchingkeys(name, NULL, dir, NULL, now, mctx,
|
||||
&matchkeys);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
return (false);
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ struct named_server {
|
||||
dns_zonemgr_t *zonemgr;
|
||||
dns_viewlist_t viewlist;
|
||||
dns_kasplist_t kasplist;
|
||||
dns_keystorelist_t keystorelist;
|
||||
ns_interfacemgr_t *interfacemgr;
|
||||
dns_db_t *in_roothints;
|
||||
|
||||
|
@ -28,8 +28,8 @@ ISC_LANG_BEGINDECLS
|
||||
isc_result_t
|
||||
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
|
||||
dns_kasplist_t *kasplist, dns_zone_t *zone,
|
||||
dns_zone_t *raw);
|
||||
dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
|
||||
dns_zone_t *zone, dns_zone_t *raw);
|
||||
/*%<
|
||||
* Configure or reconfigure a zone according to the named.conf
|
||||
* data.
|
||||
|
@ -79,6 +79,7 @@
|
||||
#include <dns/journal.h>
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/keymgr.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keytable.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/master.h>
|
||||
@ -441,8 +442,8 @@ static isc_result_t
|
||||
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
const cfg_obj_t *vconfig, dns_view_t *view,
|
||||
dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
|
||||
cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
|
||||
bool modify);
|
||||
dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
|
||||
bool added, bool old_rpz_ok, bool modify);
|
||||
|
||||
static void
|
||||
configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
|
||||
@ -2787,12 +2788,12 @@ catz_addmodzone_cb(void *arg) {
|
||||
zoneobj = cfg_listelt_value(cfg_list_first(zlist));
|
||||
|
||||
/* Mark view unfrozen so that zone can be added */
|
||||
|
||||
isc_loopmgr_pause(named_g_loopmgr);
|
||||
dns_view_thaw(cz->view);
|
||||
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, cz->view,
|
||||
&cz->cbd->server->viewlist,
|
||||
&cz->cbd->server->kasplist, cfg->actx, true,
|
||||
&cz->cbd->server->kasplist,
|
||||
&cz->cbd->server->keystorelist, cfg->actx, true,
|
||||
false, cz->mod);
|
||||
dns_view_freeze(cz->view);
|
||||
isc_loopmgr_resume(named_g_loopmgr);
|
||||
@ -3975,8 +3976,9 @@ static const char *const response_synonyms[] = { "response", NULL };
|
||||
static isc_result_t
|
||||
configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
cfg_obj_t *vconfig, named_cachelist_t *cachelist,
|
||||
dns_kasplist_t *kasplist, const cfg_obj_t *bindkeys,
|
||||
isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
|
||||
dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
|
||||
const cfg_obj_t *bindkeys, isc_mem_t *mctx,
|
||||
cfg_aclconfctx_t *actx, bool need_hints) {
|
||||
const cfg_obj_t *maps[4];
|
||||
const cfg_obj_t *cfgmaps[3];
|
||||
const cfg_obj_t *optionmaps[3];
|
||||
@ -4121,7 +4123,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
{
|
||||
const cfg_obj_t *zconfig = cfg_listelt_value(element);
|
||||
CHECK(configure_zone(config, zconfig, vconfig, view, viewlist,
|
||||
kasplist, actx, false, old_rpz_ok, false));
|
||||
kasplist, keystores, actx, false,
|
||||
old_rpz_ok, false));
|
||||
zone_element_latest = element;
|
||||
}
|
||||
|
||||
@ -6429,8 +6432,8 @@ static isc_result_t
|
||||
configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
const cfg_obj_t *vconfig, dns_view_t *view,
|
||||
dns_viewlist_t *viewlist, dns_kasplist_t *kasplist,
|
||||
cfg_aclconfctx_t *aclconf, bool added, bool old_rpz_ok,
|
||||
bool modify) {
|
||||
dns_keystorelist_t *keystores, cfg_aclconfctx_t *aclconf,
|
||||
bool added, bool old_rpz_ok, bool modify) {
|
||||
dns_view_t *pview = NULL; /* Production view */
|
||||
dns_zone_t *zone = NULL; /* New or reused zone */
|
||||
dns_zone_t *raw = NULL; /* New or reused raw zone */
|
||||
@ -6624,7 +6627,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
dns_zone_setstats(zone, named_g_server->zonestats);
|
||||
}
|
||||
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf,
|
||||
kasplist, zone, NULL));
|
||||
kasplist, keystores, zone, NULL));
|
||||
dns_zone_attach(zone, &view->redirect);
|
||||
goto cleanup;
|
||||
}
|
||||
@ -6800,7 +6803,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
* Configure the zone.
|
||||
*/
|
||||
CHECK(named_zone_configure(config, vconfig, zconfig, aclconf, kasplist,
|
||||
zone, raw));
|
||||
keystores, zone, raw));
|
||||
|
||||
/*
|
||||
* Add the zone to its view in the new view list.
|
||||
@ -7434,7 +7437,7 @@ generate_session_key(const char *filename, const char *keynamestr,
|
||||
|
||||
/* generate key */
|
||||
result = dst_key_generate(keyname, alg, bits, 1, 0, DNS_KEYPROTO_ANY,
|
||||
dns_rdataclass_in, mctx, &key, NULL);
|
||||
dns_rdataclass_in, NULL, mctx, &key, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -7800,7 +7803,8 @@ configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
|
||||
const cfg_obj_t *zconfig = cfg_listelt_value(element);
|
||||
CHECK(configure_zone(config, zconfig, vconfig, view,
|
||||
&named_g_server->viewlist,
|
||||
&named_g_server->kasplist, actx, true,
|
||||
&named_g_server->kasplist,
|
||||
&named_g_server->keystorelist, actx, true,
|
||||
false, false));
|
||||
}
|
||||
|
||||
@ -7985,7 +7989,8 @@ configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx) {
|
||||
return (configure_zone(
|
||||
config, zconfig, vconfig, view, &named_g_server->viewlist,
|
||||
&named_g_server->kasplist, actx, true, false, false));
|
||||
&named_g_server->kasplist, &named_g_server->keystorelist, actx,
|
||||
true, false, false));
|
||||
}
|
||||
|
||||
/*%
|
||||
@ -8129,10 +8134,14 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
const cfg_obj_t *options;
|
||||
const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
|
||||
const cfg_obj_t *kasps;
|
||||
const cfg_obj_t *keystores;
|
||||
dns_kasp_t *kasp = NULL;
|
||||
dns_kasp_t *kasp_next = NULL;
|
||||
dns_kasp_t *default_kasp = NULL;
|
||||
dns_kasplist_t tmpkasplist, kasplist;
|
||||
dns_keystore_t *keystore = NULL;
|
||||
dns_keystore_t *keystore_next = NULL;
|
||||
dns_keystorelist_t tmpkeystorelist, keystorelist;
|
||||
const cfg_obj_t *views;
|
||||
|
||||
dns_view_t *view_next = NULL;
|
||||
@ -8171,6 +8180,7 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
REQUIRE(isc_loop_current(named_g_loopmgr) == named_g_mainloop);
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(keystorelist);
|
||||
ISC_LIST_INIT(viewlist);
|
||||
ISC_LIST_INIT(builtin_viewlist);
|
||||
ISC_LIST_INIT(cachelist);
|
||||
@ -8882,6 +8892,33 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
*/
|
||||
(void)configure_session_key(maps, server, named_g_mctx, first_time);
|
||||
|
||||
/*
|
||||
* Create the built-in key store ("key-directory").
|
||||
*/
|
||||
result = cfg_keystore_fromconfig(NULL, named_g_mctx, named_g_lctx,
|
||||
named_g_engine, &keystorelist, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_keystorelist;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the DNSSEC key stores.
|
||||
*/
|
||||
keystores = NULL;
|
||||
(void)cfg_map_get(config, "key-store", &keystores);
|
||||
for (element = cfg_list_first(keystores); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
keystore = NULL;
|
||||
result = cfg_keystore_fromconfig(kconfig, named_g_mctx,
|
||||
named_g_lctx, named_g_engine,
|
||||
&keystorelist, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_keystorelist;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the built-in kasp policies ("default", "insecure").
|
||||
*/
|
||||
@ -8895,7 +8932,7 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
kasp = NULL;
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
|
||||
named_g_mctx, named_g_lctx,
|
||||
&kasplist, &kasp);
|
||||
&keystorelist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_kasplist;
|
||||
}
|
||||
@ -8924,7 +8961,7 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
kasp = NULL;
|
||||
result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
|
||||
named_g_mctx, named_g_lctx,
|
||||
&kasplist, &kasp);
|
||||
&keystorelist, &kasplist, &kasp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_kasplist;
|
||||
}
|
||||
@ -8932,8 +8969,15 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
dns_kasp_freeze(kasp);
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
dns_kasp_detach(&default_kasp);
|
||||
|
||||
/*
|
||||
* Save keystore list and kasp list.
|
||||
*/
|
||||
tmpkeystorelist = server->keystorelist;
|
||||
server->keystorelist = keystorelist;
|
||||
keystorelist = tmpkeystorelist;
|
||||
|
||||
tmpkasplist = server->kasplist;
|
||||
server->kasplist = kasplist;
|
||||
kasplist = tmpkasplist;
|
||||
@ -9037,7 +9081,8 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
}
|
||||
|
||||
result = configure_view(view, &viewlist, config, vconfig,
|
||||
&cachelist, &server->kasplist, bindkeys,
|
||||
&cachelist, &server->kasplist,
|
||||
&server->keystorelist, bindkeys,
|
||||
named_g_mctx, named_g_aclconfctx, true);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_view_detach(&view);
|
||||
@ -9058,7 +9103,8 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
goto cleanup_cachelist;
|
||||
}
|
||||
result = configure_view(view, &viewlist, config, NULL,
|
||||
&cachelist, &server->kasplist, bindkeys,
|
||||
&cachelist, &server->kasplist,
|
||||
&server->keystorelist, bindkeys,
|
||||
named_g_mctx, named_g_aclconfctx, true);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_view_detach(&view);
|
||||
@ -9085,10 +9131,10 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
goto cleanup_cachelist;
|
||||
}
|
||||
|
||||
result = configure_view(view, &viewlist, config, vconfig,
|
||||
&cachelist, &server->kasplist, bindkeys,
|
||||
named_g_mctx, named_g_aclconfctx,
|
||||
false);
|
||||
result = configure_view(
|
||||
view, &viewlist, config, vconfig, &cachelist,
|
||||
&server->kasplist, &server->keystorelist, bindkeys,
|
||||
named_g_mctx, named_g_aclconfctx, false);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_view_detach(&view);
|
||||
goto cleanup_cachelist;
|
||||
@ -9585,6 +9631,15 @@ cleanup_kasplist:
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
cleanup_keystorelist:
|
||||
for (keystore = ISC_LIST_HEAD(keystorelist); keystore != NULL;
|
||||
keystore = keystore_next)
|
||||
{
|
||||
keystore_next = ISC_LIST_NEXT(keystore, link);
|
||||
ISC_LIST_UNLINK(keystorelist, keystore, link);
|
||||
dns_keystore_detach(&keystore);
|
||||
}
|
||||
|
||||
cleanup_v6portset:
|
||||
isc_portset_destroy(named_g_mctx, &v6portset);
|
||||
|
||||
@ -9849,6 +9904,7 @@ shutdown_server(void *arg) {
|
||||
named_server_t *server = (named_server_t *)arg;
|
||||
dns_view_t *view = NULL, *view_next = NULL;
|
||||
dns_kasp_t *kasp = NULL, *kasp_next = NULL;
|
||||
dns_keystore_t *keystore = NULL, *keystore_next = NULL;
|
||||
bool flush = server->flushonshutdown;
|
||||
named_cache_t *nsc = NULL;
|
||||
|
||||
@ -9895,6 +9951,14 @@ shutdown_server(void *arg) {
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
|
||||
for (keystore = ISC_LIST_HEAD(server->keystorelist); keystore != NULL;
|
||||
keystore = keystore_next)
|
||||
{
|
||||
keystore_next = ISC_LIST_NEXT(keystore, link);
|
||||
ISC_LIST_UNLINK(server->keystorelist, keystore, link);
|
||||
dns_keystore_detach(&keystore);
|
||||
}
|
||||
|
||||
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
|
||||
view = view_next)
|
||||
{
|
||||
@ -10001,6 +10065,7 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
|
||||
|
||||
/* Initialize server data structures. */
|
||||
ISC_LIST_INIT(server->kasplist);
|
||||
ISC_LIST_INIT(server->keystorelist);
|
||||
ISC_LIST_INIT(server->viewlist);
|
||||
|
||||
/* Must be first. */
|
||||
@ -10109,6 +10174,7 @@ named_server_destroy(named_server_t **serverp) {
|
||||
dst_lib_destroy();
|
||||
|
||||
INSIST(ISC_LIST_EMPTY(server->kasplist));
|
||||
INSIST(ISC_LIST_EMPTY(server->keystorelist));
|
||||
INSIST(ISC_LIST_EMPTY(server->viewlist));
|
||||
INSIST(ISC_LIST_EMPTY(server->cachelist));
|
||||
|
||||
@ -13351,8 +13417,9 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
|
||||
/* Mark view unfrozen and configure zone */
|
||||
dns_view_thaw(view);
|
||||
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
|
||||
&server->viewlist, &server->kasplist, cfg->actx,
|
||||
true, false, false);
|
||||
&server->viewlist, &server->kasplist,
|
||||
&server->keystorelist, cfg->actx, true, false,
|
||||
false);
|
||||
dns_view_freeze(view);
|
||||
|
||||
isc_loopmgr_resume(named_g_loopmgr);
|
||||
@ -13536,8 +13603,9 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
|
||||
/* Reconfigure the zone */
|
||||
dns_view_thaw(view);
|
||||
result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view,
|
||||
&server->viewlist, &server->kasplist, cfg->actx,
|
||||
true, false, true);
|
||||
&server->viewlist, &server->kasplist,
|
||||
&server->keystorelist, cfg->actx, true, false,
|
||||
true);
|
||||
dns_view_freeze(view);
|
||||
|
||||
isc_loopmgr_resume(named_g_loopmgr);
|
||||
@ -14561,7 +14629,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
char output[4096];
|
||||
isc_stdtime_t now, when;
|
||||
isc_time_t timenow, timewhen;
|
||||
const char *dir;
|
||||
dns_db_t *db = NULL;
|
||||
dns_dbversion_t *version = NULL;
|
||||
|
||||
@ -14696,7 +14763,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
}
|
||||
|
||||
/* Get DNSSEC keys. */
|
||||
dir = dns_zone_getkeydirectory(zone);
|
||||
CHECK(dns_zone_getdb(zone, &db));
|
||||
dns_db_currentversion(db, &version);
|
||||
LOCK(&kasp->lock);
|
||||
@ -14728,11 +14794,11 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
|
||||
LOCK(&kasp->lock);
|
||||
if (use_keyid) {
|
||||
result = dns_keymgr_checkds_id(kasp, &keys, dir, now,
|
||||
when, dspublish, keyid,
|
||||
result = dns_keymgr_checkds_id(kasp, &keys, now, when,
|
||||
dspublish, keyid,
|
||||
(unsigned int)algorithm);
|
||||
} else {
|
||||
result = dns_keymgr_checkds(kasp, &keys, dir, now, when,
|
||||
result = dns_keymgr_checkds(kasp, &keys, now, when,
|
||||
dspublish);
|
||||
}
|
||||
UNLOCK(&kasp->lock);
|
||||
@ -14783,7 +14849,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
|
||||
isc_result_t ret;
|
||||
|
||||
LOCK(&kasp->lock);
|
||||
result = dns_keymgr_rollover(kasp, &keys, dir, now, when, keyid,
|
||||
result = dns_keymgr_rollover(kasp, &keys, now, when, keyid,
|
||||
(unsigned int)algorithm);
|
||||
UNLOCK(&kasp->lock);
|
||||
|
||||
|
@ -866,8 +866,8 @@ process_notifytype(dns_notifytype_t ntype, dns_zonetype_t ztype,
|
||||
isc_result_t
|
||||
named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
|
||||
dns_kasplist_t *kasplist, dns_zone_t *zone,
|
||||
dns_zone_t *raw) {
|
||||
dns_kasplist_t *kasplist, dns_keystorelist_t *keystorelist,
|
||||
dns_zone_t *zone, dns_zone_t *raw) {
|
||||
isc_result_t result;
|
||||
const char *zname;
|
||||
dns_rdataclass_t zclass;
|
||||
@ -1576,6 +1576,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
filename = cfg_obj_asstring(obj);
|
||||
CHECK(dns_zone_setkeydirectory(zone, filename));
|
||||
}
|
||||
/* Also save a reference to the keystore list. */
|
||||
dns_zone_setkeystores(zone, keystorelist);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "sig-signing-signatures", &obj);
|
||||
|
59
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore1.conf
Normal file
59
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore1.conf
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The same zone in different views is using different DNSSEC policies, so it
|
||||
* may not use the same directory for storing keys.
|
||||
*/
|
||||
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store2" {
|
||||
directory ".";
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store2" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "default";
|
||||
key-directory ".";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
59
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore2.conf
Normal file
59
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore2.conf
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* In view "example1" no key-directory is set, so the default is used.
|
||||
* In view "example2" the key-store directory is set to "." which is the
|
||||
* default. This should fail because the same zone in different views is using
|
||||
* different DNSSEC policies.
|
||||
*/
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store2" {
|
||||
directory ".";
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store2" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "default";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
64
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore3.conf
Normal file
64
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore3.conf
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The zone in view "example1" inherits the key directory value from "options",
|
||||
* but in view "example2" sets the key-store directory to the same value.
|
||||
* This should be detected as an error because the zone is using different
|
||||
* DNSSEC policies and should thus use different key directories.
|
||||
*/
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store2" {
|
||||
directory "keys";
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store2" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
options {
|
||||
key-directory "keys";
|
||||
};
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
/* key-directory inherited from options. */
|
||||
dnssec-policy "default";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
60
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore4.conf
Normal file
60
bin/tests/system/checkconf/bad-kasp-keydir-vs-keystore4.conf
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The zone inherits the key-directory from the "view" level. Both views use the
|
||||
* same directory for storing keys, but the zone uses a different DNSSEC policy
|
||||
* per view. This is a configuration error.
|
||||
*/
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store2" {
|
||||
directory "keys";
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store2" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
key-directory "keys";
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "default";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
19
bin/tests/system/checkconf/bad-kasp-keystore.conf
Normal file
19
bin/tests/system/checkconf/bad-kasp-keystore.conf
Normal file
@ -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;
|
||||
};
|
||||
};
|
68
bin/tests/system/checkconf/bad-kasp-keystore1.conf
Normal file
68
bin/tests/system/checkconf/bad-kasp-keystore1.conf
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The same zone in different views is using different DNSSEC policies, so it
|
||||
* may not use the same key-store directory.
|
||||
*/
|
||||
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store1" {
|
||||
directory "keys";
|
||||
};
|
||||
|
||||
key-store "store2" {
|
||||
directory "keys";
|
||||
};
|
||||
|
||||
dnssec-policy "policy1" {
|
||||
keys {
|
||||
csk key-store "store1" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store2" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy1";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
64
bin/tests/system/checkconf/bad-kasp-keystore2.conf
Normal file
64
bin/tests/system/checkconf/bad-kasp-keystore2.conf
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Both policies use the same key-store. Should fail because the same zone in
|
||||
* different views is using different DNSSEC policies.
|
||||
*/
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm "hmac-sha1";
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "store" {
|
||||
directory "keys";
|
||||
};
|
||||
|
||||
dnssec-policy "policy1" {
|
||||
keys {
|
||||
csk key-store "store" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "policy2" {
|
||||
keys {
|
||||
csk key-store "store" lifetime unlimited algorithm 13;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
view "example1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy1";
|
||||
file "example1.db";
|
||||
};
|
||||
};
|
||||
|
||||
view "example2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "example.net" {
|
||||
type primary;
|
||||
dnssec-policy "policy2";
|
||||
file "example2.db";
|
||||
};
|
||||
};
|
24
bin/tests/system/checkconf/bad-keystore-key-directory.conf
Normal file
24
bin/tests/system/checkconf/bad-keystore-key-directory.conf
Normal file
@ -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;
|
||||
};
|
||||
};
|
@ -26,7 +26,7 @@ dnssec-policy "test" {
|
||||
keys {
|
||||
ksk key-directory lifetime P1Y algorithm ecdsa256;
|
||||
zsk lifetime P30D algorithm 13;
|
||||
csk key-directory lifetime unlimited algorithm rsasha256 2048;
|
||||
csk key-store "hsm" lifetime unlimited algorithm rsasha256 2048;
|
||||
};
|
||||
max-zone-ttl 86400;
|
||||
nsec3param iterations 0 optout no salt-length 8;
|
||||
@ -39,6 +39,10 @@ dnssec-policy "test" {
|
||||
signatures-validity-dnskey P14D;
|
||||
zone-propagation-delay PT5M;
|
||||
};
|
||||
key-store "hsm" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=bind9;pin-value=1234";
|
||||
};
|
||||
options {
|
||||
dnssec-policy "default";
|
||||
};
|
||||
|
@ -23,9 +23,9 @@ dnssec-policy "test" {
|
||||
};
|
||||
dnskey-ttl 3600;
|
||||
keys {
|
||||
ksk key-directory lifetime P1Y algorithm 13 256;
|
||||
zsk key-directory lifetime P30D algorithm 13;
|
||||
csk key-directory lifetime P30D algorithm 8 2048;
|
||||
ksk key-directory lifetime P1Y algorithm 13;
|
||||
zsk lifetime P30D algorithm 13;
|
||||
csk key-store "hsm" lifetime P30D algorithm 8 2048;
|
||||
};
|
||||
max-zone-ttl 86400;
|
||||
nsec3param ;
|
||||
@ -39,6 +39,10 @@ dnssec-policy "test" {
|
||||
signatures-validity-dnskey P14D;
|
||||
zone-propagation-delay PT5M;
|
||||
};
|
||||
key-store "hsm" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=bind9;pin-value=1234";
|
||||
};
|
||||
options {
|
||||
avoid-v4-udp-ports {
|
||||
100;
|
||||
|
@ -300,20 +300,32 @@ n=$((n + 1))
|
||||
echo_i "checking for missing key directory warning ($n)"
|
||||
ret=0
|
||||
rm -rf test.keydir
|
||||
rm -rf test.keystoredir
|
||||
$CHECKCONF warn-keydir.conf >checkconf.out$n.1 2>&1
|
||||
l=$(grep "'test.keydir' does not exist" <checkconf.out$n.1 | wc -l)
|
||||
[ $l -eq 1 ] || ret=1
|
||||
l=$(grep "'test.keystoredir' does not exist" <checkconf.out$n.1 | wc -l)
|
||||
[ $l -eq 1 ] || ret=1
|
||||
touch test.keydir
|
||||
touch test.keystoredir
|
||||
$CHECKCONF warn-keydir.conf >checkconf.out$n.2 2>&1
|
||||
l=$(grep "'test.keydir' is not a directory" <checkconf.out$n.2 | wc -l)
|
||||
[ $l -eq 1 ] || ret=1
|
||||
l=$(grep "'test.keystoredir' is not a directory" <checkconf.out$n.2 | wc -l)
|
||||
[ $l -eq 1 ] || ret=1
|
||||
rm -f test.keydir
|
||||
rm -f test.keystoredir
|
||||
mkdir test.keydir
|
||||
mkdir test.keystoredir
|
||||
$CHECKCONF warn-keydir.conf >checkconf.out$n.3 2>&1
|
||||
l=$(grep "key-directory" <checkconf.out$n.3 | wc -l)
|
||||
[ $l -eq 0 ] || ret=1
|
||||
l=$(grep "key-store directory" <checkconf.out$n.3 | wc -l)
|
||||
[ $l -eq 0 ] || ret=1
|
||||
rm -rf test.keydir
|
||||
rm -rf test.keystoredir
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking that named-checkconf -z catches conflicting ttl with max-ttl ($n)"
|
||||
|
@ -18,6 +18,10 @@ options {
|
||||
directory ".";
|
||||
};
|
||||
|
||||
key-store "test" {
|
||||
directory "test.keystoredir";
|
||||
};
|
||||
|
||||
zone dummy {
|
||||
type primary;
|
||||
file "xxxx";
|
||||
|
@ -18,18 +18,24 @@ set -e
|
||||
|
||||
rm -f dig.out.*
|
||||
rm -f dsset-*
|
||||
rm -f pin
|
||||
rm -f keyfromlabel.err.* keyfromlabel.out.*
|
||||
rm -f pkcs11-tool.err.* pkcs11-tool.out.*
|
||||
rm -f signer.out.*
|
||||
rm -f ns*/*.kskid1 ns*/*.kskid2 ns*/*.zskid1 ns/*.zskid2
|
||||
rm -f ns*/dig.out.*
|
||||
rm -f ns*/K*
|
||||
rm -f ns*/keygen.out.*
|
||||
rm -f ns*/named.conf ns1/named.args ns1/named.run ns1/named.memstats
|
||||
rm -f ns*/pin
|
||||
rm -f ns*/update.cmd.*
|
||||
rm -f ns*/update.log.*
|
||||
rm -f ns*/verify.out.*
|
||||
rm -f ns*/zone.*.jnl ns1/zone.*.jbk
|
||||
rm -f ns1/*.example.db ns1/*.example.db.signed
|
||||
rm -f ns1/*.kskid1 ns1/*.kskid2 ns1/*.zskid1 ns1/*.zskid2
|
||||
rm -f ns1/dig.out.*
|
||||
rm -f ns1/K*
|
||||
rm -f ns1/named.conf ns1/named.args ns1/named.run ns1/named.memstats
|
||||
rm -f ns1/update.cmd.*
|
||||
rm -f ns1/update.log.*
|
||||
rm -f ns1/verify.out.*
|
||||
rm -f ns1/zone.*.signed.jnl ns1/zone.*.signed.jbk
|
||||
rm -f ns1/*.kasp.db ns1/*.kasp.db.signed
|
||||
rm -f ns1/*.split.db ns1/*.split.db.signed
|
||||
rm -f ns2/*.views.db ns1/*.views.db.signed
|
||||
rm -rf ./ns1/keys/
|
||||
rm -rf ./ns2/keys/
|
||||
|
||||
OPENSSL_CONF= softhsm2-util --delete-token --token "softhsm2-enginepkcs11" >/dev/null 2>&1 || echo_i "softhsm2-enginepkcs11 token not found for cleaning"
|
||||
|
@ -34,3 +34,17 @@ key rndc_key {
|
||||
controls {
|
||||
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
key-store "hsm" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=softhsm2-enginepkcs11;pin-value=1234";
|
||||
};
|
||||
|
||||
key-store "pin" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=softhsm2-enginepkcs11;pin-source=pin";
|
||||
};
|
||||
|
||||
key-store "disk" {
|
||||
directory "keys";
|
||||
};
|
||||
|
1
bin/tests/system/enginepkcs11/ns2/named.args.in
Normal file
1
bin/tests/system/enginepkcs11/ns2/named.args.in
Normal file
@ -0,0 +1 @@
|
||||
@ENGINE_ARGS@ -D enginepkcs11-ns2 -m record -c named.conf -d 99 -U 4 -T maxcachesize=2097152
|
57
bin/tests/system/enginepkcs11/ns2/named.conf.in
Normal file
57
bin/tests/system/enginepkcs11/ns2/named.conf.in
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
controls { /* empty */ };
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.2;
|
||||
notify-source 10.53.0.2;
|
||||
transfer-source 10.53.0.2;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.2; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
notify no;
|
||||
};
|
||||
|
||||
key "keyforview1" {
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
|
||||
};
|
||||
|
||||
key "keyforview2" {
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
|
||||
};
|
||||
|
||||
key-store "hsm" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=softhsm2-enginepkcs11;pin-value=1234";
|
||||
};
|
||||
|
||||
key-store "hsm2" {
|
||||
directory "keys";
|
||||
pkcs11-uri "pkcs11:token=softhsm2-enginepkcs11;pin-value=1234";
|
||||
};
|
||||
|
||||
key-store "pin" {
|
||||
directory ".";
|
||||
pkcs11-uri "pkcs11:token=softhsm2-enginepkcs11;pin-source=pin";
|
||||
};
|
||||
|
||||
key-store "disk" {
|
||||
directory "keys";
|
||||
};
|
||||
|
23
bin/tests/system/enginepkcs11/ns2/template.db.in
Normal file
23
bin/tests/system/enginepkcs11/ns2/template.db.in
Normal file
@ -0,0 +1,23 @@
|
||||
; 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 http://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$TTL 300 ; 5 minutes
|
||||
@ IN SOA ns root (
|
||||
2000082401 ; serial
|
||||
1800 ; refresh (30 minutes)
|
||||
1800 ; retry (30 minutes)
|
||||
1814400 ; expire (3 weeks)
|
||||
3600 ; minimum (1 hour)
|
||||
)
|
||||
NS ns
|
||||
ns A 10.53.0.2
|
||||
|
||||
txt TXT "test"
|
@ -13,6 +13,11 @@
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
[ "prereq/var/tmp/etc/openssl-provider.cnf" -eq "prereq${OPENSSL_CONF}" ] || {
|
||||
echo_i "skip: pkcs11-provider not enabled"
|
||||
exit 255
|
||||
}
|
||||
|
||||
[ -n "${SOFTHSM2_CONF}" ] || {
|
||||
echo_i "skip: softhsm2 configuration not available"
|
||||
exit 255
|
||||
|
@ -16,15 +16,14 @@
|
||||
|
||||
set -e
|
||||
|
||||
$SHELL clean.sh
|
||||
|
||||
OPENSSL_CONF= softhsm2-util --init-token --free --pin 1234 --so-pin 1234 --label "softhsm2-enginepkcs11" | awk '/^The token has been initialized and is reassigned to slot/ { print $NF }'
|
||||
|
||||
printf '%s' "${HSMPIN:-1234}" >pin
|
||||
parse_openssl_config
|
||||
printf '%s' "${HSMPIN:-1234}" >ns1/pin
|
||||
PWD=$(pwd)
|
||||
|
||||
copy_setports ns1/named.conf.in ns1/named.conf
|
||||
sed -e "s/@ENGINE_ARGS@/${ENGINE_ARG}/g" <ns1/named.args.in >ns1/named.args
|
||||
|
||||
keygen() {
|
||||
type="$1"
|
||||
bits="$2"
|
||||
@ -33,7 +32,7 @@ keygen() {
|
||||
|
||||
label="${id}-${zone}"
|
||||
p11id=$(echo "${label}" | openssl sha1 -r | awk '{print $1}')
|
||||
OPENSSL_CONF= pkcs11-tool --module $SOFTHSM2_MODULE --token-label "softhsm2-enginepkcs11" -l -k --key-type $type:$bits --label "${label}" --id "${p11id}" --pin $(cat $PWD/pin) >pkcs11-tool.out.$zone.$id 2>pkcs11-tool.err.$zone.$id || return 1
|
||||
OPENSSL_CONF= pkcs11-tool --module $SOFTHSM2_MODULE --token-label "softhsm2-enginepkcs11" -l -k --key-type $type:$bits --label "${label}" --id "${p11id}" --pin $(cat $PWD/ns1/pin) >pkcs11-tool.out.$zone.$id 2>pkcs11-tool.err.$zone.$id || return 1
|
||||
}
|
||||
|
||||
keyfromlabel() {
|
||||
@ -43,11 +42,16 @@ keyfromlabel() {
|
||||
dir="$4"
|
||||
shift 4
|
||||
|
||||
$KEYFRLAB $ENGINE_ARG -K $dir -a $alg -l "pkcs11:token=softhsm2-enginepkcs11;object=${id}-${zone};pin-source=$PWD/pin" "$@" $zone >>keyfromlabel.out.$zone.$id 2>keyfromlabel.err.$zone.$id || return 1
|
||||
$KEYFRLAB $ENGINE_ARG -K $dir -a $alg -l "pkcs11:token=softhsm2-enginepkcs11;object=${id}-${zone};pin-source=$PWD/ns1/pin" "$@" $zone >>keyfromlabel.out.$zone.$id 2>keyfromlabel.err.$zone.$id || return 1
|
||||
cat keyfromlabel.out.$zone.$id
|
||||
}
|
||||
|
||||
# Setup ns1.
|
||||
copy_setports ns1/named.conf.in ns1/named.conf
|
||||
sed -e "s/@ENGINE_ARGS@/${ENGINE_ARG}/g" <ns1/named.args.in >ns1/named.args
|
||||
|
||||
mkdir ns1/keys
|
||||
|
||||
dir="ns1"
|
||||
infile="${dir}/template.db.in"
|
||||
for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
|
||||
@ -57,9 +61,10 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
|
||||
type=$(echo "$algtypebits" | cut -f 2 -d :)
|
||||
bits=$(echo "$algtypebits" | cut -f 3 -d :)
|
||||
|
||||
tld="example"
|
||||
if $SHELL ../testcrypto.sh $alg; then
|
||||
zone="$alg.example"
|
||||
zonefile="zone.$alg.example.db"
|
||||
zone="$alg.$tld"
|
||||
zonefile="zone.$alg.$tld.db"
|
||||
ret=0
|
||||
|
||||
echo_i "Generate keys $alg $type:$bits for zone $zone"
|
||||
@ -111,6 +116,15 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
|
||||
cp "${ksk2}.key" "${ksk2}.ksk2"
|
||||
)
|
||||
|
||||
echo_i "Add zone $alg.kasp to named.conf"
|
||||
cp $infile ${dir}/zone.${alg}.kasp.db
|
||||
|
||||
echo_i "Add zone $alg.split to named.conf"
|
||||
cp $infile ${dir}/zone.${alg}.split.db
|
||||
|
||||
echo_i "Add weird zone to named.conf"
|
||||
cp $infile ${dir}/zone.${alg}.weird.db
|
||||
|
||||
echo_i "Add zone $zone to named.conf"
|
||||
cat >>"${dir}/named.conf" <<EOF
|
||||
zone "$zone" {
|
||||
@ -119,6 +133,195 @@ zone "$zone" {
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
dnssec-policy "$alg" {
|
||||
keys {
|
||||
ksk key-store "hsm" lifetime unlimited algorithm ${alg};
|
||||
zsk key-store "pin" lifetime unlimited algorithm ${alg};
|
||||
};
|
||||
};
|
||||
|
||||
zone "${alg}.kasp" {
|
||||
type primary;
|
||||
file "zone.${alg}.kasp.db";
|
||||
dnssec-policy "$alg";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
dnssec-policy "weird-${alg}-\"\:\;\?\&\[\]\@\!\$\*\+\,\|\=\.\(\)" {
|
||||
keys {
|
||||
ksk key-store "hsm" lifetime unlimited algorithm ${alg};
|
||||
zsk key-store "pin" lifetime unlimited algorithm ${alg};
|
||||
};
|
||||
};
|
||||
|
||||
zone "${alg}.\"\:\;\?\&\[\]\@\!\$\*\+\,\|\=\.\(\)foo.weird" {
|
||||
type primary;
|
||||
file "zone.${alg}.weird.db";
|
||||
check-names ignore;
|
||||
dnssec-policy "weird-${alg}-\"\:\;\?\&\[\]\@\!\$\*\+\,\|\=\.\(\)";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
dnssec-policy "${alg}-split" {
|
||||
keys {
|
||||
ksk key-store "hsm" lifetime unlimited algorithm ${alg};
|
||||
zsk key-store "disk" lifetime unlimited algorithm ${alg};
|
||||
};
|
||||
};
|
||||
|
||||
zone "${alg}.split" {
|
||||
type primary;
|
||||
file "zone.${alg}.split.db";
|
||||
dnssec-policy "${alg}-split";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
|
||||
# Setup ns2 (with views).
|
||||
copy_setports ns2/named.conf.in ns2/named.conf
|
||||
sed -e "s/@ENGINE_ARGS@/${ENGINE_ARG}/g" <ns2/named.args.in >ns2/named.args
|
||||
|
||||
mkdir ns2/keys
|
||||
|
||||
dir="ns2"
|
||||
infile="${dir}/template.db.in"
|
||||
algtypebits="ecdsap256sha256:EC:prime256v1"
|
||||
alg=$(echo "$algtypebits" | cut -f 1 -d :)
|
||||
type=$(echo "$algtypebits" | cut -f 2 -d :)
|
||||
bits=$(echo "$algtypebits" | cut -f 3 -d :)
|
||||
tld="views"
|
||||
|
||||
if $SHELL ../testcrypto.sh $alg; then
|
||||
zone="$alg.$tld"
|
||||
zonefile1="zone.$alg.$tld.view1.db"
|
||||
zonefile2="zone.$alg.$tld.view2.db"
|
||||
ret=0
|
||||
|
||||
echo_i "Generate keys $alg $type:$bits for zone $zone"
|
||||
keygen $type $bits $zone enginepkcs11-zsk || ret=1
|
||||
keygen $type $bits $zone enginepkcs11-ksk || ret=1
|
||||
test "$ret" -eq 0 || exit 1
|
||||
|
||||
echo_i "Get ZSK $alg $zone $type:$bits"
|
||||
zsk1=$(keyfromlabel $alg $zone enginepkcs11-zsk $dir)
|
||||
test -z "$zsk1" && exit 1
|
||||
|
||||
echo_i "Get KSK $alg $zone $type:$bits"
|
||||
ksk1=$(keyfromlabel $alg $zone enginepkcs11-ksk $dir -f KSK)
|
||||
test -z "$ksk1" && exit 1
|
||||
|
||||
(
|
||||
cd $dir
|
||||
zskid1=$(keyfile_to_key_id $zsk1)
|
||||
kskid1=$(keyfile_to_key_id $ksk1)
|
||||
echo "$zskid1" >$zone.zskid1
|
||||
echo "$kskid1" >$zone.kskid1
|
||||
)
|
||||
|
||||
echo_i "Sign zone with $ksk1 $zsk1"
|
||||
cat "$infile" "${dir}/${ksk1}.key" "${dir}/${zsk1}.key" >"${dir}/${zonefile1}"
|
||||
$SIGNER $ENGINE_ARG -K $dir -S -a -g -O full -o "$zone" "${dir}/${zonefile1}" >signer.out.view1.$zone || ret=1
|
||||
test "$ret" -eq 0 || exit 1
|
||||
|
||||
cat "$infile" "${dir}/${ksk1}.key" "${dir}/${zsk1}.key" >"${dir}/${zonefile2}"
|
||||
$SIGNER $ENGINE_ARG -K $dir -S -a -g -O full -o "$zone" "${dir}/${zonefile2}" >signer.out.view2.$zone || ret=1
|
||||
test "$ret" -eq 0 || exit 1
|
||||
|
||||
echo_i "Generate successor keys $alg $type:$bits for zone $zone"
|
||||
keygen $type $bits $zone enginepkcs11-zsk2 || ret=1
|
||||
keygen $type $bits $zone enginepkcs11-ksk2 || ret=1
|
||||
test "$ret" -eq 0 || exit 1
|
||||
|
||||
echo_i "Get ZSK $alg $id-$zone $type:$bits"
|
||||
zsk2=$(keyfromlabel $alg $zone enginepkcs11-zsk2 $dir)
|
||||
test -z "$zsk2" && exit 1
|
||||
|
||||
echo_i "Get KSK $alg $id-$zone $type:$bits"
|
||||
ksk2=$(keyfromlabel $alg $zone enginepkcs11-ksk2 $dir -f KSK)
|
||||
test -z "$ksk2" && exit 1
|
||||
|
||||
(
|
||||
cd $dir
|
||||
zskid2=$(keyfile_to_key_id $zsk2)
|
||||
kskid2=$(keyfile_to_key_id $ksk2)
|
||||
echo "$zskid2" >$zone.zskid2
|
||||
echo "$kskid2" >$zone.kskid2
|
||||
cp "${zsk2}.key" "${zsk2}.zsk2"
|
||||
cp "${ksk2}.key" "${ksk2}.ksk2"
|
||||
)
|
||||
|
||||
echo_i "Add zone $alg.same-policy.$tld to named.conf"
|
||||
cp $infile ${dir}/zone.${alg}.same-policy.view1.db
|
||||
cp $infile ${dir}/zone.${alg}.same-policy.view2.db
|
||||
|
||||
echo_i "Add zone zone-with.different-policy.$tld to named.conf"
|
||||
cp $infile ${dir}/zone.zone-with.different-policy.view1.db
|
||||
cp $infile ${dir}/zone.zone-with.different-policy.view2.db
|
||||
|
||||
echo_i "Add zone $zone to named.conf"
|
||||
cat >>"${dir}/named.conf" <<EOF
|
||||
dnssec-policy "$alg" {
|
||||
keys {
|
||||
csk key-store "hsm" lifetime unlimited algorithm ${alg};
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "rsasha256" {
|
||||
keys {
|
||||
csk key-store "hsm2" lifetime unlimited algorithm rsasha256 2048;
|
||||
};
|
||||
};
|
||||
|
||||
view "view1" {
|
||||
match-clients { key "keyforview1"; };
|
||||
|
||||
zone "$zone" {
|
||||
type primary;
|
||||
file "${zonefile1}.signed";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
zone "${alg}.same-policy.${tld}" {
|
||||
type primary;
|
||||
file "zone.${alg}.same-policy.view1.db";
|
||||
dnssec-policy "$alg";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
zone "zone-with.different-policy.${tld}" {
|
||||
type primary;
|
||||
file "zone.zone-with.different-policy.view1.db";
|
||||
dnssec-policy "$alg";
|
||||
allow-update { any; };
|
||||
};
|
||||
};
|
||||
|
||||
view "view2" {
|
||||
match-clients { key "keyforview2"; };
|
||||
|
||||
zone "$zone" {
|
||||
type primary;
|
||||
file "${zonefile2}.signed";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
zone "${alg}.same-policy.${tld}" {
|
||||
type primary;
|
||||
file "zone.${alg}.same-policy.view2.db";
|
||||
dnssec-policy "$alg";
|
||||
allow-update { any; };
|
||||
};
|
||||
|
||||
zone "zone-with.different-policy.${tld}" {
|
||||
type primary;
|
||||
file "zone.zone-with.different-policy.view2.db";
|
||||
dnssec-policy "rsasha256";
|
||||
allow-update { any; };
|
||||
};
|
||||
};
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
@ -23,9 +23,29 @@ status=0
|
||||
ret=0
|
||||
n=0
|
||||
|
||||
dig_with_opts() (
|
||||
dig_with_opts() {
|
||||
$DIG +tcp +noadd +nosea +nostat +nocmd +dnssec -p "$PORT" "$@"
|
||||
)
|
||||
}
|
||||
|
||||
check_keys() {
|
||||
_zone=$1
|
||||
_expect=$2
|
||||
_ret=0
|
||||
_status=0
|
||||
_count=$(ls K*.key | grep "K${_zone}" | wc -l)
|
||||
|
||||
test "$_count" -eq "$_expect" || _ret=1
|
||||
test "$_ret" -eq 0 || echo_i "failed (expected $_expect keys, got $_count)"
|
||||
_status=$((_status + _ret))
|
||||
|
||||
_ret=0
|
||||
_count=$(cat K${_zone}*.private | grep Label | wc -l)
|
||||
test "$_count" -eq "$_expect" || _ret=1
|
||||
test "$_ret" -eq 0 || echo_i "failed (expected Label metadata in key files)"
|
||||
_status=$((_status + _ret))
|
||||
|
||||
return $_status
|
||||
}
|
||||
|
||||
# Perform tests inside ns1 dir
|
||||
cd ns1
|
||||
@ -48,9 +68,7 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
count=$(ls K*.key | grep "K${zone}" | wc -l)
|
||||
test "$count" -eq 4 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 4 keys, got $count)"
|
||||
check_keys $zone 4 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
@ -68,10 +86,10 @@ for algtypebits in rsasha256:rsa:2048 rsasha512:rsa:2048 \
|
||||
ret=0
|
||||
echo_i "Test inline signing for $zone ($n)"
|
||||
dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || ret=1
|
||||
awk '$4 == "RRSIG" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || return 1
|
||||
awk '$4 == "RRSIG" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || ret=1
|
||||
numsigs=$(cat dig.out.keyids.$zone.$n | wc -l)
|
||||
test $numsigs -eq 1 || return 1
|
||||
grep -w "$zskid1" dig.out.keyids.$zone.$n >/dev/null || return 1
|
||||
test $numsigs -eq 1 || ret=1
|
||||
grep -w "$zskid1" dig.out.keyids.$zone.$n >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed with key $zskid1)"
|
||||
status=$((status + ret))
|
||||
|
||||
@ -94,11 +112,11 @@ EOF
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY response for $zone after inline signing ($n)"
|
||||
_dig_dnskey() (
|
||||
_dig_dnskey() {
|
||||
dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1
|
||||
count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n)
|
||||
test $count -eq 3
|
||||
)
|
||||
}
|
||||
retry_quiet 10 _dig_dnskey || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 3 DNSKEY records)"
|
||||
status=$((status + ret))
|
||||
@ -106,7 +124,7 @@ EOF
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA response for $zone after inline signing ($n)"
|
||||
_dig_soa() (
|
||||
_dig_soa() {
|
||||
dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || return 1
|
||||
awk '$4 == "RRSIG" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || return 1
|
||||
numsigs=$(cat dig.out.keyids.$zone.$n | wc -l)
|
||||
@ -114,7 +132,7 @@ EOF
|
||||
grep -w "$zskid1" dig.out.keyids.$zone.$n >/dev/null || return 1
|
||||
grep -w "$zskid2" dig.out.keyids.$zone.$n >/dev/null || return 1
|
||||
return 0
|
||||
)
|
||||
}
|
||||
retry_quiet 10 _dig_soa || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 2 SOA RRSIG records)"
|
||||
status=$((status + ret))
|
||||
@ -142,7 +160,7 @@ EOF
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY response for $zone after inline signing (key signing) ($n)"
|
||||
_dig_dnskey_ksk() (
|
||||
_dig_dnskey_ksk() {
|
||||
dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1
|
||||
count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n)
|
||||
test $count -eq 4 || return 1
|
||||
@ -152,16 +170,245 @@ EOF
|
||||
grep -w "$kskid1" dig.out.keyids.$zone.$n >/dev/null || return 1
|
||||
grep -w "$kskid2" dig.out.keyids.$zone.$n >/dev/null || return 1
|
||||
return 0
|
||||
)
|
||||
}
|
||||
retry_quiet 10 _dig_dnskey_ksk || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 4 DNSKEY records, 2 KSK signatures)"
|
||||
status=$((status + ret))
|
||||
|
||||
# Check dnssec-policy interaction.
|
||||
|
||||
# Basic checks if setup was successful (dnssec-policy).
|
||||
zone="${alg}.kasp"
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
check_keys $zone 2 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY response for $zone ($n)"
|
||||
_dig_policy_dnskey() {
|
||||
dig_with_opts "$zone" @10.53.0.1 DNSKEY >dig.out.dnskey.$zone.$n || return 1
|
||||
count=$(awk 'BEGIN { count = 0 } $4 == "DNSKEY" { count++ } END {print count}' dig.out.dnskey.$zone.$n)
|
||||
test $count -eq 2
|
||||
}
|
||||
retry_quiet 2 _dig_policy_dnskey || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 2 DNSKEY records)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA response for $zone ($n)"
|
||||
_dig_policy_soa() {
|
||||
dig_with_opts "$zone" @10.53.0.1 SOA >dig.out.soa.$zone.$n || return 1
|
||||
awk '$4 == "RRSIG" && $5 == "SOA" { print $11 }' dig.out.soa.$zone.$n >dig.out.keyids.$zone.$n || return 1
|
||||
numsigs=$(cat dig.out.keyids.$zone.$n | wc -l)
|
||||
test $numsigs -eq 1 || return 1
|
||||
return 0
|
||||
}
|
||||
retry_quiet 2 _dig_policy_soa || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected a SOA RRSIG record)"
|
||||
|
||||
zone="$alg.\"\:\;\?\&\[\]\@\!\$\*\+\,\|\=\.\(\)foo.weird"
|
||||
keyfile="${alg}.%22%3A%3B%3F%26%5B%5D%40%21%24%2A%2B%2C%7C%3D%2E%28%29foo.weird"
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
check_keys $keyfile 2 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY response for $zone ($n)"
|
||||
retry_quiet 2 _dig_policy_dnskey || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 2 DNSKEY records)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA response for $zone ($n)"
|
||||
retry_quiet 2 _dig_policy_soa || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected a SOA RRSIG record)"
|
||||
status=$((status + ret))
|
||||
|
||||
# Check a dnssec-policy that uses multiple key-stores.
|
||||
zone="${alg}.split"
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
# Check KSK.
|
||||
check_keys $zone 1 || ret=1
|
||||
# Check ZSK.
|
||||
count=$(ls keys/K*.key | grep "K${_zone}" | wc -l)
|
||||
test "$count" -eq 1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 1 key, got $count)"
|
||||
status=$((status + ret))
|
||||
ret=0
|
||||
count=$(cat keys/K${zone}*.private | grep Engine | wc -l)
|
||||
test "$count" -eq 0 || ret=1
|
||||
count=$(cat keys/K${zone}*.private | grep Label | wc -l)
|
||||
test "$count" -eq 0 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (unexpected Engine and Label in key files)"
|
||||
status=$((status + ret))
|
||||
|
||||
# Check dnssec-keygen with dnssec-policy and key-store.
|
||||
zone="${alg}.keygen"
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test dnssec-keygen for $zone ($n)"
|
||||
$KEYGEN $ENGINE_ARG -k $alg -l named.conf $zone >keygen.out.$zone.$n 2>/dev/null || ret=1
|
||||
check_keys $zone 2 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
done
|
||||
|
||||
# Go back to main test dir.
|
||||
cd ..
|
||||
|
||||
# Perform tests inside ns2 dir
|
||||
cd ns2
|
||||
|
||||
algtypebits="ecdsap256sha256:EC:prime256v1"
|
||||
alg=$(echo "$algtypebits" | cut -f 1 -d :)
|
||||
type=$(echo "$algtypebits" | cut -f 2 -d :)
|
||||
bits=$(echo "$algtypebits" | cut -f 3 -d :)
|
||||
zone="${alg}.views"
|
||||
zonefile1="zone.$alg.views.view1.db.signed"
|
||||
zonefile2="zone.$alg.views.view2.db.signed"
|
||||
|
||||
skip=0
|
||||
if [ ! -f $zonefile1 ]; then
|
||||
echo_i "skipping test for ${alg}:${type}:${bits}, no signed zone file ${zonefile1}"
|
||||
skip=1
|
||||
fi
|
||||
|
||||
if [ ! -f $zonefile2 ]; then
|
||||
echo_i "skipping test for ${alg}:${type}:${bits}, no signed zone file ${zonefile2}"
|
||||
skip=1
|
||||
fi
|
||||
|
||||
if [ $skip -eq 0 ]; then
|
||||
# Basic checks if setup was successful.
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
check_keys $zone 4 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test zone signing was successful for $zone in view1 ($n)"
|
||||
$VERIFY -z -o $zone "${zonefile1}" >verify.out.$zone.view1.$n 2>&1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (dnssec-verify failed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test zone signing was successful for $zone in view2 ($n)"
|
||||
$VERIFY -z -o $zone "${zonefile2}" >verify.out.$zone.view2.$n 2>&1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (dnssec-verify failed)"
|
||||
status=$((status + ret))
|
||||
|
||||
# Test dnssec-policy signing with keys stored in engine.
|
||||
zone="${alg}.same-policy.views"
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone ($n)"
|
||||
check_keys $zone 1 || ret=1
|
||||
status=$((status + ret))
|
||||
|
||||
_dig_inview() {
|
||||
_qtype="$1"
|
||||
_alg="$2"
|
||||
_tsig="$DEFAULT_HMAC:$3:$4"
|
||||
dig_with_opts "$zone" @10.53.0.2 $_qtype -y "$_tsig" >dig.out.$zone.$n || return 1
|
||||
awk -v cov="$_qtype" '$4 == "RRSIG" && $5 == cov { print $6 }' dig.out.$zone.$n >dig.out.alg.$zone.$n || return 1
|
||||
numsigs=$(cat dig.out.alg.$zone.$n | wc -l)
|
||||
test $numsigs -eq 1 || return 1
|
||||
grep -w "$_alg" dig.out.alg.$zone.$n >/dev/null || return 1
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA is signed for $zone in view1 ($n)"
|
||||
VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY="
|
||||
retry_quiet 4 _dig_inview SOA 13 keyforview1 $VIEW1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY is signed for $zone in view1 ($n)"
|
||||
retry_quiet 4 _dig_inview DNSKEY 13 keyforview1 $VIEW1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA is signed for $zone in view2 ($n)"
|
||||
VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
|
||||
retry_quiet 4 _dig_inview SOA 13 keyforview2 $VIEW2 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY is signed for $zone in view2 ($n)"
|
||||
retry_quiet 4 _dig_inview DNSKEY 13 keyforview2 $VIEW2 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
# Now test zone in different views using a different dnssec-policy.
|
||||
zone="zone-with.different-policy.views"
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test key generation was successful for $zone in view1 ($n)"
|
||||
# view1
|
||||
check_keys $zone 1 || ret=1
|
||||
status=$((status + ret))
|
||||
# view2
|
||||
echo_i "Test key generation was successful for $zone in view2 ($n)"
|
||||
count=$(ls keys/K*.key | grep "K${zone}" | wc -l)
|
||||
test "$count" -eq 1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (expected 1 key, got $count)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA is signed for $zone in view1 ($n)"
|
||||
VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY="
|
||||
retry_quiet 4 _dig_inview SOA 13 keyforview1 $VIEW1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY is signed for $zone in view1 ($n)"
|
||||
retry_quiet 4 _dig_inview DNSKEY 13 keyforview1 $VIEW1 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test SOA is signed for $zone in view2 ($n)"
|
||||
VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
|
||||
retry_quiet 4 _dig_inview SOA 8 keyforview2 $VIEW2 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (SOA RRset not signed)"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Test DNSKEY is signed for $zone in view2 ($n)"
|
||||
retry_quiet 4 _dig_inview DNSKEY 8 keyforview2 $VIEW2 || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed (DNSKEY RRset not signed)"
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
# Go back to main test dir.
|
||||
cd ..
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "Checking for assertion failure in pk11_numbits()"
|
||||
|
@ -67,6 +67,8 @@ VIEW3="C1Azf+gGPMmxrUg/WQINP6eV9Y0="
|
||||
# PRIVKEY_STAT
|
||||
# PUBKEY_STAT
|
||||
# STATE_STAT
|
||||
# FLAGS
|
||||
# KEYDIR
|
||||
|
||||
key_key() {
|
||||
echo "${1}__${2}"
|
||||
@ -132,6 +134,7 @@ key_clear() {
|
||||
key_set "$1" "PRIVKEY_STAT" '0'
|
||||
key_set "$1" "PUBKEY_STAT" '0'
|
||||
key_set "$1" "STATE_STAT" '0'
|
||||
key_set "$1" "KEYDIR" 'none'
|
||||
}
|
||||
|
||||
# Start clear.
|
||||
@ -176,7 +179,7 @@ get_keyids() {
|
||||
_zone=$2
|
||||
_regex="K${_zone}.+*+*.key"
|
||||
|
||||
find "${_dir}" -mindepth 1 -maxdepth 1 -name "${_regex}" | sed "s,$_dir/K${_zone}.+\([0-9]\{3\}\)+\([0-9]\{5\}\).key,\2,"
|
||||
find "${_dir}" -mindepth 1 -maxdepth 3 -name "${_regex}" | sed "s,.*/K${_zone}.+\([0-9]\{3\}\)+\([0-9]\{5\}\).key,\2,"
|
||||
}
|
||||
|
||||
# By default log errors and don't quit immediately.
|
||||
@ -313,6 +316,13 @@ set_keystate() {
|
||||
key_set "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
# Set key directory.
|
||||
# $1: Key to update (KEY1, KEY2, ...)
|
||||
# $2: Directory.
|
||||
set_keydir() {
|
||||
key_set "$1" "KEYDIR" "$2"
|
||||
}
|
||||
|
||||
# Check the key $1 with id $2.
|
||||
# This requires environment variables to be set.
|
||||
#
|
||||
@ -324,7 +334,10 @@ set_keystate() {
|
||||
# KEY_ID=$(echo $1 | sed 's/^0\{0,4\}//')
|
||||
# KEY_CREATED (from the KEY_FILE)
|
||||
check_key() {
|
||||
_dir="$DIR"
|
||||
_dir=$(key_get "$1" KEYDIR)
|
||||
if [ "$_dir" = "none" ]; then
|
||||
_dir="$DIR"
|
||||
fi
|
||||
_zone="$ZONE"
|
||||
_role=$(key_get "$1" ROLE)
|
||||
_key_idpad="$2"
|
||||
@ -465,7 +478,10 @@ check_key() {
|
||||
|
||||
# Check the key timing metadata for key $1.
|
||||
check_timingmetadata() {
|
||||
_dir="$DIR"
|
||||
_dir=$(key_get "$1" KEYDIR)
|
||||
if [ "$_dir" = "none" ]; then
|
||||
_dir="$DIR"
|
||||
fi
|
||||
_zone="$ZONE"
|
||||
_key_idpad=$(key_get "$1" ID)
|
||||
_key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//')
|
||||
@ -644,11 +660,11 @@ check_keytimes() {
|
||||
# STATE_FILE="${BASE_FILE}.state"
|
||||
# KEY_ID=$(echo $1 | sed 's/^0\{0,4\}//')
|
||||
key_unused() {
|
||||
_dir=$DIR
|
||||
_zone=$ZONE
|
||||
_key_idpad=$1
|
||||
_dir="$DIR"
|
||||
_zone="$ZONE"
|
||||
_key_idpad="$1"
|
||||
_key_id=$(echo "$_key_idpad" | sed 's/^0\{0,4\}//')
|
||||
_alg_num=$2
|
||||
_alg_num="$2"
|
||||
_alg_numpad=$(printf "%03d" "$_alg_num")
|
||||
|
||||
BASE_FILE="${_dir}/K${_zone}.+${_alg_numpad}+${_key_idpad}"
|
||||
@ -788,6 +804,8 @@ _check_keys() {
|
||||
#
|
||||
# It is expected that KEY1, KEY2, KEY3, and KEY4 arrays are set correctly.
|
||||
# Found key identifiers are stored in the right key array.
|
||||
# Keys are found if they are stored inside $DIR or in a subdirectory up to
|
||||
# three levels deeper.
|
||||
check_keys() {
|
||||
n=$((n + 1))
|
||||
echo_i "check keys are created for zone ${ZONE} ($n)"
|
||||
|
@ -35,3 +35,5 @@ rm -f rndc.dnssec.*.out.* rndc.zonestatus.out.*
|
||||
rm -f python.out.*
|
||||
rm -f *-supported.file
|
||||
rm -f created.key-* unused.key-*
|
||||
rm -f ns3/ksk/K* ns3/zsk/K*
|
||||
rm -rf ./ns3/ksk/ ./ns3/zsk/
|
||||
|
@ -166,6 +166,14 @@ zone "inline-signing.kasp" {
|
||||
dnssec-policy "default";
|
||||
};
|
||||
|
||||
/* A zone that uses dnssec-policy with key stores. */
|
||||
zone "keystore.kasp" {
|
||||
type primary;
|
||||
file "keystore.kasp.db";
|
||||
inline-signing yes;
|
||||
dnssec-policy "keystore";
|
||||
};
|
||||
|
||||
/*
|
||||
* A configured dnssec-policy but some keys already created.
|
||||
*/
|
||||
|
@ -121,3 +121,20 @@ dnssec-policy "checkds-csk" {
|
||||
dnssec-policy "ttl" {
|
||||
max-zone-ttl 299;
|
||||
};
|
||||
|
||||
key-store "ksk" {
|
||||
directory "ksk";
|
||||
};
|
||||
|
||||
key-store "zsk" {
|
||||
directory "zsk";
|
||||
};
|
||||
|
||||
dnssec-policy "keystore" {
|
||||
dnskey-ttl 303;
|
||||
|
||||
keys {
|
||||
ksk key-store "ksk" lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk key-store "zsk" lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
echo_i "ns3/setup.sh"
|
||||
|
||||
# Create key store directories.
|
||||
mkdir ksk
|
||||
mkdir zsk
|
||||
|
||||
setup() {
|
||||
zone="$1"
|
||||
echo_i "setting up zone: $zone"
|
||||
@ -46,7 +50,7 @@ for zn in default dnssec-keygen some-keys legacy-keys pregenerated \
|
||||
rumoured rsasha256 rsasha512 ecdsa256 ecdsa384 \
|
||||
dynamic dynamic-inline-signing inline-signing \
|
||||
checkds-ksk checkds-doubleksk checkds-csk inherit unlimited \
|
||||
manual-rollover multisigner-model2; do
|
||||
manual-rollover multisigner-model2 keystore; do
|
||||
setup "${zn}.kasp"
|
||||
cp template.db.in "$zonefile"
|
||||
done
|
||||
|
@ -97,6 +97,7 @@ set_zonesigning "KEY4" "yes"
|
||||
|
||||
lines=$(get_keyids "$DIR" "$ZONE" | wc -l)
|
||||
test "$lines" -eq $NUM_KEYS || log_error "bad number of key ids"
|
||||
status=$((status + ret))
|
||||
|
||||
ids=$(get_keyids "$DIR" "$ZONE")
|
||||
for id in $ids; do
|
||||
@ -127,6 +128,7 @@ set_zone "kasp"
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "." "10.53.0.1"
|
||||
# Key properties.
|
||||
key_clear "KEY1"
|
||||
set_keyrole "KEY1" "csk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
|
||||
@ -508,7 +510,6 @@ n=$((n + 1))
|
||||
echo_i "check if resigning the raw version of the zone is prevented for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
grep "zone_resigninc: zone $ZONE/IN (unsigned): enter" $DIR/named.run && ret=1
|
||||
grep "error reading K$ZONE" $DIR/named.run && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
@ -538,6 +539,7 @@ key_clear "KEY4"
|
||||
set_zone "checkds-ksk.kasp"
|
||||
set_policy "checkds-ksk" "2" "303"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
|
||||
# Key properties.
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
@ -940,6 +942,55 @@ check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# Zone: keystore.kasp.
|
||||
#
|
||||
set_zone "keystore.kasp"
|
||||
set_policy "keystore" "2" "303"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# Key properties.
|
||||
key_clear "KEY1"
|
||||
set_keyrole "KEY1" "ksk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
set_keydir "KEY1" "ns3/ksk"
|
||||
set_keyalgorithm "KEY1" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "no"
|
||||
|
||||
key_clear "KEY2"
|
||||
set_keyrole "KEY2" "zsk"
|
||||
set_keylifetime "KEY2" "0"
|
||||
set_keydir "KEY2" "ns3/zsk"
|
||||
set_keyalgorithm "KEY2" "$DEFAULT_ALGORITHM_NUMBER" "$DEFAULT_ALGORITHM" "$DEFAULT_BITS"
|
||||
set_keysigning "KEY2" "no"
|
||||
set_zonesigning "KEY2" "yes"
|
||||
|
||||
# KSK: DNSKEY, RRSIG (ksk) published. DS needs to wait.
|
||||
# ZSK: DNSKEY, RRSIG (zsk) published.
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_DS" "hidden"
|
||||
|
||||
set_keystate "KEY2" "GOAL" "omnipresent"
|
||||
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
|
||||
# Two keys only.
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
# Reuse set_keytimes_csk_policy to set the KEY1 keytimes.
|
||||
set_keytimes_csk_policy
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_keytime "KEY2" "PUBLISHED" "${created}"
|
||||
set_keytime "KEY2" "ACTIVE" "${created}"
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# Zone: inherit.kasp.
|
||||
#
|
||||
|
@ -147,7 +147,7 @@ status=$((status + ret))
|
||||
n=$((n + 1))
|
||||
echo_i "make sure we did not try to sign with the keys added with nsupdate for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
grep "dns_dnssec_findzonekeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
# Verify again.
|
||||
@ -176,7 +176,7 @@ status=$((status + ret))
|
||||
n=$((n + 1))
|
||||
echo_i "make sure we did not try to sign with the keys added with nsupdate for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
grep "dns_dnssec_findzonekeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
# Verify again.
|
||||
@ -521,7 +521,7 @@ test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
dnssec_verify
|
||||
no_dnssec_in_journal
|
||||
grep "dns_dnssec_findzonekeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
# NS4
|
||||
@ -534,7 +534,7 @@ test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
dnssec_verify
|
||||
no_dnssec_in_journal
|
||||
grep "dns_dnssec_findzonekeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
|
@ -91,6 +91,11 @@ When using engine_pkcs11, all BIND binaries potentially need the keys require
|
||||
Even though OpenSSL 3 has compatibility support for Engine API it is not
|
||||
recommended to be used due to bugs in OpenSSL and libp11.
|
||||
|
||||
It is not possible to generate new keys via the engine_pkcs11 and therefore it
|
||||
is not recommended to use it in a ``dnssec-policy`` setup (although it is
|
||||
possible to put previously generated keys in the ``key-directory`` and let the
|
||||
key manager select those keys when a key rollover is started.
|
||||
|
||||
Configuring engine_pkcs11
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -170,8 +175,8 @@ path to the PKCS#11 module which should be gatewayed to. This can be done by
|
||||
editing the OpenSSL configuration file, by engine specific controls, or by using
|
||||
the p11-kit proxy module.
|
||||
|
||||
It is recommended that pkcs11-provider git commit 8672b98d2558aecb49f173df97b1463c7697b540
|
||||
from August 15, 2023 or later is used.
|
||||
It is required to use pkcs11-provider git commit
|
||||
2e8c26b4157fd21422c66f0b4d7b26cf8c320570 from October 2, 2023 or later.
|
||||
|
||||
BIND support for pkcs11-provider is built in and the -E command line option
|
||||
explained above should not be used.
|
||||
|
@ -407,6 +407,9 @@ The following blocks are supported:
|
||||
:namedconf:ref:`key`
|
||||
Specifies key information for use in authentication and authorization using TSIG.
|
||||
|
||||
:any:``key-store``
|
||||
Describes a DNSSEC key store. See :ref:`key-store Grammar <key_store_grammar>` for details.
|
||||
|
||||
:any:`logging`
|
||||
Specifies what information the server logs and where the log messages are sent.
|
||||
|
||||
@ -592,6 +595,42 @@ matching this name, algorithm, and secret.
|
||||
The ``secret_string`` is the secret to be used by the
|
||||
algorithm, and is treated as a Base64-encoded string.
|
||||
|
||||
.. _key_store_grammar:
|
||||
|
||||
:any:`key-store` Block Grammar
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. namedconf:statement:: key-store
|
||||
:tags: dnssec
|
||||
:short: Configures a DNSSEC key store.
|
||||
|
||||
.. _key_store_statement:
|
||||
|
||||
``key-store`` Block Definition and Usage
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``key-store`` statement defines how DNSSEC keys should be stored.
|
||||
|
||||
There is one built-in key store named ``key-directory``. Configuring
|
||||
keys to use ``key-store "key-directory"`` is identical to using
|
||||
``key-directory``.
|
||||
|
||||
The following options can be specified in a :any:`key-store` statement:
|
||||
|
||||
.. directory
|
||||
|
||||
The ``directory`` specifies where key files for this key should be stored.
|
||||
This is similar to using the zone's ``key-directory``.
|
||||
|
||||
.. namedconf:statement:: pkcs11-uri
|
||||
:tags: dnssec, pkcs11
|
||||
|
||||
The ``uri`` is a string that specifies a PKCS#11 URI Scheme (defined in
|
||||
:rfc:`7512`). When set, ``named`` will try to create keys inside the
|
||||
corresponding PKCS#11 token. This requires BIND to be built with OpenSSL 3,
|
||||
and have a PKCS#11 provider configured.
|
||||
|
||||
.. _logging_grammar:
|
||||
|
||||
:any:`logging` Block Grammar
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.. namedconf:statement:: logging
|
||||
@ -6282,7 +6321,10 @@ The following options can be specified in a :any:`dnssec-policy` statement:
|
||||
|
||||
This behavior is enabled by default.
|
||||
|
||||
:any:`keys`
|
||||
.. keys
|
||||
:tags: dnssec
|
||||
:short: Specifies the type of keys to be used for DNSSEC signing.
|
||||
|
||||
This is a list specifying the algorithms and roles to use when
|
||||
generating keys and signing the zone. Entries in this list do not
|
||||
represent specific DNSSEC keys, which may be changed on a regular
|
||||
@ -6298,7 +6340,7 @@ The following options can be specified in a :any:`dnssec-policy` statement:
|
||||
keys {
|
||||
ksk key-directory lifetime unlimited algorithm rsasha256 2048;
|
||||
zsk lifetime 30d algorithm 8;
|
||||
csk lifetime P6MT12H3M15S algorithm ecdsa256;
|
||||
csk key-store "hsm" lifetime P6MT12H3M15S algorithm ecdsa256;
|
||||
};
|
||||
|
||||
This example specifies that three keys should be used in the zone.
|
||||
@ -6311,9 +6353,15 @@ The following options can be specified in a :any:`dnssec-policy` statement:
|
||||
used to sign all RRsets.
|
||||
|
||||
An optional second token determines where the key is stored.
|
||||
Currently, keys can only be stored in the configured
|
||||
:any:`key-directory`. This token may be used in the future to store
|
||||
keys in hardware security modules or separate directories.
|
||||
The two available options are ``key-store <string>`` and
|
||||
``key-directory``.
|
||||
|
||||
When using ``key-store``, the referenced :any:`key-store` describes
|
||||
how the key should be be stored. This can be as a file, or it can be
|
||||
inside a PKCS#11 token.
|
||||
|
||||
When using ``key-directory``, the key is stored in the zone's
|
||||
configured :any:`key-directory`. This is also the default.
|
||||
|
||||
The ``lifetime`` parameter specifies how long a key may be used
|
||||
before rolling over. For convenience, TTL-style time-unit suffixes
|
||||
@ -6346,6 +6394,13 @@ The following options can be specified in a :any:`dnssec-policy` statement:
|
||||
Each KSK/ZSK pair must have the same algorithm. A CSK combines the
|
||||
functionality of a ZSK and a KSK.
|
||||
|
||||
.. note:: When changing the ``key-directory`` or the ``key-store``, BIND will
|
||||
be unable to find existing key files. Make sure you copy key files to the
|
||||
new directory before changing the path used in the configuration file.
|
||||
This is also true when changing to a built-in policy, for example to
|
||||
``insecure``. In this specific case you should move the existing key files
|
||||
to the zone's ``key-directory`` from the new configuration.
|
||||
|
||||
.. namedconf:statement:: purge-keys
|
||||
:tags: dnssec
|
||||
:short: Specifies the amount of time after which DNSSEC keys that have been deleted from the zone can be removed from disk.
|
||||
|
@ -15,7 +15,7 @@ dnssec-policy <string> {
|
||||
cds-digest-types { <string>; ... };
|
||||
dnskey-ttl <duration>;
|
||||
inline-signing <boolean>;
|
||||
keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime <duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
|
||||
keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
|
||||
max-zone-ttl <duration>;
|
||||
nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
|
||||
parent-ds-ttl <duration>;
|
||||
@ -42,6 +42,11 @@ key <string> {
|
||||
secret <string>;
|
||||
}; // may occur multiple times
|
||||
|
||||
key-store <string> {
|
||||
directory <string>;
|
||||
pkcs11-uri <quoted_string>;
|
||||
}; // may occur multiple times
|
||||
|
||||
logging {
|
||||
category <string> { <string>; ... }; // may occur multiple times
|
||||
channel <string> {
|
||||
|
@ -28,6 +28,11 @@ New Features
|
||||
- The statistics channel now includes counters that indicate the number
|
||||
of currently connected TCP IPv4/IPv6 clients. :gl:`#4425`
|
||||
|
||||
- Add HSM support to :any:`dnssec-policy`. You can now configure keys with a
|
||||
``key-store`` that allows you to set the directory to store the key files and
|
||||
set a PKCS#11 URI string. The latter requires OpenSSL 3 and a valid PKCS#11
|
||||
provider to be configured for OpenSSL. :gl`#1129`.
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -83,6 +83,7 @@ libdns_la_HEADERS = \
|
||||
include/dns/keydata.h \
|
||||
include/dns/keyflags.h \
|
||||
include/dns/keymgr.h \
|
||||
include/dns/keystore.h \
|
||||
include/dns/keytable.h \
|
||||
include/dns/keyvalues.h \
|
||||
include/dns/librpz.h \
|
||||
@ -190,6 +191,7 @@ libdns_la_SOURCES = \
|
||||
key.c \
|
||||
keydata.c \
|
||||
keymgr.c \
|
||||
keystore.c \
|
||||
keytable.c \
|
||||
log.c \
|
||||
master.c \
|
||||
|
333
lib/dns/dnssec.c
333
lib/dns/dnssec.c
@ -759,177 +759,6 @@ syncdelete(dst_key_t *key, isc_stdtime_t now) {
|
||||
#define is_zone_key(key) \
|
||||
((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE)
|
||||
|
||||
isc_result_t
|
||||
dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
|
||||
const dns_name_t *name, const char *directory,
|
||||
isc_stdtime_t now, isc_mem_t *mctx,
|
||||
unsigned int maxkeys, dst_key_t **keys,
|
||||
unsigned int *nkeys) {
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
isc_result_t result;
|
||||
dst_key_t *pubkey = NULL;
|
||||
unsigned int count = 0;
|
||||
|
||||
REQUIRE(nkeys != NULL);
|
||||
REQUIRE(keys != NULL);
|
||||
|
||||
*nkeys = 0;
|
||||
memset(keys, 0, sizeof(*keys) * maxkeys);
|
||||
dns_rdataset_init(&rdataset);
|
||||
RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
|
||||
&rdataset, NULL));
|
||||
RETERR(dns_rdataset_first(&rdataset));
|
||||
while (result == ISC_R_SUCCESS && count < maxkeys) {
|
||||
pubkey = NULL;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
|
||||
dst_key_setttl(pubkey, rdataset.ttl);
|
||||
|
||||
if (!is_zone_key(pubkey) ||
|
||||
(dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
|
||||
{
|
||||
goto next;
|
||||
}
|
||||
/* Corrupted .key file? */
|
||||
if (!dns_name_equal(name, dst_key_name(pubkey))) {
|
||||
goto next;
|
||||
}
|
||||
keys[count] = NULL;
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(pubkey), dst_key_id(pubkey),
|
||||
dst_key_alg(pubkey),
|
||||
DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE,
|
||||
directory, mctx, &keys[count]);
|
||||
|
||||
/*
|
||||
* If the key was revoked and the private file
|
||||
* doesn't exist, maybe it was revoked internally
|
||||
* by named. Try loading the unrevoked version.
|
||||
*/
|
||||
if (result == ISC_R_FILENOTFOUND) {
|
||||
uint32_t flags;
|
||||
flags = dst_key_flags(pubkey);
|
||||
if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
|
||||
dst_key_setflags(pubkey,
|
||||
flags & ~DNS_KEYFLAG_REVOKE);
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(pubkey),
|
||||
dst_key_id(pubkey), dst_key_alg(pubkey),
|
||||
DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE,
|
||||
directory, mctx, &keys[count]);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
dst_key_pubcompare(pubkey, keys[count],
|
||||
false))
|
||||
{
|
||||
dst_key_setflags(keys[count], flags);
|
||||
}
|
||||
dst_key_setflags(pubkey, flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
char filename[DNS_NAME_FORMATSIZE +
|
||||
DNS_SECALG_FORMATSIZE +
|
||||
sizeof("key file for //65535")];
|
||||
isc_result_t result2;
|
||||
isc_buffer_t buf;
|
||||
|
||||
isc_buffer_init(&buf, filename, NAME_MAX);
|
||||
result2 = dst_key_getfilename(
|
||||
dst_key_name(pubkey), dst_key_id(pubkey),
|
||||
dst_key_alg(pubkey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
directory, mctx, &buf);
|
||||
if (result2 != ISC_R_SUCCESS) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
|
||||
dns_name_format(dst_key_name(pubkey), namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_secalg_format(dst_key_alg(pubkey), algbuf,
|
||||
sizeof(algbuf));
|
||||
snprintf(filename, sizeof(filename) - 1,
|
||||
"key file for %s/%s/%d", namebuf,
|
||||
algbuf, dst_key_id(pubkey));
|
||||
}
|
||||
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
|
||||
"dns_dnssec_findzonekeys: error "
|
||||
"reading %s: %s",
|
||||
filename, isc_result_totext(result));
|
||||
}
|
||||
|
||||
if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
|
||||
keys[count] = pubkey;
|
||||
pubkey = NULL;
|
||||
count++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a key is marked inactive, skip it
|
||||
*/
|
||||
if (!dns_dnssec_keyactive(keys[count], now)) {
|
||||
dst_key_setinactive(pubkey, true);
|
||||
dst_key_free(&keys[count]);
|
||||
keys[count] = pubkey;
|
||||
pubkey = NULL;
|
||||
count++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whatever the key's default TTL may have
|
||||
* been, the rdataset TTL takes priority.
|
||||
*/
|
||||
dst_key_setttl(keys[count], rdataset.ttl);
|
||||
|
||||
if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
|
||||
/* We should never get here. */
|
||||
dst_key_free(&keys[count]);
|
||||
goto next;
|
||||
}
|
||||
count++;
|
||||
next:
|
||||
if (pubkey != NULL) {
|
||||
dst_key_free(&pubkey);
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
result = dns_rdataset_next(&rdataset);
|
||||
}
|
||||
if (result != ISC_R_NOMORE) {
|
||||
goto failure;
|
||||
}
|
||||
if (count == 0) {
|
||||
result = ISC_R_NOTFOUND;
|
||||
} else {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
failure:
|
||||
if (dns_rdataset_isassociated(&rdataset)) {
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
}
|
||||
if (pubkey != NULL) {
|
||||
dst_key_free(&pubkey);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
while (count > 0) {
|
||||
dst_key_free(&keys[--count]);
|
||||
}
|
||||
}
|
||||
*nkeys = count;
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
|
||||
dns_rdata_sig_t sig; /* SIG(0) */
|
||||
@ -1396,32 +1225,18 @@ dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
|
||||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
* Get a list of DNSSEC keys from the key repository.
|
||||
*/
|
||||
isc_result_t
|
||||
dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
|
||||
isc_stdtime_t now, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keylist) {
|
||||
static isc_result_t
|
||||
findmatchingkeys(const char *directory, char *namebuf, unsigned int len,
|
||||
isc_mem_t *mctx, isc_stdtime_t now,
|
||||
dns_dnsseckeylist_t *list) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
bool dir_open = false;
|
||||
dns_dnsseckeylist_t list;
|
||||
isc_dir_t dir;
|
||||
bool dir_open = false;
|
||||
unsigned int i, alg;
|
||||
dns_dnsseckey_t *key = NULL;
|
||||
dst_key_t *dstkey = NULL;
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
isc_buffer_t b;
|
||||
unsigned int len, i, alg;
|
||||
|
||||
REQUIRE(keylist != NULL);
|
||||
ISC_LIST_INIT(list);
|
||||
isc_dir_init(&dir);
|
||||
|
||||
isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
|
||||
RETERR(dns_name_tofilenametext(origin, false, &b));
|
||||
len = isc_buffer_usedlength(&b);
|
||||
namebuf[len] = '\0';
|
||||
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
@ -1508,11 +1323,70 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
|
||||
if (key->legacy) {
|
||||
dns_dnsseckey_destroy(mctx, &key);
|
||||
} else {
|
||||
ISC_LIST_APPEND(list, key, link);
|
||||
ISC_LIST_APPEND(*list, key, link);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
failure:
|
||||
if (dir_open) {
|
||||
isc_dir_close(&dir);
|
||||
}
|
||||
if (dstkey != NULL) {
|
||||
dst_key_free(&dstkey);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Get a list of DNSSEC keys from the key repository.
|
||||
*/
|
||||
isc_result_t
|
||||
dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
|
||||
const char *keydir, dns_keystorelist_t *keystores,
|
||||
isc_stdtime_t now, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keylist) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_dnsseckeylist_t list;
|
||||
dns_dnsseckey_t *key = NULL;
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
isc_buffer_t b;
|
||||
unsigned int len;
|
||||
|
||||
REQUIRE(keylist != NULL);
|
||||
ISC_LIST_INIT(list);
|
||||
|
||||
isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
|
||||
RETERR(dns_name_tofilenametext(origin, false, &b));
|
||||
len = isc_buffer_usedlength(&b);
|
||||
namebuf[len] = '\0';
|
||||
|
||||
if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
|
||||
(strcmp(dns_kasp_getname(kasp), "insecure") == 0))
|
||||
{
|
||||
RETERR(findmatchingkeys(keydir, namebuf, len, mctx, now,
|
||||
&list));
|
||||
} else if (keystores != NULL) {
|
||||
for (dns_keystore_t *keystore = ISC_LIST_HEAD(*keystores);
|
||||
keystore != NULL; keystore = ISC_LIST_NEXT(keystore, link))
|
||||
{
|
||||
for (dns_kasp_key_t *kkey =
|
||||
ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
if (dns_kasp_key_keystore(kkey) == keystore) {
|
||||
const char *directory =
|
||||
dns_keystore_directory(keystore,
|
||||
keydir);
|
||||
RETERR(findmatchingkeys(
|
||||
directory, namebuf, len, mctx,
|
||||
now, &list));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ISC_LIST_EMPTY(list)) {
|
||||
result = ISC_R_SUCCESS;
|
||||
ISC_LIST_APPENDLIST(*keylist, list, link);
|
||||
@ -1521,19 +1395,12 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
|
||||
}
|
||||
|
||||
failure:
|
||||
if (dir_open) {
|
||||
isc_dir_close(&dir);
|
||||
}
|
||||
INSIST(key == NULL);
|
||||
while ((key = ISC_LIST_HEAD(list)) != NULL) {
|
||||
ISC_LIST_UNLINK(list, key, link);
|
||||
INSIST(key->key != NULL);
|
||||
dst_key_free(&key->key);
|
||||
dns_dnsseckey_destroy(mctx, &key);
|
||||
}
|
||||
if (dstkey != NULL) {
|
||||
dst_key_free(&dstkey);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
@ -1641,15 +1508,46 @@ mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
keyfromfile(dns_kasp_t *kasp, const char *keydir, dst_key_t *key, int type,
|
||||
isc_mem_t *mctx, dst_key_t **savekey) {
|
||||
const char *directory = keydir;
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
|
||||
if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
|
||||
(strcmp(dns_kasp_getname(kasp), "insecure") == 0))
|
||||
{
|
||||
result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
|
||||
dst_key_alg(key), type, directory,
|
||||
mctx, savekey);
|
||||
} else {
|
||||
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
dns_keystore_t *ks = dns_kasp_key_keystore(kkey);
|
||||
directory = dns_keystore_directory(ks, keydir);
|
||||
result = dst_key_fromfile(dst_key_name(key),
|
||||
dst_key_id(key),
|
||||
dst_key_alg(key), type,
|
||||
directory, mctx, savekey);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
|
||||
*/
|
||||
isc_result_t
|
||||
dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
|
||||
isc_mem_t *mctx, dns_rdataset_t *keyset,
|
||||
dns_rdataset_t *keysigs, dns_rdataset_t *soasigs,
|
||||
bool savekeys, bool publickey,
|
||||
dns_dnsseckeylist_t *keylist) {
|
||||
dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp,
|
||||
const char *directory, isc_mem_t *mctx,
|
||||
dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
|
||||
dns_rdataset_t *soasigs, bool savekeys,
|
||||
bool publickey, dns_dnsseckeylist_t *keylist) {
|
||||
dns_rdataset_t keys;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dst_key_t *dnskey = NULL, *pubkey = NULL, *privkey = NULL;
|
||||
@ -1695,21 +1593,19 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
|
||||
}
|
||||
|
||||
/* Try to read the public key. */
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(dnskey), dst_key_id(dnskey),
|
||||
dst_key_alg(dnskey), (DST_TYPE_PUBLIC | DST_TYPE_STATE),
|
||||
directory, mctx, &pubkey);
|
||||
result = keyfromfile(kasp, directory, dnskey,
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_STATE), mctx,
|
||||
&pubkey);
|
||||
if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
RETERR(result);
|
||||
|
||||
/* Now read the private key. */
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(dnskey), dst_key_id(dnskey),
|
||||
dst_key_alg(dnskey),
|
||||
result = keyfromfile(
|
||||
kasp, directory, dnskey,
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE),
|
||||
directory, mctx, &privkey);
|
||||
mctx, &privkey);
|
||||
|
||||
/*
|
||||
* If the key was revoked and the private file
|
||||
@ -1722,12 +1618,11 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
|
||||
if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
|
||||
dst_key_setflags(dnskey,
|
||||
flags & ~DNS_KEYFLAG_REVOKE);
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(dnskey),
|
||||
dst_key_id(dnskey), dst_key_alg(dnskey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
directory, mctx, &privkey);
|
||||
result = keyfromfile(kasp, directory, dnskey,
|
||||
(DST_TYPE_PUBLIC |
|
||||
DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
mctx, &privkey);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
dst_key_pubcompare(dnskey, privkey, false))
|
||||
{
|
||||
@ -1750,7 +1645,7 @@ dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
|
||||
dst_key_alg(dnskey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
directory, mctx, &buf);
|
||||
NULL, mctx, &buf);
|
||||
if (result2 != ISC_R_SUCCESS) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
|
@ -691,6 +691,10 @@ dst_key_fromnamedfile(const char *filename, const char *dirname, int type,
|
||||
}
|
||||
|
||||
key->modified = false;
|
||||
|
||||
if (dirname != NULL) {
|
||||
key->directory = isc_mem_strdup(mctx, dirname);
|
||||
}
|
||||
*keyp = key;
|
||||
key = NULL;
|
||||
|
||||
@ -1027,8 +1031,8 @@ dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags,
|
||||
isc_result_t
|
||||
dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits,
|
||||
unsigned int param, unsigned int flags, unsigned int protocol,
|
||||
dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp,
|
||||
void (*callback)(int)) {
|
||||
dns_rdataclass_t rdclass, const char *label, isc_mem_t *mctx,
|
||||
dst_key_t **keyp, void (*callback)(int)) {
|
||||
dst_key_t *key;
|
||||
isc_result_t ret;
|
||||
|
||||
@ -1042,6 +1046,10 @@ dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits,
|
||||
key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 0,
|
||||
mctx);
|
||||
|
||||
if (label != NULL) {
|
||||
key->label = isc_mem_strdup(mctx, label);
|
||||
}
|
||||
|
||||
if (bits == 0) { /*%< NULL KEY */
|
||||
key->key_flags |= DNS_KEYTYPE_NOKEY;
|
||||
*keyp = key;
|
||||
@ -1391,6 +1399,9 @@ dst_key_free(dst_key_t **keyp) {
|
||||
INSIST(key->func->destroy != NULL);
|
||||
key->func->destroy(key);
|
||||
}
|
||||
if (key->directory != NULL) {
|
||||
isc_mem_free(mctx, key->directory);
|
||||
}
|
||||
if (key->engine != NULL) {
|
||||
isc_mem_free(mctx, key->engine);
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ struct dst_key {
|
||||
dns_rdataclass_t key_class; /*%< class of the key record */
|
||||
dns_ttl_t key_ttl; /*%< default/initial dnskey ttl */
|
||||
isc_mem_t *mctx; /*%< memory context */
|
||||
char *directory; /*%< key directory */
|
||||
char *engine; /*%< engine name (HSM) */
|
||||
char *label; /*%< engine label (HSM) */
|
||||
union {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <isc/stdtime.h>
|
||||
|
||||
#include <dns/diff.h>
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
@ -176,20 +177,6 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
|
||||
*\li DST_R_*
|
||||
*/
|
||||
|
||||
/*@{*/
|
||||
isc_result_t
|
||||
dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
|
||||
const dns_name_t *name, const char *directory,
|
||||
isc_stdtime_t now, isc_mem_t *mctx,
|
||||
unsigned int maxkeys, dst_key_t **keys,
|
||||
unsigned int *nkeys);
|
||||
|
||||
/*%<
|
||||
* Finds a set of zone keys.
|
||||
* XXX temporary - this should be handled in dns_zone_t.
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
bool
|
||||
dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now);
|
||||
/*%<
|
||||
@ -295,11 +282,15 @@ dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now);
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
|
||||
dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
|
||||
const char *keydir, dns_keystorelist_t *keystores,
|
||||
isc_stdtime_t now, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keylist);
|
||||
/*%<
|
||||
* Search 'directory' for K* key files matching the name in 'origin'.
|
||||
* Search for K* key files matching the name in 'origin'. If 'kasp' is not
|
||||
* NULL, search in the directories used in 'keystores'. Otherwise search in the
|
||||
* key-directory 'keydir'.
|
||||
*
|
||||
* Append all such keys, along with use hints gleaned from their
|
||||
* metadata, onto 'keylist'. Skip any unsupported algorithms.
|
||||
*
|
||||
@ -318,17 +309,18 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
|
||||
isc_mem_t *mctx, dns_rdataset_t *keyset,
|
||||
dns_rdataset_t *keysigs, dns_rdataset_t *soasigs,
|
||||
bool savekeys, bool publickey,
|
||||
dns_dnsseckeylist_t *keylist);
|
||||
dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp,
|
||||
const char *directory, isc_mem_t *mctx,
|
||||
dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
|
||||
dns_rdataset_t *soasigs, bool savekeys,
|
||||
bool publickey, dns_dnsseckeylist_t *keylist);
|
||||
/*%<
|
||||
* Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
|
||||
* Omit duplicates. If 'publickey' is false, search 'directory' for
|
||||
* matching key files, and load the private keys that go with
|
||||
* the public ones. If 'savekeys' is true, mark the keys so
|
||||
* they will not be deleted or inactivated regardless of metadata.
|
||||
* Omit duplicates. If 'publickey' is false, search the key stores referenced
|
||||
* in 'kasp', or 'directory' if 'kasp' is NULL, for matching key files, and
|
||||
* load the private keys that go with the public ones. If 'savekeys' is true,
|
||||
* mark the keys so they will not be deleted or inactivated regardless of
|
||||
* metadata.
|
||||
*
|
||||
* 'keysigs' and 'soasigs', if not NULL and associated, contain the
|
||||
* RRSIGS for the DNSKEY and SOA records respectively and are used to mark
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/refcount.h>
|
||||
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
@ -51,10 +52,11 @@ struct dns_kasp_key {
|
||||
ISC_LINK(struct dns_kasp_key) link;
|
||||
|
||||
/* Configuration */
|
||||
uint32_t lifetime;
|
||||
uint8_t algorithm;
|
||||
int length;
|
||||
uint8_t role;
|
||||
dns_keystore_t *keystore;
|
||||
uint32_t lifetime;
|
||||
uint8_t algorithm;
|
||||
int length;
|
||||
uint8_t role;
|
||||
};
|
||||
|
||||
struct dns_kasp_nsec3param {
|
||||
@ -643,6 +645,21 @@ dns_kasp_key_lifetime(dns_kasp_key_t *key);
|
||||
*
|
||||
*/
|
||||
|
||||
dns_keystore_t *
|
||||
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);
|
||||
/*%<
|
||||
|
@ -26,13 +26,13 @@ ISC_LANG_BEGINDECLS
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
const char *directory, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys,
|
||||
isc_mem_t *mctx, dns_dnsseckeylist_t *keyring,
|
||||
dns_dnsseckeylist_t *dnskeys, const char *keydir,
|
||||
dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime);
|
||||
/*%<
|
||||
* Manage keys in 'keyring' and update timing data according to 'kasp' policy.
|
||||
* Create new keys for 'origin' if necessary in 'directory'. Append all such
|
||||
* keys, along with use hints gleaned from their metadata, onto 'keyring'.
|
||||
* Create new keys for 'origin' if necessary. Append all such keys, along
|
||||
* with use hints gleaned from their metadata, onto 'keyring'.
|
||||
*
|
||||
* Update key states and store changes back to disk. Store when to run next
|
||||
* in 'nexttime'.
|
||||
@ -54,13 +54,11 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, isc_stdtime_t when,
|
||||
bool dspublish);
|
||||
isc_stdtime_t now, isc_stdtime_t when, bool dspublish);
|
||||
isc_result_t
|
||||
dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now,
|
||||
isc_stdtime_t when, bool dspublish, dns_keytag_t id,
|
||||
unsigned int algorithm);
|
||||
isc_stdtime_t now, isc_stdtime_t when, bool dspublish,
|
||||
dns_keytag_t id, unsigned int algorithm);
|
||||
/*%<
|
||||
* Check DS for one key in 'keyring'. The key must have the KSK role.
|
||||
* If 'dspublish' is set to true, set the DS Publish time to 'now'.
|
||||
@ -82,8 +80,7 @@ dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now,
|
||||
isc_stdtime_t when, dns_keytag_t id,
|
||||
isc_stdtime_t now, isc_stdtime_t when, dns_keytag_t id,
|
||||
unsigned int algorithm);
|
||||
/*%<
|
||||
* Rollover key with given 'id'. If the 'algorithm' is non-zero, it must
|
||||
|
220
lib/dns/include/dns/keystore.h
Normal file
220
lib/dns/include/dns/keystore.h
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*****
|
||||
***** Module Info
|
||||
*****/
|
||||
|
||||
/*! \file dns/keystore.h
|
||||
* \brief
|
||||
* DNSSEC Key Store
|
||||
*
|
||||
* A key store defines where to store DNSSEC keys.
|
||||
*/
|
||||
|
||||
/* Add -DDNS_KEYSTORE_TRACE=1 to CFLAGS for detailed reference tracing */
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/refcount.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
/* Key store */
|
||||
struct dns_keystore {
|
||||
unsigned int magic;
|
||||
isc_mem_t *mctx;
|
||||
const char *name;
|
||||
const char *engine;
|
||||
|
||||
/* Internals. */
|
||||
isc_mutex_t lock;
|
||||
|
||||
/* Locked by themselves. */
|
||||
isc_refcount_t references;
|
||||
|
||||
/* Under owner's locking control. */
|
||||
ISC_LINK(struct dns_keystore) link;
|
||||
|
||||
/* Configuration values */
|
||||
char *directory;
|
||||
char *pkcs11uri;
|
||||
};
|
||||
|
||||
#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, const char *engine,
|
||||
dns_keystore_t **kspp);
|
||||
/*%<
|
||||
* Create a key store.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*
|
||||
*\li 'name' is a valid C string.
|
||||
*
|
||||
*\li 'engine' is the name of the OpenSSL engine to use, may be NULL.
|
||||
*
|
||||
*\li kspp != NULL && *kspp == NULL
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS
|
||||
*\li #ISC_R_NOMEMORY
|
||||
*
|
||||
*\li Other errors are possible.
|
||||
*/
|
||||
|
||||
const char *
|
||||
dns_keystore_name(dns_keystore_t *keystore);
|
||||
/*%<
|
||||
* Get keystore name.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li name of 'keystore'.
|
||||
*/
|
||||
|
||||
const char *
|
||||
dns_keystore_engine(dns_keystore_t *keystore);
|
||||
/*%<
|
||||
* Get keystore engine.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li engine of 'keystore'. May be NULL.
|
||||
*/
|
||||
|
||||
const char *
|
||||
dns_keystore_directory(dns_keystore_t *keystore, const char *keydir);
|
||||
/*%<
|
||||
* Get keystore directory. If 'keystore' is NULL or 'keystore->directory' is
|
||||
*NULL, return 'keydir'.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li directory of 'keystore'.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_keystore_setdirectory(dns_keystore_t *keystore, const char *dir);
|
||||
/*%<
|
||||
* Set keystore directory.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
*/
|
||||
|
||||
const char *
|
||||
dns_keystore_pkcs11uri(dns_keystore_t *keystore);
|
||||
/*%<
|
||||
* Get keystore PKCS#11 URI.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li PKCS#11 URI of 'keystore'.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri);
|
||||
/*%<
|
||||
* Set keystore PKCS#11 URI.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
|
||||
const char *policy, dns_rdataclass_t rdclass,
|
||||
isc_mem_t *mctx, uint32_t alg, int size, int flags,
|
||||
dst_key_t **dstkey);
|
||||
/*%<
|
||||
* Create a DNSSEC key pair. Set keystore PKCS#11 URI.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'keystore' is a valid keystore.
|
||||
*
|
||||
*\li 'origin' is a valid DNS owner name.
|
||||
*
|
||||
*\li 'policy' is the name of the DNSSEC policy.
|
||||
*
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*
|
||||
*\li 'dstkey' is not NULL and '*dstkey' is NULL.
|
||||
*
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
|
||||
dns_keystore_t **kspp);
|
||||
/*%<
|
||||
* Search for a keystore with name 'name' in 'list'.
|
||||
* If found, '*kspp' is (strongly) attached to it.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'kspp' points to a NULL dns_keystore_t *.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS A matching keystore was found.
|
||||
*\li #ISC_R_NOTFOUND No matching keystore was found.
|
||||
*/
|
||||
|
||||
#ifdef DNS_KEYSTORE_TRACE
|
||||
/* Compatibility macros */
|
||||
#define dns_keystore_attach(ks, ksp) \
|
||||
dns_keystore__attach(ks, ksp, __func__, __FILE__, __LINE__)
|
||||
#define dns_keystore_detach(ksp) \
|
||||
dns_keystore__detach(ksp, __func__, __FILE__, __LINE__)
|
||||
#define dns_keystore_ref(ptr) \
|
||||
dns_keystore__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_keystore_unref(ptr) \
|
||||
dns_keystore__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
|
||||
ISC_REFCOUNT_TRACE_DECL(dns_keystore);
|
||||
#else
|
||||
ISC_REFCOUNT_DECL(dns_keystore);
|
||||
#endif /* DNS_KEYSTORE_TRACE */
|
||||
|
||||
ISC_LANG_ENDDECLS
|
@ -106,8 +106,10 @@ typedef struct dns_kasp_nsec3param dns_kasp_nsec3param_t;
|
||||
typedef uint16_t dns_keyflags_t;
|
||||
typedef struct dns_keynode dns_keynode_t;
|
||||
typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t;
|
||||
typedef struct dns_keytable dns_keytable_t;
|
||||
typedef uint16_t dns_keytag_t;
|
||||
typedef struct dns_keytable dns_keytable_t;
|
||||
typedef uint16_t dns_keytag_t;
|
||||
typedef struct dns_keystore dns_keystore_t;
|
||||
typedef ISC_LIST(dns_keystore_t) dns_keystorelist_t;
|
||||
typedef struct dns_loadctx dns_loadctx_t;
|
||||
typedef struct dns_loadmgr dns_loadmgr_t;
|
||||
typedef struct dns_masterrawheader dns_masterrawheader_t;
|
||||
|
@ -1595,7 +1595,7 @@ isc_result_t
|
||||
dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory);
|
||||
/*%<
|
||||
* Sets the name of the directory where private keys used for
|
||||
* online signing of dynamic zones are found.
|
||||
* online signing or dynamic zones are found.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
@ -1618,10 +1618,33 @@ dns_zone_getkeydirectory(dns_zone_t *zone);
|
||||
* Pointer to null-terminated file name, or NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_zone_setkeystores(dns_zone_t *zone, dns_keystorelist_t *keystores);
|
||||
/*%<
|
||||
* Sets the keystore list where private keys used for
|
||||
* online signing or dynamic zones are found.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*/
|
||||
|
||||
dns_keystorelist_t *
|
||||
dns_zone_getkeystores(dns_zone_t *zone);
|
||||
/*%<
|
||||
* Gets the keystore list where private keys used for
|
||||
* online signing or dynamic zones are found.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the keystore list, or NULL.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
isc_stdtime_t now, dns_dnsseckeylist_t *keys);
|
||||
/*%
|
||||
/*%<
|
||||
* Find DNSSEC keys used for signing with dnssec-policy. Load these keys
|
||||
* into 'keys'.
|
||||
*
|
||||
@ -1634,6 +1657,26 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
*\li Error
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys,
|
||||
dst_key_t **keys, unsigned int *nkeys);
|
||||
/*%<
|
||||
* Finds a set of zone keys. Searches in the applicable key stores for the
|
||||
* given 'zone' if there is a dnssec-policy attached, otherwise it looks up
|
||||
* the keys in the zone's key-directory. The found keys are loaded into 'keys'.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'zone' to be a valid initialised zone.
|
||||
*\li 'mctx' is not NULL.
|
||||
*\li 'keys' is not NULL and has enough space form 'nkeys' keys.
|
||||
*\li 'nkeys' is not NULL.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*\li Error
|
||||
*/
|
||||
|
||||
void
|
||||
dns_zonemgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *netmgr,
|
||||
dns_zonemgr_t **zmgrp);
|
||||
|
@ -629,8 +629,8 @@ dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags,
|
||||
isc_result_t
|
||||
dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits,
|
||||
unsigned int param, unsigned int flags, unsigned int protocol,
|
||||
dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp,
|
||||
void (*callback)(int));
|
||||
dns_rdataclass_t rdclass, const char *label, isc_mem_t *mctx,
|
||||
dst_key_t **keyp, void (*callback)(int));
|
||||
|
||||
/*%<
|
||||
* Generate a DST key (or keypair) with the supplied parameters. The
|
||||
@ -765,6 +765,9 @@ dst_key_rid(const dst_key_t *key);
|
||||
dns_rdataclass_t
|
||||
dst_key_class(const dst_key_t *key);
|
||||
|
||||
const char *
|
||||
dst_key_directory(const dst_key_t *key);
|
||||
|
||||
bool
|
||||
dst_key_isprivate(const dst_key_t *key);
|
||||
|
||||
@ -1233,6 +1236,15 @@ dst_key_copy_metadata(dst_key_t *to, dst_key_t *from);
|
||||
* 'to' and 'from' to be valid.
|
||||
*/
|
||||
|
||||
void
|
||||
dst_key_setdirectory(dst_key_t *key, const char *dir);
|
||||
/*%<
|
||||
* Set the directory where to store key files for this key.
|
||||
*
|
||||
* Requires:
|
||||
* 'key' to be valid.
|
||||
*/
|
||||
|
||||
const char *
|
||||
dst_hmac_algorithm_totext(dst_algorithm_t alg);
|
||||
/*$<
|
||||
|
@ -385,21 +385,20 @@ dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key) {
|
||||
|
||||
isc_result_t
|
||||
dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp) {
|
||||
dns_kasp_key_t *key;
|
||||
dns_kasp_key_t *key = NULL;
|
||||
dns_kasp_key_t k = { .length = -1 };
|
||||
|
||||
REQUIRE(DNS_KASP_VALID(kasp));
|
||||
REQUIRE(keyp != NULL && *keyp == NULL);
|
||||
|
||||
key = isc_mem_get(kasp->mctx, sizeof(*key));
|
||||
*key = k;
|
||||
|
||||
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);
|
||||
}
|
||||
@ -408,6 +407,9 @@ void
|
||||
dns_kasp_key_destroy(dns_kasp_key_t *key) {
|
||||
REQUIRE(key != NULL);
|
||||
|
||||
if (key->keystore != NULL) {
|
||||
dns_keystore_detach(&key->keystore);
|
||||
}
|
||||
isc_mem_putanddetach(&key->mctx, key, sizeof(*key));
|
||||
}
|
||||
|
||||
@ -469,6 +471,13 @@ dns_kasp_key_lifetime(dns_kasp_key_t *key) {
|
||||
return (key->lifetime);
|
||||
}
|
||||
|
||||
dns_keystore_t *
|
||||
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);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
@ -123,6 +124,12 @@ dst_key_class(const dst_key_t *key) {
|
||||
return (key->key_class);
|
||||
}
|
||||
|
||||
const char *
|
||||
dst_key_directory(const dst_key_t *key) {
|
||||
REQUIRE(VALID_KEY(key));
|
||||
return (key->directory);
|
||||
}
|
||||
|
||||
bool
|
||||
dst_key_iszonekey(const dst_key_t *key) {
|
||||
REQUIRE(VALID_KEY(key));
|
||||
@ -247,4 +254,12 @@ dst_key_getttl(const dst_key_t *key) {
|
||||
return (key->key_ttl);
|
||||
}
|
||||
|
||||
void
|
||||
dst_key_setdirectory(dst_key_t *key, const char *dir) {
|
||||
if (key->directory != NULL) {
|
||||
isc_mem_free(key->mctx, key->directory);
|
||||
}
|
||||
key->directory = isc_mem_strdup(key->mctx, dir);
|
||||
}
|
||||
|
||||
/*! \file */
|
||||
|
152
lib/dns/keymgr.c
152
lib/dns/keymgr.c
@ -23,6 +23,7 @@
|
||||
#include <isc/mem.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/time.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/dnssec.h>
|
||||
@ -443,24 +444,32 @@ keymgr_keyid_conflict(dst_key_t *newkey, dns_dnsseckeylist_t *keys) {
|
||||
*/
|
||||
static isc_result_t
|
||||
keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
|
||||
dns_rdataclass_t rdclass, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keylist, dns_dnsseckeylist_t *newkeys,
|
||||
dst_key_t **dst_key) {
|
||||
bool conflict = false;
|
||||
int keyflags = DNS_KEYOWNER_ZONE;
|
||||
dns_kasp_t *kasp, dns_rdataclass_t rdclass, isc_mem_t *mctx,
|
||||
const char *keydir, dns_dnsseckeylist_t *keylist,
|
||||
dns_dnsseckeylist_t *newkeys, dst_key_t **dst_key) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
bool conflict = false;
|
||||
int flags = DNS_KEYOWNER_ZONE;
|
||||
dst_key_t *newkey = NULL;
|
||||
uint32_t alg = dns_kasp_key_algorithm(kkey);
|
||||
dns_keystore_t *keystore = dns_kasp_key_keystore(kkey);
|
||||
const char *dir = NULL;
|
||||
int size = dns_kasp_key_size(kkey);
|
||||
|
||||
if (dns_kasp_key_ksk(kkey)) {
|
||||
flags |= DNS_KEYFLAG_KSK;
|
||||
}
|
||||
|
||||
do {
|
||||
uint32_t algo = dns_kasp_key_algorithm(kkey);
|
||||
int size = dns_kasp_key_size(kkey);
|
||||
|
||||
if (dns_kasp_key_ksk(kkey)) {
|
||||
keyflags |= DNS_KEYFLAG_KSK;
|
||||
if (keystore == NULL) {
|
||||
RETERR(dst_key_generate(origin, alg, size, 0, flags,
|
||||
DNS_KEYPROTO_DNSSEC, rdclass,
|
||||
NULL, mctx, &newkey, NULL));
|
||||
} else {
|
||||
RETERR(dns_keystore_keygen(
|
||||
keystore, origin, dns_kasp_getname(kasp),
|
||||
rdclass, mctx, alg, size, flags, &newkey));
|
||||
}
|
||||
RETERR(dst_key_generate(origin, algo, size, 0, keyflags,
|
||||
DNS_KEYPROTO_DNSSEC, rdclass, mctx,
|
||||
&newkey, NULL));
|
||||
|
||||
/* Key collision? */
|
||||
conflict = keymgr_keyid_conflict(newkey, keylist);
|
||||
@ -481,6 +490,11 @@ keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
|
||||
dst_key_setnum(newkey, DST_NUM_LIFETIME, dns_kasp_key_lifetime(kkey));
|
||||
dst_key_setbool(newkey, DST_BOOL_KSK, dns_kasp_key_ksk(kkey));
|
||||
dst_key_setbool(newkey, DST_BOOL_ZSK, dns_kasp_key_zsk(kkey));
|
||||
|
||||
dir = dns_keystore_directory(keystore, keydir);
|
||||
if (dir != NULL) {
|
||||
dst_key_setdirectory(newkey, dir);
|
||||
}
|
||||
*dst_key = newkey;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
@ -1671,8 +1685,8 @@ static isc_result_t
|
||||
keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
||||
dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *newkeys,
|
||||
const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
dns_kasp_t *kasp, uint32_t lifetime, bool rollover,
|
||||
isc_stdtime_t now, isc_stdtime_t *nexttime,
|
||||
dns_kasp_t *kasp, const char *keydir, uint32_t lifetime,
|
||||
bool rollover, isc_stdtime_t now, isc_stdtime_t *nexttime,
|
||||
isc_mem_t *mctx) {
|
||||
char keystr[DST_KEY_FORMATSIZE];
|
||||
isc_stdtime_t retire = 0, active = 0, prepub = 0;
|
||||
@ -1790,9 +1804,9 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
||||
bool csk = (dns_kasp_key_ksk(kaspkey) &&
|
||||
dns_kasp_key_zsk(kaspkey));
|
||||
|
||||
isc_result_t result = keymgr_createkey(kaspkey, origin, rdclass,
|
||||
mctx, keyring, newkeys,
|
||||
&dst_key);
|
||||
isc_result_t result =
|
||||
keymgr_createkey(kaspkey, origin, kasp, rdclass, mctx,
|
||||
keydir, keyring, newkeys, &dst_key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
@ -1936,7 +1950,7 @@ keymgr_key_may_be_purged(dst_key_t *key, uint32_t after, isc_stdtime_t now) {
|
||||
}
|
||||
|
||||
static void
|
||||
keymgr_purge_keyfile(dst_key_t *key, const char *dir, int type) {
|
||||
keymgr_purge_keyfile(dst_key_t *key, int type) {
|
||||
isc_result_t ret;
|
||||
isc_buffer_t fileb;
|
||||
char filename[NAME_MAX];
|
||||
@ -1945,7 +1959,7 @@ keymgr_purge_keyfile(dst_key_t *key, const char *dir, int type) {
|
||||
* Make the filename.
|
||||
*/
|
||||
isc_buffer_init(&fileb, filename, sizeof(filename));
|
||||
ret = dst_key_buildfilename(key, type, dir, &fileb);
|
||||
ret = dst_key_buildfilename(key, type, dst_key_directory(key), &fileb);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
char keystr[DST_KEY_FORMATSIZE];
|
||||
dst_key_format(key, keystr, sizeof(keystr));
|
||||
@ -1975,33 +1989,25 @@ keymgr_purge_keyfile(dst_key_t *key, const char *dir, int type) {
|
||||
*/
|
||||
isc_result_t
|
||||
dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
const char *directory, isc_mem_t *mctx,
|
||||
dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys,
|
||||
isc_mem_t *mctx, dns_dnsseckeylist_t *keyring,
|
||||
dns_dnsseckeylist_t *dnskeys, const char *keydir,
|
||||
dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_dnsseckeylist_t newkeys;
|
||||
dns_kasp_key_t *kkey;
|
||||
dns_dnsseckey_t *newkey = NULL;
|
||||
isc_dir_t dir;
|
||||
bool dir_open = false;
|
||||
bool secure_to_insecure = false;
|
||||
int numkeys = 0;
|
||||
int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
|
||||
char keystr[DST_KEY_FORMATSIZE];
|
||||
|
||||
REQUIRE(DNS_KASP_VALID(kasp));
|
||||
REQUIRE(dns_name_isvalid(origin));
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(keyring != NULL);
|
||||
REQUIRE(DNS_KASP_VALID(kasp));
|
||||
|
||||
ISC_LIST_INIT(newkeys);
|
||||
|
||||
isc_dir_init(&dir);
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
|
||||
RETERR(isc_dir_open(&dir, directory));
|
||||
dir_open = true;
|
||||
|
||||
*nexttime = 0;
|
||||
|
||||
/* Debug logging: what keys are available in the keyring? */
|
||||
@ -2076,13 +2082,9 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
dns_kasp_getname(kasp));
|
||||
|
||||
keymgr_purge_keyfile(dkey->key, directory,
|
||||
DST_TYPE_PUBLIC);
|
||||
keymgr_purge_keyfile(dkey->key, directory,
|
||||
DST_TYPE_PRIVATE);
|
||||
keymgr_purge_keyfile(dkey->key, directory,
|
||||
DST_TYPE_STATE);
|
||||
|
||||
keymgr_purge_keyfile(dkey->key, DST_TYPE_PUBLIC);
|
||||
keymgr_purge_keyfile(dkey->key, DST_TYPE_PRIVATE);
|
||||
keymgr_purge_keyfile(dkey->key, DST_TYPE_STATE);
|
||||
dkey->purge = true;
|
||||
}
|
||||
}
|
||||
@ -2191,9 +2193,10 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
}
|
||||
|
||||
/* See if this key requires a rollover. */
|
||||
RETERR(keymgr_key_rollover(
|
||||
kkey, active_key, keyring, &newkeys, origin, rdclass,
|
||||
kasp, lifetime, rollover_allowed, now, nexttime, mctx));
|
||||
RETERR(keymgr_key_rollover(kkey, active_key, keyring, &newkeys,
|
||||
origin, rdclass, kasp, keydir,
|
||||
lifetime, rollover_allowed, now,
|
||||
nexttime, mctx));
|
||||
}
|
||||
|
||||
/* Walked all kasp key configurations. Append new keys. */
|
||||
@ -2220,8 +2223,25 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
modified = true;
|
||||
}
|
||||
if (modified && !dkey->purge) {
|
||||
const char *directory = dst_key_directory(dkey->key);
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
|
||||
dns_dnssec_get_hints(dkey, now);
|
||||
RETERR(dst_key_tofile(dkey->key, options, directory));
|
||||
dst_key_setmodified(dkey->key, false);
|
||||
|
||||
if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
|
||||
continue;
|
||||
}
|
||||
dst_key_format(dkey->key, keystr, sizeof(keystr));
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(3),
|
||||
"keymgr: DNSKEY %s (%s) "
|
||||
"saved to directory %s, policy %s",
|
||||
keystr, keymgr_keyrole(dkey->key),
|
||||
directory, dns_kasp_getname(kasp));
|
||||
}
|
||||
dst_key_setmodified(dkey->key, false);
|
||||
}
|
||||
@ -2229,10 +2249,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
failure:
|
||||
if (dir_open) {
|
||||
isc_dir_close(&dir);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
while ((newkey = ISC_LIST_HEAD(newkeys)) != NULL) {
|
||||
ISC_LIST_UNLINK(newkeys, newkey, link);
|
||||
@ -2254,11 +2270,10 @@ failure:
|
||||
|
||||
static isc_result_t
|
||||
keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, isc_stdtime_t when,
|
||||
bool dspublish, dns_keytag_t id, unsigned int alg,
|
||||
bool check_id) {
|
||||
isc_stdtime_t now, isc_stdtime_t when, bool dspublish,
|
||||
dns_keytag_t id, unsigned int alg, bool check_id) {
|
||||
int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
|
||||
isc_dir_t dir;
|
||||
const char *directory = NULL;
|
||||
isc_result_t result;
|
||||
dns_dnsseckey_t *ksk_key = NULL;
|
||||
|
||||
@ -2325,40 +2340,33 @@ keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
}
|
||||
|
||||
/* Store key state and update hints. */
|
||||
isc_dir_init(&dir);
|
||||
directory = dst_key_directory(ksk_key->key);
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
result = isc_dir_open(&dir, directory);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
dns_dnssec_get_hints(ksk_key, now);
|
||||
result = dst_key_tofile(ksk_key->key, options, directory);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dst_key_setmodified(ksk_key->key, false);
|
||||
}
|
||||
isc_dir_close(&dir);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now, isc_stdtime_t when,
|
||||
bool dspublish) {
|
||||
return (keymgr_checkds(kasp, keyring, directory, now, when, dspublish,
|
||||
0, 0, false));
|
||||
isc_stdtime_t now, isc_stdtime_t when, bool dspublish) {
|
||||
return (keymgr_checkds(kasp, keyring, now, when, dspublish, 0, 0,
|
||||
false));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now,
|
||||
isc_stdtime_t when, bool dspublish, dns_keytag_t id,
|
||||
unsigned int alg) {
|
||||
return (keymgr_checkds(kasp, keyring, directory, now, when, dspublish,
|
||||
id, alg, true));
|
||||
isc_stdtime_t now, isc_stdtime_t when, bool dspublish,
|
||||
dns_keytag_t id, unsigned int alg) {
|
||||
return (keymgr_checkds(kasp, keyring, now, when, dspublish, id, alg,
|
||||
true));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2565,11 +2573,10 @@ dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
const char *directory, isc_stdtime_t now,
|
||||
isc_stdtime_t when, dns_keytag_t id,
|
||||
isc_stdtime_t now, isc_stdtime_t when, dns_keytag_t id,
|
||||
unsigned int algorithm) {
|
||||
int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
|
||||
isc_dir_t dir;
|
||||
const char *directory = NULL;
|
||||
isc_result_t result;
|
||||
dns_dnsseckey_t *key = NULL;
|
||||
isc_stdtime_t active, retire, prepub;
|
||||
@ -2628,21 +2635,16 @@ dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, (retire - active));
|
||||
|
||||
/* Store key state and update hints. */
|
||||
isc_dir_init(&dir);
|
||||
directory = dst_key_directory(key->key);
|
||||
if (directory == NULL) {
|
||||
directory = ".";
|
||||
}
|
||||
result = isc_dir_open(&dir, directory);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
dns_dnssec_get_hints(key, now);
|
||||
result = dst_key_tofile(key->key, options, directory);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dst_key_setmodified(key->key, false);
|
||||
}
|
||||
isc_dir_close(&dir);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
291
lib/dns/keystore.c
Normal file
291
lib/dns/keystore.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* 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/mem.h>
|
||||
#include <isc/time.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keyvalues.h>
|
||||
|
||||
isc_result_t
|
||||
dns_keystore_create(isc_mem_t *mctx, const char *name, const char *engine,
|
||||
dns_keystore_t **kspp) {
|
||||
dns_keystore_t *keystore;
|
||||
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(kspp != NULL && *kspp == NULL);
|
||||
|
||||
keystore = isc_mem_get(mctx, sizeof(*keystore));
|
||||
keystore->engine = engine;
|
||||
keystore->mctx = NULL;
|
||||
isc_mem_attach(mctx, &keystore->mctx);
|
||||
|
||||
keystore->name = isc_mem_strdup(mctx, name);
|
||||
isc_mutex_init(&keystore->lock);
|
||||
|
||||
isc_refcount_init(&keystore->references, 1);
|
||||
|
||||
ISC_LINK_INIT(keystore, link);
|
||||
|
||||
keystore->directory = NULL;
|
||||
keystore->pkcs11uri = NULL;
|
||||
|
||||
keystore->magic = DNS_KEYSTORE_MAGIC;
|
||||
*kspp = keystore;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dns__keystore_destroy(dns_keystore_t *keystore) {
|
||||
char *name;
|
||||
|
||||
REQUIRE(!ISC_LINK_LINKED(keystore, link));
|
||||
|
||||
isc_mutex_destroy(&keystore->lock);
|
||||
name = UNCONST(keystore->name);
|
||||
isc_mem_free(keystore->mctx, name);
|
||||
if (keystore->directory != NULL) {
|
||||
isc_mem_free(keystore->mctx, keystore->directory);
|
||||
}
|
||||
if (keystore->pkcs11uri != NULL) {
|
||||
isc_mem_free(keystore->mctx, keystore->pkcs11uri);
|
||||
}
|
||||
isc_mem_putanddetach(&keystore->mctx, keystore, sizeof(*keystore));
|
||||
}
|
||||
|
||||
#ifdef DNS_KEYSTORE_TRACE
|
||||
ISC_REFCOUNT_TRACE_IMPL(dns_keystore, dns__keystore_destroy);
|
||||
#else
|
||||
ISC_REFCOUNT_IMPL(dns_keystore, dns__keystore_destroy);
|
||||
#endif
|
||||
|
||||
const char *
|
||||
dns_keystore_name(dns_keystore_t *keystore) {
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
return (keystore->name);
|
||||
}
|
||||
|
||||
const char *
|
||||
dns_keystore_engine(dns_keystore_t *keystore) {
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
return (keystore->engine);
|
||||
}
|
||||
|
||||
const char *
|
||||
dns_keystore_directory(dns_keystore_t *keystore, const char *keydir) {
|
||||
if (keystore == NULL) {
|
||||
return (keydir);
|
||||
}
|
||||
|
||||
INSIST(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
if (keystore->directory == NULL) {
|
||||
return (keydir);
|
||||
}
|
||||
|
||||
return (keystore->directory);
|
||||
}
|
||||
|
||||
void
|
||||
dns_keystore_setdirectory(dns_keystore_t *keystore, const char *dir) {
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
if (keystore->directory != NULL) {
|
||||
isc_mem_free(keystore->mctx, keystore->directory);
|
||||
}
|
||||
keystore->directory = (dir == NULL)
|
||||
? NULL
|
||||
: isc_mem_strdup(keystore->mctx, dir);
|
||||
}
|
||||
|
||||
const char *
|
||||
dns_keystore_pkcs11uri(dns_keystore_t *keystore) {
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
return (keystore->pkcs11uri);
|
||||
}
|
||||
|
||||
void
|
||||
dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri) {
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
if (keystore->pkcs11uri != NULL) {
|
||||
isc_mem_free(keystore->mctx, keystore->pkcs11uri);
|
||||
}
|
||||
keystore->pkcs11uri = (uri == NULL)
|
||||
? NULL
|
||||
: isc_mem_strdup(keystore->mctx, uri);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
buildpkcs11label(const char *uri, const dns_name_t *zname, const char *policy,
|
||||
int flags, isc_buffer_t *buf) {
|
||||
bool ksk = ((flags & DNS_KEYFLAG_KSK) != 0);
|
||||
char timebuf[18];
|
||||
isc_time_t now = isc_time_now();
|
||||
isc_result_t result;
|
||||
dns_fixedname_t fname;
|
||||
dns_name_t *pname = dns_fixedname_initname(&fname);
|
||||
|
||||
/* uri + object */
|
||||
if (isc_buffer_availablelength(buf) < strlen(uri) + strlen(";object="))
|
||||
{
|
||||
return (ISC_R_NOSPACE);
|
||||
}
|
||||
isc_buffer_putstr(buf, uri);
|
||||
isc_buffer_putstr(buf, ";object=");
|
||||
/* zone name */
|
||||
result = dns_name_tofilenametext(zname, false, buf);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
/*
|
||||
* policy name
|
||||
*
|
||||
* Note that strlen(policy) is not the actual length, but if this
|
||||
* already does not fit, the escaped version returned from
|
||||
* dns_name_tofilenametext() certainly won't fit.
|
||||
*/
|
||||
if (isc_buffer_availablelength(buf) < (strlen(policy) + 1)) {
|
||||
return (ISC_R_NOSPACE);
|
||||
}
|
||||
isc_buffer_putstr(buf, "-");
|
||||
result = dns_name_fromstring(pname, policy, dns_rootname, 0, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
result = dns_name_tofilenametext(pname, false, buf);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
/* key type + current time */
|
||||
isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf));
|
||||
return isc_buffer_printf(buf, "-%s-%s", ksk ? "ksk" : "zsk", timebuf);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
|
||||
const char *policy, dns_rdataclass_t rdclass,
|
||||
isc_mem_t *mctx, uint32_t alg, int size, int flags,
|
||||
dst_key_t **dstkey) {
|
||||
isc_result_t result;
|
||||
dst_key_t *newkey = NULL;
|
||||
const char *uri = NULL;
|
||||
|
||||
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
||||
REQUIRE(dns_name_isvalid(origin));
|
||||
REQUIRE(policy != NULL);
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(dstkey != NULL && *dstkey == NULL);
|
||||
|
||||
uri = dns_keystore_pkcs11uri(keystore);
|
||||
if (uri != NULL) {
|
||||
/*
|
||||
* Create the PKCS#11 label.
|
||||
* The label consists of the configured URI, and the object
|
||||
* parameter. The object parameter needs to be unique. We
|
||||
* know that for a given point in time, there will be at most
|
||||
* one key per type created for each zone in a given DNSSEC
|
||||
* policy. Hence the object is constructed out of the following
|
||||
* parts: the zone name, policy name, key type, and the
|
||||
* current time.
|
||||
*
|
||||
* The object may not contain any characters that conflict with
|
||||
* special characters in the PKCS#11 URI scheme syntax (see
|
||||
* RFC 7512, Section 2.3). Therefore, we mangle the zone name
|
||||
* and policy name through 'dns_name_tofilenametext()'. We
|
||||
* could create a new function to convert a name to PKCS#11
|
||||
* text, but this existing function will suffice.
|
||||
*/
|
||||
char label[NAME_MAX];
|
||||
isc_buffer_t buf;
|
||||
isc_buffer_init(&buf, label, sizeof(label));
|
||||
result = buildpkcs11label(uri, origin, policy, flags, &buf);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
dns_name_format(origin, namebuf, sizeof(namebuf));
|
||||
isc_log_write(
|
||||
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
||||
"keystore: failed to create PKCS#11 object "
|
||||
"for zone %s, policy %s: %s",
|
||||
namebuf, policy, isc_result_totext(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Generate the key */
|
||||
result = dst_key_generate(origin, alg, size, 0, flags,
|
||||
DNS_KEYPROTO_DNSSEC, rdclass, label,
|
||||
mctx, &newkey, NULL);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(
|
||||
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
||||
"keystore: failed to generate PKCS#11 object "
|
||||
"%s: %s",
|
||||
label, isc_result_totext(result));
|
||||
return (result);
|
||||
}
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
||||
"keystore: generated PKCS#11 object %s", label);
|
||||
} else {
|
||||
result = dst_key_generate(origin, alg, size, 0, flags,
|
||||
DNS_KEYPROTO_DNSSEC, rdclass, NULL,
|
||||
mctx, &newkey, NULL);
|
||||
}
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
*dstkey = newkey;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
|
||||
dns_keystore_t **kspp) {
|
||||
dns_keystore_t *keystore = NULL;
|
||||
|
||||
REQUIRE(kspp != NULL && *kspp == NULL);
|
||||
|
||||
if (list == NULL) {
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
for (keystore = ISC_LIST_HEAD(*list); keystore != NULL;
|
||||
keystore = ISC_LIST_NEXT(keystore, link))
|
||||
{
|
||||
if (strcmp(keystore->name, name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keystore == NULL) {
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
dns_keystore_attach(keystore, kspp);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
@ -410,13 +410,78 @@ opensslecdsa_create_pkey(unsigned int key_alg, bool private,
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
static isc_result_t
|
||||
opensslecdsa_generate_pkey(unsigned int key_alg, EVP_PKEY **retkey) {
|
||||
opensslecdsa_generate_pkey_with_uri(int group_nid, const char *label,
|
||||
EVP_PKEY **retkey) {
|
||||
int status;
|
||||
isc_result_t ret;
|
||||
char *uri = UNCONST(label);
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
OSSL_PARAM params[3];
|
||||
|
||||
/* Generate the key's parameters. */
|
||||
params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0);
|
||||
params[1] = OSSL_PARAM_construct_utf8_string(
|
||||
"pkcs11_key_usage", (char *)"digitalSignature", 0);
|
||||
params[2] = OSSL_PARAM_construct_end();
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11");
|
||||
if (ctx == NULL) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
status = EVP_PKEY_keygen_init(ctx);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
status = EVP_PKEY_CTX_set_params(ctx, params);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_params",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
/*
|
||||
* Setting the P-384 curve doesn't work correctly when using:
|
||||
* OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0);
|
||||
*
|
||||
* Instead use the OpenSSL function to set the curve nid param.
|
||||
*/
|
||||
status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_"
|
||||
"curve_nid",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
/* Generate the key. */
|
||||
status = EVP_PKEY_generate(ctx, retkey);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_generate",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
ret = ISC_R_SUCCESS;
|
||||
|
||||
err:
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
opensslecdsa_generate_pkey(unsigned int key_alg, const char *label,
|
||||
EVP_PKEY **retkey) {
|
||||
isc_result_t ret;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
EVP_PKEY *params_pkey = NULL;
|
||||
int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg);
|
||||
int status;
|
||||
|
||||
if (label != NULL) {
|
||||
return (opensslecdsa_generate_pkey_with_uri(group_nid, label,
|
||||
retkey));
|
||||
}
|
||||
|
||||
/* Generate the key's parameters. */
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
|
||||
if (ctx == NULL) {
|
||||
@ -498,11 +563,16 @@ opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf,
|
||||
#else
|
||||
|
||||
static isc_result_t
|
||||
opensslecdsa_generate_pkey(unsigned int key_alg, EVP_PKEY **retkey) {
|
||||
opensslecdsa_generate_pkey(unsigned int key_alg, const char *label,
|
||||
EVP_PKEY **retkey) {
|
||||
isc_result_t ret;
|
||||
EC_KEY *eckey = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg);
|
||||
int group_nid;
|
||||
|
||||
UNUSED(label);
|
||||
|
||||
group_nid = opensslecdsa_key_alg_to_group_nid(key_alg);
|
||||
|
||||
eckey = EC_KEY_new_by_curve_name(group_nid);
|
||||
if (eckey == NULL) {
|
||||
@ -815,7 +885,7 @@ opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
|
||||
UNUSED(unused);
|
||||
UNUSED(callback);
|
||||
|
||||
ret = opensslecdsa_generate_pkey(key->key_alg, &pkey);
|
||||
ret = opensslecdsa_generate_pkey(key->key_alg, key->label, &pkey);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
return (ret);
|
||||
}
|
||||
|
@ -366,13 +366,17 @@ progress_cb(int p, int n, BN_GENCB *cb) {
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
opensslrsa_generate_pkey(unsigned int key_size, BIGNUM *e,
|
||||
opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e,
|
||||
void (*callback)(int), EVP_PKEY **retkey) {
|
||||
RSA *rsa = RSA_new();
|
||||
EVP_PKEY *pkey = EVP_PKEY_new();
|
||||
RSA *rsa = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
BN_GENCB *cb = NULL;
|
||||
isc_result_t ret;
|
||||
|
||||
UNUSED(label);
|
||||
|
||||
rsa = RSA_new();
|
||||
pkey = EVP_PKEY_new();
|
||||
if (rsa == NULL || pkey == NULL) {
|
||||
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
@ -493,11 +497,62 @@ progress_cb(EVP_PKEY_CTX *ctx) {
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
opensslrsa_generate_pkey(unsigned int key_size, BIGNUM *e,
|
||||
opensslrsa_generate_pkey_with_uri(size_t key_size, const char *label,
|
||||
EVP_PKEY **retkey) {
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
OSSL_PARAM params[4];
|
||||
char *uri = UNCONST(label);
|
||||
isc_result_t ret;
|
||||
int status;
|
||||
|
||||
params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0);
|
||||
params[1] = OSSL_PARAM_construct_utf8_string(
|
||||
"pkcs11_key_usage", (char *)"digitalSignature", 0);
|
||||
params[2] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &key_size);
|
||||
params[3] = OSSL_PARAM_construct_end();
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11");
|
||||
if (ctx == NULL) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
status = EVP_PKEY_keygen_init(ctx);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
status = EVP_PKEY_CTX_set_params(ctx, params);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_params",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
status = EVP_PKEY_generate(ctx, retkey);
|
||||
if (status != 1) {
|
||||
DST_RET(dst__openssl_toresult2("EVP_PKEY_generate",
|
||||
DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
|
||||
ret = ISC_R_SUCCESS;
|
||||
err:
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
opensslrsa_generate_pkey(unsigned int key_size, const char *label, BIGNUM *e,
|
||||
void (*callback)(int), EVP_PKEY **retkey) {
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
EVP_PKEY_CTX *ctx;
|
||||
isc_result_t ret;
|
||||
|
||||
if (label != NULL) {
|
||||
return (opensslrsa_generate_pkey_with_uri(key_size, label,
|
||||
retkey));
|
||||
}
|
||||
|
||||
ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
if (ctx == NULL) {
|
||||
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
|
||||
}
|
||||
@ -669,7 +724,8 @@ opensslrsa_generate(dst_key_t *key, int exp, void (*callback)(int)) {
|
||||
BN_set_bit(e, 32);
|
||||
}
|
||||
|
||||
ret = opensslrsa_generate_pkey(key->key_size, e, callback, &pkey);
|
||||
ret = opensslrsa_generate_pkey(key->key_size, key->label, e, callback,
|
||||
&pkey);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
goto err;
|
||||
}
|
||||
|
@ -1056,13 +1056,20 @@ find_zone_keys(dns_zone_t *zone, isc_mem_t *mctx, unsigned int maxkeys,
|
||||
unsigned int count = 0;
|
||||
isc_result_t result;
|
||||
isc_stdtime_t now = isc_stdtime_now();
|
||||
dns_kasp_t *kasp;
|
||||
dns_keystorelist_t *keystores;
|
||||
const char *keydir;
|
||||
|
||||
ISC_LIST_INIT(keylist);
|
||||
|
||||
kasp = dns_zone_getkasp(zone);
|
||||
keydir = dns_zone_getkeydirectory(zone);
|
||||
keystores = dns_zone_getkeystores(zone);
|
||||
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone),
|
||||
dns_zone_getkeydirectory(zone),
|
||||
now, mctx, &keylist);
|
||||
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), kasp,
|
||||
keydir, keystores, now, mctx,
|
||||
&keylist);
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
313
lib/dns/zone.c
313
lib/dns/zone.c
@ -218,6 +218,13 @@ typedef struct dns_include dns_include_t;
|
||||
#define ZONEDB_LOCK(l, t) RWLOCK((l), (t))
|
||||
#define ZONEDB_UNLOCK(l, t) RWUNLOCK((l), (t))
|
||||
|
||||
#define RETERR(x) \
|
||||
do { \
|
||||
result = (x); \
|
||||
if (result != ISC_R_SUCCESS) \
|
||||
goto failure; \
|
||||
} while (0)
|
||||
|
||||
#ifdef ENABLE_AFL
|
||||
extern bool dns_fuzzing_resolver;
|
||||
#endif /* ifdef ENABLE_AFL */
|
||||
@ -303,6 +310,7 @@ struct dns_zone {
|
||||
isc_stdtime_t log_key_expired_timer;
|
||||
char *keydirectory;
|
||||
dns_keyfileio_t *kfio;
|
||||
dns_keystorelist_t *keystores;
|
||||
|
||||
uint32_t maxrefresh;
|
||||
uint32_t minrefresh;
|
||||
@ -6056,6 +6064,207 @@ was_dumping(dns_zone_t *zone) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
keyfromfile(dns_zone_t *zone, dst_key_t *pubkey, isc_mem_t *mctx,
|
||||
dst_key_t **key) {
|
||||
const char *directory = zone->keydirectory;
|
||||
dns_kasp_t *kasp = zone->kasp;
|
||||
dst_key_t *foundkey = NULL;
|
||||
isc_result_t result = ISC_R_NOTFOUND;
|
||||
|
||||
if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
|
||||
(strcmp(dns_kasp_getname(kasp), "insecure") == 0))
|
||||
{
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(pubkey), dst_key_id(pubkey),
|
||||
dst_key_alg(pubkey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE),
|
||||
directory, mctx, &foundkey);
|
||||
} else {
|
||||
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
dns_keystore_t *ks = dns_kasp_key_keystore(kkey);
|
||||
directory = dns_keystore_directory(ks,
|
||||
zone->keydirectory);
|
||||
|
||||
result = dst_key_fromfile(
|
||||
dst_key_name(pubkey), dst_key_id(pubkey),
|
||||
dst_key_alg(pubkey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
directory, mctx, &foundkey);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*key = foundkey;
|
||||
return (result);
|
||||
}
|
||||
|
||||
#define is_zone_key(key) \
|
||||
((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE)
|
||||
|
||||
static isc_result_t
|
||||
findzonekeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_dbnode_t *node, const dns_name_t *name, isc_stdtime_t now,
|
||||
isc_mem_t *mctx, unsigned int maxkeys, dst_key_t **keys,
|
||||
unsigned int *nkeys) {
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
isc_result_t result;
|
||||
dst_key_t *pubkey = NULL;
|
||||
unsigned int count = 0;
|
||||
|
||||
*nkeys = 0;
|
||||
memset(keys, 0, sizeof(*keys) * maxkeys);
|
||||
dns_rdataset_init(&rdataset);
|
||||
RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
|
||||
&rdataset, NULL));
|
||||
RETERR(dns_rdataset_first(&rdataset));
|
||||
while (result == ISC_R_SUCCESS && count < maxkeys) {
|
||||
pubkey = NULL;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
|
||||
dst_key_setttl(pubkey, rdataset.ttl);
|
||||
|
||||
if (!is_zone_key(pubkey) ||
|
||||
(dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
|
||||
{
|
||||
goto next;
|
||||
}
|
||||
/* Corrupted .key file? */
|
||||
if (!dns_name_equal(name, dst_key_name(pubkey))) {
|
||||
goto next;
|
||||
}
|
||||
keys[count] = NULL;
|
||||
result = keyfromfile(zone, pubkey, mctx, &keys[count]);
|
||||
|
||||
/*
|
||||
* If the key was revoked and the private file
|
||||
* doesn't exist, maybe it was revoked internally
|
||||
* by named. Try loading the unrevoked version.
|
||||
*/
|
||||
if (result == ISC_R_FILENOTFOUND) {
|
||||
uint32_t flags;
|
||||
flags = dst_key_flags(pubkey);
|
||||
if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
|
||||
dst_key_setflags(pubkey,
|
||||
flags & ~DNS_KEYFLAG_REVOKE);
|
||||
result = keyfromfile(zone, pubkey, mctx,
|
||||
&keys[count]);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
dst_key_pubcompare(pubkey, keys[count],
|
||||
false))
|
||||
{
|
||||
dst_key_setflags(keys[count], flags);
|
||||
}
|
||||
dst_key_setflags(pubkey, flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
char filename[DNS_NAME_FORMATSIZE +
|
||||
DNS_SECALG_FORMATSIZE +
|
||||
sizeof("key file for //65535")];
|
||||
isc_result_t result2;
|
||||
isc_buffer_t buf;
|
||||
|
||||
isc_buffer_init(&buf, filename, sizeof(filename));
|
||||
result2 = dst_key_getfilename(
|
||||
dst_key_name(pubkey), dst_key_id(pubkey),
|
||||
dst_key_alg(pubkey),
|
||||
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
|
||||
DST_TYPE_STATE),
|
||||
NULL, mctx, &buf);
|
||||
if (result2 != ISC_R_SUCCESS) {
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
char algbuf[DNS_SECALG_FORMATSIZE];
|
||||
|
||||
dns_name_format(dst_key_name(pubkey), namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_secalg_format(dst_key_alg(pubkey), algbuf,
|
||||
sizeof(algbuf));
|
||||
snprintf(filename, sizeof(filename) - 1,
|
||||
"key file for %s/%s/%d", namebuf,
|
||||
algbuf, dst_key_id(pubkey));
|
||||
}
|
||||
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
|
||||
"dns_zone_findkeys: error reading %s: %s",
|
||||
filename, isc_result_totext(result));
|
||||
}
|
||||
|
||||
if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
|
||||
keys[count] = pubkey;
|
||||
pubkey = NULL;
|
||||
count++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a key is marked inactive, skip it
|
||||
*/
|
||||
if (!dns_dnssec_keyactive(keys[count], now)) {
|
||||
dst_key_setinactive(pubkey, true);
|
||||
dst_key_free(&keys[count]);
|
||||
keys[count] = pubkey;
|
||||
pubkey = NULL;
|
||||
count++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whatever the key's default TTL may have
|
||||
* been, the rdataset TTL takes priority.
|
||||
*/
|
||||
dst_key_setttl(keys[count], rdataset.ttl);
|
||||
|
||||
if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
|
||||
/* We should never get here. */
|
||||
dst_key_free(&keys[count]);
|
||||
goto next;
|
||||
}
|
||||
count++;
|
||||
next:
|
||||
if (pubkey != NULL) {
|
||||
dst_key_free(&pubkey);
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
result = dns_rdataset_next(&rdataset);
|
||||
}
|
||||
if (result != ISC_R_NOMORE) {
|
||||
goto failure;
|
||||
}
|
||||
if (count == 0) {
|
||||
result = ISC_R_NOTFOUND;
|
||||
} else {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
failure:
|
||||
if (dns_rdataset_isassociated(&rdataset)) {
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
}
|
||||
if (pubkey != NULL) {
|
||||
dst_key_free(&pubkey);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
while (count > 0) {
|
||||
dst_key_free(&keys[--count]);
|
||||
}
|
||||
}
|
||||
*nkeys = count;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Find up to 'maxkeys' DNSSEC keys used for signing version 'ver' of database
|
||||
* 'db' for zone 'zone' in its key directory, then load these keys into 'keys'.
|
||||
@ -6063,21 +6272,23 @@ was_dumping(dns_zone_t *zone) {
|
||||
* 'now'. Store the number of keys found in 'nkeys'.
|
||||
*/
|
||||
isc_result_t
|
||||
dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys,
|
||||
dst_key_t **keys, unsigned int *nkeys) {
|
||||
dns_zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys,
|
||||
dst_key_t **keys, unsigned int *nkeys) {
|
||||
isc_result_t result;
|
||||
dns_dbnode_t *node = NULL;
|
||||
const char *directory = dns_zone_getkeydirectory(zone);
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(nkeys != NULL);
|
||||
REQUIRE(keys != NULL);
|
||||
|
||||
CHECK(dns_db_findnode(db, dns_db_origin(db), false, &node));
|
||||
memset(keys, 0, sizeof(*keys) * maxkeys);
|
||||
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
|
||||
result = dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db),
|
||||
directory, now, mctx, maxkeys, keys,
|
||||
nkeys);
|
||||
result = findzonekeys(zone, db, ver, node, dns_db_origin(db), now, mctx,
|
||||
maxkeys, keys, nkeys);
|
||||
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
@ -6120,8 +6331,8 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
|
||||
/* Get keys from private key files. */
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_dnssec_findmatchingkeys(origin, dir, now,
|
||||
dns_zone_getmctx(zone), keys);
|
||||
result = dns_dnssec_findmatchingkeys(origin, kasp, dir, zone->keystores,
|
||||
now, dns_zone_getmctx(zone), keys);
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
|
||||
@ -6134,8 +6345,8 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatatype_none, 0, &keyset, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
CHECK(dns_dnssec_keylistfromrdataset(
|
||||
origin, dir, dns_zone_getmctx(zone), &keyset, NULL,
|
||||
NULL, false, false, &dnskeys));
|
||||
origin, kasp, dir, dns_zone_getmctx(zone), &keyset,
|
||||
NULL, NULL, false, false, &dnskeys));
|
||||
} else if (result != ISC_R_NOTFOUND) {
|
||||
CHECK(result);
|
||||
}
|
||||
@ -6751,11 +6962,11 @@ zone_resigninc(dns_zone_t *zone) {
|
||||
|
||||
now = isc_stdtime_now();
|
||||
|
||||
result = dns__zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
result = dns_zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dns_zone_log(zone, ISC_LOG_ERROR,
|
||||
"zone_resigninc:dns__zone_findkeys -> %s",
|
||||
"zone_resigninc:dns_zone_findkeys -> %s",
|
||||
isc_result_totext(result));
|
||||
goto failure;
|
||||
}
|
||||
@ -7986,11 +8197,11 @@ zone_nsec3chain(dns_zone_t *zone) {
|
||||
|
||||
now = isc_stdtime_now();
|
||||
|
||||
result = dns__zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
result = dns_zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dnssec_log(zone, ISC_LOG_ERROR,
|
||||
"zone_nsec3chain:dns__zone_findkeys -> %s",
|
||||
"zone_nsec3chain:dns_zone_findkeys -> %s",
|
||||
isc_result_totext(result));
|
||||
goto failure;
|
||||
}
|
||||
@ -9071,11 +9282,11 @@ zone_sign(dns_zone_t *zone) {
|
||||
|
||||
now = isc_stdtime_now();
|
||||
|
||||
result = dns__zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
result = dns_zone_findkeys(zone, db, version, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dnssec_log(zone, ISC_LOG_ERROR,
|
||||
"zone_sign:dns__zone_findkeys -> %s",
|
||||
"zone_sign:dns_zone_findkeys -> %s",
|
||||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
@ -15920,6 +16131,9 @@ dns_zone_dnskey_inuse(dns_zone_t *zone, dns_rdata_t *rdata, bool *inuse) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_stdtime_t now = isc_stdtime_now();
|
||||
isc_mem_t *mctx;
|
||||
dns_kasp_t *kasp;
|
||||
dns_keystorelist_t *keystores;
|
||||
const char *keydir;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(dns_rdatatype_iskeymaterial(rdata->type));
|
||||
@ -15930,10 +16144,14 @@ dns_zone_dnskey_inuse(dns_zone_t *zone, dns_rdata_t *rdata, bool *inuse) {
|
||||
|
||||
*inuse = false;
|
||||
|
||||
kasp = dns_zone_getkasp(zone);
|
||||
keydir = dns_zone_getkeydirectory(zone);
|
||||
keystores = dns_zone_getkeystores(zone);
|
||||
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone),
|
||||
dns_zone_getkeydirectory(zone),
|
||||
now, mctx, &keylist);
|
||||
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), kasp,
|
||||
keydir, keystores, now, mctx,
|
||||
&keylist);
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
return (ISC_R_SUCCESS);
|
||||
@ -19414,6 +19632,32 @@ dns_zone_getkeydirectory(dns_zone_t *zone) {
|
||||
return (zone->keydirectory);
|
||||
}
|
||||
|
||||
void
|
||||
dns_zone_setkeystores(dns_zone_t *zone, dns_keystorelist_t *keystores) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->keystores = keystores;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
dns_keystorelist_t *
|
||||
dns_zone_getkeystores(dns_zone_t *zone) {
|
||||
dns_keystorelist_t *ks = NULL;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
if (inline_raw(zone) && zone->secure != NULL) {
|
||||
ks = zone->secure->keystores;
|
||||
} else {
|
||||
ks = zone->keystores;
|
||||
}
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return (ks);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) {
|
||||
dns_zone_t *zone;
|
||||
@ -20105,11 +20349,11 @@ sign_apex(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
dst_key_t *zone_keys[DNS_MAXZONEKEYS];
|
||||
unsigned int nkeys = 0, i;
|
||||
|
||||
result = dns__zone_findkeys(zone, db, ver, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
result = dns_zone_findkeys(zone, db, ver, now, zone->mctx,
|
||||
DNS_MAXZONEKEYS, zone_keys, &nkeys);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
dnssec_log(zone, ISC_LOG_ERROR,
|
||||
"sign_apex:dns__zone_findkeys -> %s",
|
||||
"sign_apex:dns_zone_findkeys -> %s",
|
||||
isc_result_totext(result));
|
||||
return (result);
|
||||
}
|
||||
@ -20321,7 +20565,6 @@ static bool
|
||||
do_checkds(dns_zone_t *zone, dst_key_t *key, isc_stdtime_t now,
|
||||
bool dspublish) {
|
||||
dns_kasp_t *kasp = zone->kasp;
|
||||
const char *dir = dns_zone_getkeydirectory(zone);
|
||||
isc_result_t result;
|
||||
uint32_t count = 0;
|
||||
uint32_t num;
|
||||
@ -20372,7 +20615,7 @@ do_checkds(dns_zone_t *zone, dst_key_t *key, isc_stdtime_t now,
|
||||
dspublish ? "published" : "withdrawn", dst_key_id(key));
|
||||
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_keymgr_checkds_id(kasp, &zone->checkds_ok, dir, now, now,
|
||||
result = dns_keymgr_checkds_id(kasp, &zone->checkds_ok, now, now,
|
||||
dspublish, dst_key_id(key),
|
||||
dst_key_alg(key));
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
@ -21574,7 +21817,6 @@ zone_rekey(dns_zone_t *zone) {
|
||||
dns_rdataset_init(&keysigs);
|
||||
dns_rdataset_init(&cdsset);
|
||||
dns_rdataset_init(&cdnskeyset);
|
||||
dir = dns_zone_getkeydirectory(zone);
|
||||
mctx = zone->mctx;
|
||||
dns_diff_init(mctx, &diff);
|
||||
dns_diff_init(mctx, &_sig_diff);
|
||||
@ -21588,6 +21830,7 @@ zone_rekey(dns_zone_t *zone) {
|
||||
now = isc_time_seconds(&timenow);
|
||||
|
||||
kasp = zone->kasp;
|
||||
dir = dns_zone_getkeydirectory(zone);
|
||||
|
||||
dnssec_log(zone, ISC_LOG_INFO, "reconfiguring zone keys");
|
||||
|
||||
@ -21634,8 +21877,8 @@ zone_rekey(dns_zone_t *zone) {
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
|
||||
result = dns_dnssec_keylistfromrdataset(
|
||||
&zone->origin, dir, mctx, &keyset, &keysigs, &soasigs,
|
||||
false, false, &dnskeys);
|
||||
&zone->origin, kasp, dir, mctx, &keyset, &keysigs,
|
||||
&soasigs, false, false, &dnskeys);
|
||||
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
@ -21696,8 +21939,8 @@ zone_rekey(dns_zone_t *zone) {
|
||||
KASP_LOCK(kasp);
|
||||
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx,
|
||||
&keys);
|
||||
result = dns_dnssec_findmatchingkeys(&zone->origin, kasp, dir,
|
||||
zone->keystores, now, mctx, &keys);
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@ -21733,7 +21976,7 @@ zone_rekey(dns_zone_t *zone) {
|
||||
if (result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND) {
|
||||
dns_zone_lock_keyfiles(zone);
|
||||
result = dns_keymgr_run(&zone->origin, zone->rdclass,
|
||||
dir, mctx, &keys, &dnskeys,
|
||||
mctx, &keys, &dnskeys, dir,
|
||||
kasp, now, &nexttime);
|
||||
dns_zone_unlock_keyfiles(zone);
|
||||
|
||||
|
@ -29,11 +29,6 @@ typedef struct {
|
||||
bool offline;
|
||||
} dns__zonediff_t;
|
||||
|
||||
isc_result_t
|
||||
dns__zone_findkeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
|
||||
isc_stdtime_t now, isc_mem_t *mctx, unsigned int maxkeys,
|
||||
dst_key_t **keys, unsigned int *nkeys);
|
||||
|
||||
isc_result_t
|
||||
dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version,
|
||||
dst_key_t *zone_keys[], unsigned int nkeys,
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <dns/dnstap.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rbt.h>
|
||||
@ -77,8 +78,9 @@ fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
|
||||
isc_log_t *logctxlogc);
|
||||
|
||||
static isc_result_t
|
||||
keydirexist(const cfg_obj_t *zcgf, const char *dir, const char *kaspnamestr,
|
||||
isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx);
|
||||
keydirexist(const cfg_obj_t *zcgf, const char *optname, dns_name_t *zname,
|
||||
const char *dirname, const char *kaspnamestr, isc_symtab_t *symtab,
|
||||
isc_log_t *logctx, isc_mem_t *mctx);
|
||||
|
||||
static const cfg_obj_t *
|
||||
find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
|
||||
@ -1200,6 +1202,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 +1333,108 @@ 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 *val;
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
const cfg_obj_t *kopt;
|
||||
const cfg_obj_t *kobj = NULL;
|
||||
if (!cfg_obj_istuple(kconfig)) {
|
||||
continue;
|
||||
}
|
||||
val = cfg_obj_asstring(
|
||||
cfg_tuple_get(kconfig, "name"));
|
||||
if (strcmp(DNS_KEYSTORE_KEYDIRECTORY, val) == 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;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
kopt = cfg_tuple_get(kconfig, "options");
|
||||
if (cfg_map_get(kopt, "directory", &kobj) ==
|
||||
ISC_R_SUCCESS)
|
||||
{
|
||||
val = cfg_obj_asstring(kobj);
|
||||
ret = isc_file_isdirectory(val);
|
||||
switch (ret) {
|
||||
case ISC_R_SUCCESS:
|
||||
break;
|
||||
case ISC_R_FILENOTFOUND:
|
||||
cfg_obj_log(
|
||||
obj, logctx,
|
||||
ISC_LOG_WARNING,
|
||||
"key-store directory: "
|
||||
"'%s' does not exist",
|
||||
val);
|
||||
break;
|
||||
case ISC_R_INVALIDFILE:
|
||||
cfg_obj_log(
|
||||
obj, logctx,
|
||||
ISC_LOG_WARNING,
|
||||
"key-store directory: "
|
||||
"'%s' is not a "
|
||||
"directory",
|
||||
val);
|
||||
break;
|
||||
default:
|
||||
cfg_obj_log(
|
||||
obj, logctx,
|
||||
ISC_LOG_WARNING,
|
||||
"key-store directory: "
|
||||
"'%s' %s",
|
||||
val,
|
||||
isc_result_totext(ret));
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = cfg_keystore_fromconfig(kconfig, mctx,
|
||||
logctx, NULL,
|
||||
&kslist, NULL);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add default key-store "key-directory".
|
||||
*/
|
||||
tresult = cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist,
|
||||
NULL);
|
||||
if (tresult != ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = tresult;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check dnssec-policy.
|
||||
*/
|
||||
@ -1366,7 +1472,8 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
|
||||
|
||||
ret = cfg_kasp_fromconfig(
|
||||
kconfig, NULL, check_algorithms,
|
||||
mctx, logctx, &list, &kasp);
|
||||
mctx, logctx, &kslist, &list,
|
||||
&kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
@ -1407,6 +1514,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) {
|
||||
@ -2800,6 +2919,129 @@ cleanup:
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
|
||||
dns_name_t *zname, const char *name, const char *keydir,
|
||||
isc_symtab_t *keydirs, isc_log_t *logctx, isc_mem_t *mctx) {
|
||||
const char *dir = keydir;
|
||||
const cfg_listelt_t *element;
|
||||
isc_result_t ret, result = ISC_R_SUCCESS;
|
||||
bool do_cleanup = false;
|
||||
bool done = false;
|
||||
bool keystore = false;
|
||||
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
dns_kasp_t *kasp = NULL, *kasp_next = NULL;
|
||||
dns_kasplist_t kasplist;
|
||||
|
||||
const cfg_obj_t *keystores = NULL;
|
||||
dns_keystore_t *ks = NULL, *ks_next = NULL;
|
||||
dns_keystorelist_t kslist;
|
||||
|
||||
/* If no dnssec-policy or key-store, use the dir (key-directory) */
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
(void)cfg_map_get(config, "key-store", &keystores);
|
||||
if (kasps == NULL || keystores == NULL) {
|
||||
goto check;
|
||||
}
|
||||
|
||||
ISC_LIST_INIT(kasplist);
|
||||
ISC_LIST_INIT(kslist);
|
||||
do_cleanup = true;
|
||||
|
||||
/*
|
||||
* Build the keystore list.
|
||||
*/
|
||||
for (element = cfg_list_first(keystores); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kcfg = cfg_listelt_value(element);
|
||||
(void)cfg_keystore_fromconfig(kcfg, mctx, logctx, NULL, &kslist,
|
||||
NULL);
|
||||
}
|
||||
(void)cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist, NULL);
|
||||
|
||||
/*
|
||||
* Look for the dnssec-policy by name, which is the dnssec-policy
|
||||
* for the zone in question.
|
||||
*/
|
||||
for (element = cfg_list_first(kasps); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *kconfig = cfg_listelt_value(element);
|
||||
const cfg_obj_t *kaspobj = NULL;
|
||||
|
||||
if (!cfg_obj_istuple(kconfig)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kaspobj = cfg_tuple_get(kconfig, "name");
|
||||
if (strcmp(name, cfg_obj_asstring(kaspobj)) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = cfg_kasp_fromconfig(kconfig, NULL, false, mctx, logctx,
|
||||
&kslist, &kasplist, &kasp);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
kasp = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (kasp == NULL) {
|
||||
goto check;
|
||||
}
|
||||
|
||||
/* Check key-stores of keys */
|
||||
dns_kasp_freeze(kasp);
|
||||
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
dns_keystore_t *kks = dns_kasp_key_keystore(kkey);
|
||||
dir = dns_keystore_directory(kks, keydir);
|
||||
keystore = (kks != NULL && strcmp(DNS_KEYSTORE_KEYDIRECTORY,
|
||||
dns_keystore_name(kks)) != 0);
|
||||
|
||||
ret = keydirexist(zconfig,
|
||||
keystore ? "key-store directory"
|
||||
: "key-directory",
|
||||
zname, dir, name, keydirs, logctx, mctx);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
dns_kasp_thaw(kasp);
|
||||
done = true;
|
||||
|
||||
check:
|
||||
if (!done) {
|
||||
ret = keydirexist(zconfig, "key-directory", zname, dir, name,
|
||||
keydirs, logctx, mctx);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
result = ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_cleanup) {
|
||||
if (kasp != NULL) {
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL;
|
||||
kasp = kasp_next)
|
||||
{
|
||||
kasp_next = ISC_LIST_NEXT(kasp, link);
|
||||
ISC_LIST_UNLINK(kasplist, kasp, link);
|
||||
dns_kasp_detach(&kasp);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
||||
const cfg_obj_t *config, isc_symtab_t *symtab,
|
||||
@ -3068,8 +3310,6 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
||||
(void)cfg_map_get(goptions, "dnssec-policy", &obj);
|
||||
}
|
||||
if (obj != NULL) {
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
|
||||
kaspname = cfg_obj_asstring(obj);
|
||||
if (strcmp(kaspname, "default") == 0) {
|
||||
has_dnssecpolicy = true;
|
||||
@ -3081,6 +3321,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
||||
has_dnssecpolicy = false;
|
||||
kasp_inlinesigning = false;
|
||||
} else {
|
||||
const cfg_obj_t *kasps = NULL;
|
||||
(void)cfg_map_get(config, "dnssec-policy", &kasps);
|
||||
for (element = cfg_list_first(kasps); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
@ -3653,19 +3894,18 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there is no other zone with the same
|
||||
* key-directory and a different dnssec-policy.
|
||||
* Make sure there is no other zone with the same key directory (from
|
||||
* (key-directory or key-store/directory) and a different dnssec-policy.
|
||||
*/
|
||||
if (zname != NULL) {
|
||||
char keydirbuf[DNS_NAME_FORMATSIZE + 128];
|
||||
char *tmp = keydirbuf;
|
||||
size_t len = sizeof(keydirbuf);
|
||||
dns_name_format(zname, keydirbuf, sizeof(keydirbuf));
|
||||
len -= strlen(tmp);
|
||||
tmp += strlen(tmp);
|
||||
(void)snprintf(tmp, len, "/%s", (dir == NULL) ? "(null)" : dir);
|
||||
tresult = keydirexist(zconfig, (const char *)keydirbuf,
|
||||
kaspname, keydirs, logctx, mctx);
|
||||
if (has_dnssecpolicy) {
|
||||
tresult = check_keydir(config, zconfig, zname, kaspname,
|
||||
dir, keydirs, logctx, mctx);
|
||||
} else {
|
||||
tresult = keydirexist(zconfig, "key-directory", zname,
|
||||
dir, kaspname, keydirs, logctx,
|
||||
mctx);
|
||||
}
|
||||
if (tresult != ISC_R_SUCCESS) {
|
||||
result = tresult;
|
||||
}
|
||||
@ -3885,16 +4125,33 @@ fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
keydirexist(const cfg_obj_t *zcfg, const char *keydir, const char *kaspnamestr,
|
||||
isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx) {
|
||||
keydirexist(const cfg_obj_t *zcfg, const char *optname, dns_name_t *zname,
|
||||
const char *dirname, const char *kaspnamestr, isc_symtab_t *symtab,
|
||||
isc_log_t *logctx, isc_mem_t *mctx) {
|
||||
isc_result_t result;
|
||||
isc_symvalue_t symvalue;
|
||||
char *symkey;
|
||||
char keydirbuf[DNS_NAME_FORMATSIZE + 128];
|
||||
char *keydir = keydirbuf;
|
||||
size_t len = sizeof(keydirbuf);
|
||||
size_t n;
|
||||
|
||||
if (kaspnamestr == NULL || strcmp(kaspnamestr, "none") == 0) {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
dns_name_format(zname, keydirbuf, sizeof(keydirbuf));
|
||||
len -= strlen(keydir);
|
||||
keydir += strlen(keydir);
|
||||
n = snprintf(keydir, len, "/%s", (dirname == NULL) ? "." : dirname);
|
||||
if (n > len) {
|
||||
cfg_obj_log(zcfg, logctx, ISC_LOG_WARNING,
|
||||
"%s '%s' truncated because too long, may cause "
|
||||
"false positives in key directory in use checks",
|
||||
optname, (dirname == NULL) ? "." : dirname);
|
||||
}
|
||||
keydir = keydirbuf;
|
||||
|
||||
result = isc_symtab_lookup(symtab, keydir, 0, &symvalue);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
const cfg_obj_t *kasp = NULL;
|
||||
@ -3916,9 +4173,9 @@ keydirexist(const cfg_obj_t *zcfg, const char *keydir, const char *kaspnamestr,
|
||||
}
|
||||
|
||||
cfg_obj_log(zcfg, logctx, ISC_LOG_ERROR,
|
||||
"key-directory '%s' already in use by zone %s with "
|
||||
"%s '%s' already in use by zone %s with "
|
||||
"policy %s: %s:%u",
|
||||
keydir,
|
||||
optname, keydir,
|
||||
cfg_obj_asstring(cfg_tuple_get(exist, "name")),
|
||||
cfg_obj_asstring(kasp), file, line);
|
||||
return (ISC_R_EXISTS);
|
||||
|
@ -26,13 +26,17 @@ ISC_LANG_BEGINDECLS
|
||||
isc_result_t
|
||||
cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
bool check_algorithms, isc_mem_t *mctx, isc_log_t *logctx,
|
||||
dns_kasplist_t *kasplist, dns_kasp_t **kaspp);
|
||||
dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
|
||||
dns_kasp_t **kaspp);
|
||||
/*%<
|
||||
* Create and configure a KASP. If 'default_kasp' is not NULL, the built-in
|
||||
* default configuration is used to set values that are not explicitly set in
|
||||
* the policy. If a 'kasplist' is provided, a lookup happens and if a KASP
|
||||
* already exists with the same name, no new KASP is created, and no attach to
|
||||
* 'kaspp' happens.
|
||||
* the policy.
|
||||
*
|
||||
* If a 'kasplist' is provided, a lookup happens and if a KASP already exists
|
||||
* with the same name, no new KASP is created, and no attach to 'kaspp' happens.
|
||||
*
|
||||
* The 'keystorelist' is where to lookup key stores if KASP keys are using them.
|
||||
*
|
||||
* If 'check_algorithms' is true then the dnssec-policy DNSSEC key
|
||||
* algorithms are checked against those supported by the crypto provider.
|
||||
@ -56,4 +60,33 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
*\li Other errors are possible.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
|
||||
isc_log_t *logctx, const char *engine,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
dns_keystore_t **kspp);
|
||||
/*%<
|
||||
* Create and configure a key store. If a 'keystorelist' is provided, a lookup
|
||||
* happens and if a keystore already exists with the same name, no new one is
|
||||
* created, and no attach to 'kspp' happens.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li config != NULL
|
||||
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*
|
||||
*\li 'logctx' is a valid logging context.
|
||||
*
|
||||
*\li kspp == NULL || *kspp == NULL
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS If creating and configuring the keystore succeeds.
|
||||
*\li #ISC_R_EXISTS If 'keystorelist' already has a keystore with 'name'.
|
||||
*\li #ISC_R_NOMEMORY
|
||||
*
|
||||
*\li Other errors are possible.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/kasp.h>
|
||||
#include <dns/keystore.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/log.h>
|
||||
#include <dns/nsec3.h>
|
||||
@ -89,12 +90,30 @@ get_duration(const cfg_obj_t **maps, const char *option, const char *dfl) {
|
||||
return (cfg_obj_asduration(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function for configuring strings.
|
||||
*/
|
||||
static const char *
|
||||
get_string(const cfg_obj_t **maps, const char *option) {
|
||||
const cfg_obj_t *obj;
|
||||
isc_result_t result;
|
||||
obj = NULL;
|
||||
|
||||
result = confget(maps, option, &obj);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
return (NULL);
|
||||
}
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
return (cfg_obj_asstring(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new kasp key derived from configuration.
|
||||
*/
|
||||
static isc_result_t
|
||||
cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
||||
bool check_algorithms, isc_log_t *logctx,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
uint32_t ksk_min_lifetime, uint32_t zsk_min_lifetime) {
|
||||
isc_result_t result;
|
||||
dns_kasp_key_t *key = NULL;
|
||||
@ -111,8 +130,15 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
||||
key->lifetime = 0; /* unlimited */
|
||||
key->algorithm = DNS_KEYALG_ECDSA256;
|
||||
key->length = -1;
|
||||
result = dns_keystorelist_find(keystorelist,
|
||||
DNS_KEYSTORE_KEYDIRECTORY,
|
||||
&key->keystore);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
const char *rolestr = NULL;
|
||||
const char *keydir = NULL;
|
||||
const cfg_obj_t *obj = NULL;
|
||||
isc_consttextregion_t alg;
|
||||
bool error = false;
|
||||
@ -127,6 +153,29 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
|
||||
key->role |= DNS_KASP_KEY_ROLE_ZSK;
|
||||
}
|
||||
|
||||
obj = cfg_tuple_get(config, "keystorage");
|
||||
if (cfg_obj_isstring(obj)) {
|
||||
keydir = cfg_obj_asstring(obj);
|
||||
}
|
||||
if (keydir == NULL) {
|
||||
keydir = DNS_KEYSTORE_KEYDIRECTORY;
|
||||
}
|
||||
result = dns_keystorelist_find(keystorelist, keydir,
|
||||
&key->keystore);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
|
||||
"dnssec-policy: keystore %s does not exist",
|
||||
keydir);
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
|
||||
"dnssec-policy: bad keystore %s", keydir);
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
INSIST(key->keystore != NULL);
|
||||
|
||||
key->lifetime = 0; /* unlimited */
|
||||
obj = cfg_tuple_get(config, "lifetime");
|
||||
if (cfg_obj_isduration(obj)) {
|
||||
@ -349,7 +398,8 @@ add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, isc_log_t *logctx) {
|
||||
isc_result_t
|
||||
cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
bool check_algorithms, isc_mem_t *mctx, isc_log_t *logctx,
|
||||
dns_kasplist_t *kasplist, dns_kasp_t **kaspp) {
|
||||
dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
|
||||
dns_kasp_t **kaspp) {
|
||||
isc_result_t result;
|
||||
const cfg_obj_t *maps[2];
|
||||
const cfg_obj_t *koptions = NULL;
|
||||
@ -524,8 +574,13 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
cfg_obj_t *kobj = cfg_listelt_value(element);
|
||||
result = cfg_kaspkey_fromconfig(
|
||||
kobj, kasp, check_algorithms, logctx,
|
||||
ksk_min_lifetime, zsk_min_lifetime);
|
||||
keystorelist, ksk_min_lifetime,
|
||||
zsk_min_lifetime);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(kobj, logctx, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"configure keys (%s)",
|
||||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -596,9 +651,12 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
new_key = NULL;
|
||||
result = dns_kasp_key_create(kasp, &new_key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, logctx, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"configure keys (%s)",
|
||||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dns_kasp_key_ksk(key)) {
|
||||
new_key->role |= DNS_KASP_KEY_ROLE_KSK;
|
||||
}
|
||||
@ -608,6 +666,16 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
|
||||
new_key->lifetime = dns_kasp_key_lifetime(key);
|
||||
new_key->algorithm = dns_kasp_key_algorithm(key);
|
||||
new_key->length = dns_kasp_key_size(key);
|
||||
result = dns_keystorelist_find(
|
||||
keystorelist, DNS_KEYSTORE_KEYDIRECTORY,
|
||||
&new_key->keystore);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, logctx, ISC_LOG_ERROR,
|
||||
"dnssec-policy: failed to "
|
||||
"find keystore (%s)",
|
||||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
dns_kasp_addkey(kasp, new_key);
|
||||
}
|
||||
}
|
||||
@ -655,3 +723,75 @@ cleanup:
|
||||
dns_kasp_detach(&kasp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
|
||||
isc_log_t *logctx, const char *engine,
|
||||
dns_keystorelist_t *keystorelist,
|
||||
dns_keystore_t **kspp) {
|
||||
isc_result_t result;
|
||||
const cfg_obj_t *maps[2];
|
||||
const cfg_obj_t *koptions = NULL;
|
||||
const char *name = NULL;
|
||||
const char *keydirectory = DNS_KEYSTORE_KEYDIRECTORY;
|
||||
dns_keystore_t *keystore = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (config != NULL) {
|
||||
name = cfg_obj_asstring(cfg_tuple_get(config, "name"));
|
||||
} else {
|
||||
name = keydirectory;
|
||||
}
|
||||
INSIST(name != NULL);
|
||||
|
||||
result = dns_keystorelist_find(keystorelist, name, &keystore);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
cfg_obj_log(config, logctx, ISC_LOG_ERROR,
|
||||
"key-store: duplicate key-store found '%s'", name);
|
||||
dns_keystore_detach(&keystore);
|
||||
return (ISC_R_EXISTS);
|
||||
}
|
||||
if (result != ISC_R_NOTFOUND) {
|
||||
cfg_obj_log(config, logctx, ISC_LOG_ERROR,
|
||||
"key-store: lookup '%s' failed: %s", name,
|
||||
isc_result_totext(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* No key-store with configured name was found in list, create new one.
|
||||
*/
|
||||
INSIST(keystore == NULL);
|
||||
result = dns_keystore_create(mctx, name, engine, &keystore);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
INSIST(keystore != NULL);
|
||||
|
||||
/* Now configure. */
|
||||
INSIST(DNS_KEYSTORE_VALID(keystore));
|
||||
|
||||
if (config != NULL) {
|
||||
koptions = cfg_tuple_get(config, "options");
|
||||
maps[i++] = koptions;
|
||||
maps[i] = NULL;
|
||||
dns_keystore_setdirectory(keystore,
|
||||
get_string(maps, "directory"));
|
||||
dns_keystore_setpkcs11uri(keystore,
|
||||
get_string(maps, "pkcs11-uri"));
|
||||
}
|
||||
|
||||
/* Append it to the list for future lookups. */
|
||||
ISC_LIST_APPEND(*keystorelist, keystore, link);
|
||||
INSIST(!(ISC_LIST_EMPTY(*keystorelist)));
|
||||
|
||||
/* Success: Attach the keystore to the pointer and return. */
|
||||
if (kspp != NULL) {
|
||||
INSIST(*kspp == NULL);
|
||||
dns_keystore_attach(keystore, kspp);
|
||||
}
|
||||
|
||||
/* Don't detach as keystore is on '*keystorelist' */
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ static cfg_type_t cfg_type_http_description;
|
||||
static cfg_type_t cfg_type_ixfrdifftype;
|
||||
static cfg_type_t cfg_type_ixfrratio;
|
||||
static cfg_type_t cfg_type_key;
|
||||
static cfg_type_t cfg_type_keystore;
|
||||
static cfg_type_t cfg_type_logfile;
|
||||
static cfg_type_t cfg_type_logging;
|
||||
static cfg_type_t cfg_type_logseverity;
|
||||
@ -477,7 +478,6 @@ static cfg_tuplefielddef_t dnssecpolicy_fields[] = {
|
||||
{ "options", &cfg_type_dnssecpolicyopts, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cfg_type_t cfg_type_dnssecpolicy = {
|
||||
"dnssec-policy", cfg_parse_tuple, cfg_print_tuple,
|
||||
cfg_doc_tuple, &cfg_rep_tuple, dnssecpolicy_fields
|
||||
@ -582,10 +582,58 @@ static cfg_type_t cfg_type_dnsseckeyrole = {
|
||||
/*%
|
||||
* DNSSEC key storage types.
|
||||
*/
|
||||
static const char *dnsseckeystore_enums[] = { "key-directory", NULL };
|
||||
static cfg_type_t cfg_type_dnsseckeystore = {
|
||||
"dnssec-key-storage", parse_optional_enum, cfg_print_ustring,
|
||||
doc_optional_enum, &cfg_rep_string, dnsseckeystore_enums
|
||||
static keyword_type_t keystore_kw = { "key-store", &cfg_type_astring };
|
||||
static cfg_type_t cfg_type_keystorage = { "keystorage", parse_keyvalue,
|
||||
print_keyvalue, doc_keyvalue,
|
||||
&cfg_rep_string, &keystore_kw };
|
||||
|
||||
static isc_result_t
|
||||
parse_keystore(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
||||
isc_result_t result;
|
||||
cfg_obj_t *obj = NULL;
|
||||
|
||||
UNUSED(type);
|
||||
|
||||
CHECK(cfg_peektoken(pctx, 0));
|
||||
if (pctx->token.type == isc_tokentype_string &&
|
||||
strcasecmp(TOKEN_STRING(pctx), "key-directory") == 0)
|
||||
{
|
||||
CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, &obj));
|
||||
} else if (pctx->token.type == isc_tokentype_string &&
|
||||
strcasecmp(TOKEN_STRING(pctx), "key-store") == 0)
|
||||
{
|
||||
CHECK(cfg_parse_obj(pctx, &cfg_type_keystorage, &obj));
|
||||
} else {
|
||||
CHECK(cfg_parse_void(pctx, NULL, &obj));
|
||||
}
|
||||
|
||||
*ret = obj;
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
doc_keystore(cfg_printer_t *pctx, const cfg_type_t *type) {
|
||||
UNUSED(type);
|
||||
|
||||
cfg_print_cstr(pctx, "[ key-directory | key-store <string> ]");
|
||||
}
|
||||
|
||||
static void
|
||||
print_keystore(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
||||
REQUIRE(pctx != NULL);
|
||||
REQUIRE(obj != NULL);
|
||||
REQUIRE(obj->type->rep == &cfg_rep_string);
|
||||
|
||||
if (strcasecmp(cfg_obj_asstring(obj), "key-directory") != 0) {
|
||||
cfg_print_cstr(pctx, "key-store ");
|
||||
}
|
||||
cfg_print_ustring(pctx, obj);
|
||||
}
|
||||
|
||||
static cfg_type_t cfg_type_optional_keystore = {
|
||||
"optionalkeystorage", parse_keystore, print_keystore,
|
||||
doc_keystore, &cfg_rep_string, &keystore_kw
|
||||
};
|
||||
|
||||
/*%
|
||||
@ -604,7 +652,7 @@ static cfg_type_t cfg_type_lifetime = { "lifetime", parse_keyvalue,
|
||||
|
||||
static cfg_tuplefielddef_t kaspkey_fields[] = {
|
||||
{ "role", &cfg_type_dnsseckeyrole, 0 },
|
||||
{ "keystore-type", &cfg_type_dnsseckeystore, 0 },
|
||||
{ "keystorage", &cfg_type_optional_keystore, 0 },
|
||||
{ "lifetime", &cfg_type_lifetime, 0 },
|
||||
{ "algorithm", &cfg_type_algorithm, 0 },
|
||||
{ "length", &cfg_type_optional_uint32, 0 },
|
||||
@ -1143,6 +1191,7 @@ static cfg_clausedef_t namedconf_clauses[] = {
|
||||
{ "http", &cfg_type_http_description,
|
||||
CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_NOTCONFIGURED },
|
||||
#endif
|
||||
{ "key-store", &cfg_type_keystore, CFG_CLAUSEFLAG_MULTI },
|
||||
{ "logging", &cfg_type_logging, 0 },
|
||||
{ "lwres", NULL, CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "masters", &cfg_type_remoteservers,
|
||||
@ -2549,6 +2598,30 @@ static cfg_type_t cfg_type_key = { "key", cfg_parse_named_map,
|
||||
cfg_print_map, cfg_doc_map,
|
||||
&cfg_rep_map, key_clausesets };
|
||||
|
||||
/*%
|
||||
* A key-store statement.
|
||||
*/
|
||||
static cfg_clausedef_t keystore_clauses[] = {
|
||||
{ "directory", &cfg_type_astring, 0 },
|
||||
{ "pkcs11-uri", &cfg_type_qstring, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cfg_clausedef_t *keystore_clausesets[] = { keystore_clauses, NULL };
|
||||
static cfg_type_t cfg_type_keystoreopts = {
|
||||
"keystoreopts", cfg_parse_map, cfg_print_map,
|
||||
cfg_doc_map, &cfg_rep_map, keystore_clausesets
|
||||
};
|
||||
|
||||
static cfg_tuplefielddef_t keystore_fields[] = {
|
||||
{ "name", &cfg_type_astring, 0 },
|
||||
{ "options", &cfg_type_keystoreopts, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
static cfg_type_t cfg_type_keystore = { "key-store", cfg_parse_tuple,
|
||||
cfg_print_tuple, cfg_doc_tuple,
|
||||
&cfg_rep_tuple, keystore_fields };
|
||||
|
||||
/*%
|
||||
* Clauses that can be found in a 'server' statement.
|
||||
*
|
||||
|
@ -315,8 +315,8 @@ ISC_RUN_TEST_IMPL(updatesigs_next) {
|
||||
result = dns_zone_setkeydirectory(zone, TESTS_DIR "/testkeys");
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns__zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS,
|
||||
zone_keys, &nkeys);
|
||||
result = dns_zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS,
|
||||
zone_keys, &nkeys);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_int_equal(nkeys, 2);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user