2
0
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:
Matthijs Mekking 2024-01-25 16:31:59 +00:00
commit b51d8f2c5d
66 changed files with 3233 additions and 543 deletions

View File

@ -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"

View File

@ -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]

View File

@ -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));

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);

View 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";
};
};

View 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";
};
};

View 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";
};
};

View 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";
};
};

View 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;
};
};

View 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";
};
};

View 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";
};
};

View 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;
};
};

View File

@ -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";
};

View File

@ -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;

View File

@ -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)"

View File

@ -18,6 +18,10 @@ options {
directory ".";
};
key-store "test" {
directory "test.keystoredir";
};
zone dummy {
type primary;
file "xxxx";

View File

@ -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"

View File

@ -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";
};

View File

@ -0,0 +1 @@
@ENGINE_ARGS@ -D enginepkcs11-ns2 -m record -c named.conf -d 99 -U 4 -T maxcachesize=2097152

View 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";
};

View 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"

View File

@ -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

View File

@ -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

View File

@ -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()"

View File

@ -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)"

View File

@ -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/

View File

@ -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.
*/

View File

@ -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@;
};
};

View File

@ -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

View File

@ -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.
#

View File

@ -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))

View File

@ -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.

View File

@ -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.

View File

@ -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> {

View File

@ -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
~~~~~~~~~~~~~~~~

View File

@ -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 \

View File

@ -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];

View File

@ -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);
}

View File

@ -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 {

View File

@ -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

View File

@ -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);
/*%<

View File

@ -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

View 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

View File

@ -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;

View File

@ -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);

View File

@ -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);
/*$<

View File

@ -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);

View File

@ -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 */

View File

@ -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
View 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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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.
*

View File

@ -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);