diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c index e3542df49f..55ecec9e87 100644 --- a/bin/dnssec/dnssec-keygen.c +++ b/bin/dnssec/dnssec-keygen.c @@ -255,7 +255,7 @@ 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 *engine, dns_kasp_t **kaspp) { isc_result_t result = ISC_R_NOTFOUND; const cfg_listelt_t *element; const cfg_obj_t *kasps = NULL; @@ -274,8 +274,8 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name, { cfg_obj_t *kconfig = cfg_listelt_value(element); ks = NULL; - result = cfg_keystore_fromconfig(kconfig, mctx, lctx, &kslist, - &ks); + result = cfg_keystore_fromconfig(kconfig, mctx, lctx, engine, + &kslist, &ks); if (result != ISC_R_SUCCESS) { fatal("failed to configure key-store '%s': %s", cfg_obj_asstring(cfg_tuple_get(kconfig, "name")), @@ -1305,7 +1305,7 @@ main(int argc, char **argv) { ctx.policy, ctx.configfile); } - kasp_from_conf(config, mctx, ctx.policy, &kasp); + kasp_from_conf(config, mctx, ctx.policy, engine, &kasp); if (kasp == NULL) { fatal("failed to load dnssec-policy '%s'", ctx.policy); diff --git a/configure.ac b/configure.ac index 92f40c17ac..3631772b14 100644 --- a/configure.ac +++ b/configure.ac @@ -644,7 +644,6 @@ AS_IF([test "$enable_doh" = "yes"], AM_CONDITIONAL([HAVE_LIBNGHTTP2], [test -n "$LIBNGHTTP2_LIBS"]) - # # flockfile is usually provided by pthreads # diff --git a/lib/dns/include/dns/keystore.h b/lib/dns/include/dns/keystore.h index a5d5840aa1..bd486e541e 100644 --- a/lib/dns/include/dns/keystore.h +++ b/lib/dns/include/dns/keystore.h @@ -31,6 +31,8 @@ #include +#include + ISC_LANG_BEGINDECLS /* Key store */ @@ -60,7 +62,8 @@ struct dns_keystore { #define DNS_KEYSTORE_KEYDIRECTORY "key-directory" isc_result_t -dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp); +dns_keystore_create(isc_mem_t *mctx, const char *name, const char *engine, + dns_keystore_t **kspp); /*%< * Create a key store. * @@ -70,6 +73,8 @@ dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp); * *\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: @@ -126,6 +131,20 @@ dns_keystore_name(dns_keystore_t *keystore); *\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); /*%< @@ -176,6 +195,25 @@ dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri); * */ +isc_result_t +dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin, + 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 '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); diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c index 2327f89064..027965fef4 100644 --- a/lib/dns/keymgr.c +++ b/lib/dns/keymgr.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -446,21 +447,28 @@ 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; 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); + 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, rdclass, + mctx, alg, size, flags, + &newkey)); } - RETERR(dst_key_generate(origin, algo, size, 0, keyflags, - DNS_KEYPROTO_DNSSEC, rdclass, NULL, - mctx, &newkey, NULL)); /* Key collision? */ conflict = keymgr_keyid_conflict(newkey, keylist); @@ -1989,8 +1997,10 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, 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); diff --git a/lib/dns/keystore.c b/lib/dns/keystore.c index e7fac0ab62..c57c712a7a 100644 --- a/lib/dns/keystore.c +++ b/lib/dns/keystore.c @@ -13,11 +13,6 @@ /*! \file */ -#ifdef HAVE_GNUTLS -#include -#include -#endif - #include #include @@ -26,15 +21,18 @@ #include #include +#include isc_result_t -dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp) { +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); @@ -65,6 +63,8 @@ dns_keystore_attach(dns_keystore_t *source, dns_keystore_t **targetp) { static inline void destroy(dns_keystore_t *keystore) { + char *name; + REQUIRE(!ISC_LINK_LINKED(keystore, link)); isc_mutex_destroy(&keystore->lock); @@ -98,6 +98,13 @@ dns_keystore_name(dns_keystore_t *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) { REQUIRE(DNS_KEYSTORE_VALID(keystore)); @@ -136,6 +143,80 @@ dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri) { : isc_mem_strdup(keystore->mctx, uri); } +isc_result_t +dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin, + 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(mctx != NULL); + REQUIRE(dstkey != NULL && *dstkey == NULL); + + uri = dns_keystore_pkcs11uri(keystore); + if (uri != NULL) { + dst_key_t *key = NULL; + char *label = NULL; + size_t len; + char timebuf[18]; + isc_time_t now = isc_time_now(); + bool ksk = ((flags & DNS_KEYFLAG_KSK) != 0); + char namebuf[DNS_NAME_FORMATSIZE]; + char object[DNS_NAME_FORMATSIZE + 26]; + + /* Generate the key */ + isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf)); + dns_name_format(origin, namebuf, sizeof(namebuf)); + snprintf(object, sizeof(object), "%s-%s-%s", namebuf, + ksk ? "ksk" : "zsk", timebuf); + + result = dst_key_generate(origin, alg, size, 0, flags, + DNS_KEYPROTO_DNSSEC, rdclass, object, + mctx, &key, NULL); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR, + "keystore: failed to generate key " + "%s (ret=%d)", + object, result); + return (result); + } + dst_key_free(&key); + + /* Retrieve generated key from label */ + len = strlen(object) + strlen(uri) + 10; + label = isc_mem_get(mctx, len); + sprintf(label, "%s;object=%s;", uri, object); + result = dst_key_fromlabel( + origin, alg, flags, DNS_KEYPROTO_DNSSEC, + dns_rdataclass_in, dns_keystore_engine(keystore), label, + NULL, mctx, &newkey); + + isc_mem_put(mctx, label, len); + + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR, + "keystore: failed to access key " + "%s (ret=%d)", + object, result); + return (result); + } + } 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) { diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index b54e43ade3..4b8740b8d7 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -410,13 +410,85 @@ 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_object(int group_nid, const char *object, + EVP_PKEY **retkey) { + int status; + isc_result_t ret; + unsigned char id[16]; + char *label = UNCONST(object); + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM params[3]; + + /* Generate the key's parameters. */ + status = RAND_bytes(id, 16); + if (status != 1) { + DST_RET(dst__openssl_toresult2("RAND_bytes", + DST_R_OPENSSLFAILURE)); + } + + params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_key_label", label, + 0); + params[1] = OSSL_PARAM_construct_octet_string("pkcs11_key_id", id, 16); + 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 *object, + 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 (object != NULL) { + return (opensslecdsa_generate_pkey_with_object(group_nid, + object, retkey)); + } + /* Generate the key's parameters. */ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); if (ctx == NULL) { @@ -498,11 +570,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 *object, + 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(object); + + group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); eckey = EC_KEY_new_by_curve_name(group_nid); if (eckey == NULL) { @@ -815,7 +892,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->object, &pkey); if (ret != ISC_R_SUCCESS) { return (ret); } diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 4c264c183a..6d06c71f27 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -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 *object, 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(object); + + rsa = RSA_new(); + pkey = EVP_PKEY_new(); if (rsa == NULL || pkey == NULL) { DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); } @@ -493,11 +497,69 @@ progress_cb(EVP_PKEY_CTX *ctx) { } static isc_result_t -opensslrsa_generate_pkey(unsigned int key_size, BIGNUM *e, +opensslrsa_generate_pkey_with_object(size_t key_size, const char *object, + EVP_PKEY **retkey) { + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM params[4]; + unsigned char id[16]; + char *label = UNCONST(object); + isc_result_t ret; + int status; + + status = RAND_bytes(id, 16); + if (status != 1) { + DST_RET(dst__openssl_toresult2("RAND_bytes", + DST_R_OPENSSLFAILURE)); + } + + params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_key_label", label, + 0); + params[1] = OSSL_PARAM_construct_octet_string("pkcs11_key_id", id, 16); + 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 *object, 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 (object != NULL) { + return (opensslrsa_generate_pkey_with_object(key_size, object, + retkey)); + } + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); if (ctx == NULL) { DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); } @@ -669,7 +731,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->object, e, callback, + &pkey); if (ret != ISC_R_SUCCESS) { goto err; } diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index fb8012cf53..c00c588845 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -1412,8 +1412,9 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, } } - ret = cfg_keystore_fromconfig( - kconfig, mctx, logctx, &kslist, &ks); + ret = cfg_keystore_fromconfig(kconfig, mctx, + logctx, NULL, + &kslist, &ks); if (ret != ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) { result = ret; @@ -1429,7 +1430,8 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config, /* * Add default key-store "key-directory". */ - tresult = cfg_keystore_fromconfig(NULL, mctx, logctx, &kslist, &ks); + tresult = cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist, + &ks); if (tresult != ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) { result = tresult; @@ -2961,12 +2963,13 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig, { cfg_obj_t *kcfg = cfg_listelt_value(element); ks = NULL; - (void)cfg_keystore_fromconfig(kcfg, mctx, logctx, &kslist, &ks); + (void)cfg_keystore_fromconfig(kcfg, mctx, logctx, NULL, &kslist, + &ks); INSIST(ks != NULL); dns_keystore_detach(&ks); } ks = NULL; - (void)cfg_keystore_fromconfig(NULL, mctx, logctx, &kslist, &ks); + (void)cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist, &ks); INSIST(ks != NULL); dns_keystore_detach(&ks); diff --git a/lib/isccfg/include/isccfg/kaspconf.h b/lib/isccfg/include/isccfg/kaspconf.h index 6f40fab072..1bc727d89c 100644 --- a/lib/isccfg/include/isccfg/kaspconf.h +++ b/lib/isccfg/include/isccfg/kaspconf.h @@ -62,7 +62,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp, isc_result_t cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, - isc_log_t *logctx, dns_keystorelist_t *keystorelist, + 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 diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 9598864ef2..9bd4ebb3e9 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -726,7 +726,8 @@ cleanup: isc_result_t cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, - isc_log_t *logctx, dns_keystorelist_t *keystorelist, + 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]; @@ -764,7 +765,7 @@ cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx, * No key-store with configured name was found in list, create new one. */ INSIST(keystore == NULL); - result = dns_keystore_create(mctx, name, &keystore); + result = dns_keystore_create(mctx, name, engine, &keystore); if (result != ISC_R_SUCCESS) { return (result); }