From a035f3b10ee0818dec2db773bb0b1f0955d844c0 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 20 Jan 2022 14:00:27 +0100 Subject: [PATCH] Add configuration for key-store Add new configuration for setting key stores. The new 'key-store' statement allows users to configure key store backends. These can be of type 'file' (that works the same as 'key-directory') or of type 'pkcs11'. In the latter case, keys should be stored in a HSM that is accessible through a PKCS#11 interface. Keys configured within 'dnssec-policy' can now also use the 'key-store' option to set a specific key store. Update the checkconf test to accomodate for the new configuration. --- bin/tests/system/checkconf/good-kasp.conf | 6 +- bin/tests/system/checkconf/good.conf.in | 8 ++- doc/misc/options | 7 +- lib/isccfg/namedconf.c | 84 +++++++++++++++++++++-- 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/bin/tests/system/checkconf/good-kasp.conf b/bin/tests/system/checkconf/good-kasp.conf index d5da98fc6d..40b5793ad0 100644 --- a/bin/tests/system/checkconf/good-kasp.conf +++ b/bin/tests/system/checkconf/good-kasp.conf @@ -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 "."; + uri "pkcs11:token=bind9;pin-value=1234"; +}; options { dnssec-policy "default"; }; diff --git a/bin/tests/system/checkconf/good.conf.in b/bin/tests/system/checkconf/good.conf.in index 7d1f6b8576..b39b20941a 100644 --- a/bin/tests/system/checkconf/good.conf.in +++ b/bin/tests/system/checkconf/good.conf.in @@ -24,8 +24,8 @@ 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; + 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 "."; + uri "pkcs11:token=bind9;pin-value=1234"; +}; options { avoid-v4-udp-ports { 100; diff --git a/doc/misc/options b/doc/misc/options index edf6fb04af..bde27bd36d 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -15,7 +15,7 @@ dnssec-policy { cds-digest-types { ; ... }; dnskey-ttl ; inline-signing ; - keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime algorithm [ ]; ... }; + keys { ( csk | ksk | zsk ) [ key-directory | key-store ] lifetime algorithm [ ]; ... }; max-zone-ttl ; nsec3param [ iterations ] [ optout ] [ salt-length ]; parent-ds-ttl ; @@ -42,6 +42,11 @@ key { secret ; }; // may occur multiple times +key-store { + directory ; + uri ; +}; // may occur multiple times + logging { category { ; ... }; // may occur multiple times channel { diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 625edc7f4f..216eebce30 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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 ]"); +} + +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,29 @@ 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 }, + { "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. *