Fix dnssec-keygen key collision checking for KEY rrtype keys

When generating a new key, dnssec-keygen checks for possible
key ID collisions with existing keys. The dnssec.c:findmatchingkeys()
function, which is supposed to get the list of the existing keys,
fails to do that for the existing KEY rrtype keys (i.e. generated
using 'dnssec-keygen -T KEY') because it doesn't pass down to the
dst_key_fromnamedfile() -> dst_key_read_public() functions the type
of the keys it's interested in. Fix the issue by introducing a new
function parameter which tells in which type of keys the caller is
currently interested in.

(cherry picked from commit 49b7ce9a54)
This commit is contained in:
Aram Sargsyan 2025-10-02 12:52:12 +00:00 committed by Mark Andrews
parent 4dcb995aaa
commit 3a1922f464
11 changed files with 81 additions and 35 deletions

View file

@ -224,7 +224,7 @@ get_dnskeys(ksr_ctx_t *ksr, dns_dnsseckeylist_t *keys) {
ISC_LIST_INIT(*keys);
ISC_LIST_INIT(keys_read);
ret = dns_dnssec_findmatchingkeys(name, NULL, ksr->keydir, NULL,
ksr->now, mctx, &keys_read);
ksr->now, false, mctx, &keys_read);
if (ret != ISC_R_SUCCESS && ret != ISC_R_NOTFOUND) {
fatal("failed to load existing keys from %s: %s", ksr->keydir,
isc_result_totext(ret));

View file

@ -2852,7 +2852,7 @@ findkeys:
* Find keys that match this zone in the key repository.
*/
result = dns_dnssec_findmatchingkeys(gorigin, NULL, directory, NULL,
now, mctx, &matchkeys);
now, false, mctx, &matchkeys);
if (result == ISC_R_NOTFOUND) {
result = ISC_R_SUCCESS;
}

View file

@ -511,10 +511,17 @@ key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
}
ISC_LIST_INIT(matchkeys);
result = dns_dnssec_findmatchingkeys(name, NULL, dir, NULL, now, mctx,
&matchkeys);
bool keykey = false;
/*
* DNSKEY and KEY both use the same file names patterns so
* we have to look for both sets of keys.
*/
again:
result = dns_dnssec_findmatchingkeys(name, NULL, dir, NULL, now, keykey,
mctx, &matchkeys);
if (result == ISC_R_NOTFOUND) {
return false;
goto try_key;
}
while (!ISC_LIST_EMPTY(matchkeys) && !conflict) {
@ -558,6 +565,11 @@ key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
dns_dnsseckey_destroy(mctx, &key);
}
try_key:
if (!conflict && !keykey) {
keykey = true;
goto again;
}
return conflict;
}

View file

@ -108,7 +108,7 @@ void
set_keyversion(dst_key_t *key);
bool
key_collision(dst_key_t *key, dns_name_t *name, const char *dir,
key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
isc_mem_t *mctx, uint16_t min, uint16_t max, bool *exact);
bool

View file

@ -1199,12 +1199,12 @@ dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
}
static isc_result_t
findmatchingkeys(const char *directory, char *namebuf, unsigned int len,
isc_mem_t *mctx, isc_stdtime_t now,
findmatchingkeys(const char *directory, bool rrtypekey, char *namebuf,
unsigned int len, isc_mem_t *mctx, isc_stdtime_t now,
dns_dnsseckeylist_t *list) {
isc_result_t result = ISC_R_SUCCESS;
isc_result_t result;
isc_dir_t dir;
bool dir_open = false;
bool dir_open = false, match = false;
unsigned int i, alg;
dns_dnsseckey_t *key = NULL;
dst_key_t *dstkey = NULL;
@ -1213,6 +1213,7 @@ findmatchingkeys(const char *directory, char *namebuf, unsigned int len,
if (directory == NULL) {
directory = ".";
}
RETERR(isc_dir_open(&dir, directory));
dir_open = true;
@ -1261,11 +1262,13 @@ findmatchingkeys(const char *directory, char *namebuf, unsigned int len,
continue;
}
int type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE;
if (rrtypekey) {
type |= DST_TYPE_KEY;
}
dstkey = NULL;
result = dst_key_fromnamedfile(
dir.entry.name, directory,
DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE,
mctx, &dstkey);
result = dst_key_fromnamedfile(dir.entry.name, directory, type,
mctx, &dstkey);
switch (alg) {
case DST_ALG_HMACMD5:
@ -1297,9 +1300,11 @@ findmatchingkeys(const char *directory, char *namebuf, unsigned int len,
dns_dnsseckey_destroy(mctx, &key);
} else {
ISC_LIST_APPEND(*list, key, link);
match = true;
key = NULL;
}
}
result = match ? ISC_R_SUCCESS : ISC_R_NOTFOUND;
failure:
if (dir_open) {
@ -1312,12 +1317,13 @@ failure:
}
/*%
* Get a list of DNSSEC keys from the key repository.
* Get a list of KEY or DNSKEY keys from the key repository. If rrtypekey
* is true KEY keys will be returned otherwise DNSSEC keys.
*/
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,
isc_stdtime_t now, bool rrtypekey, isc_mem_t *mctx,
dns_dnsseckeylist_t *keylist) {
isc_result_t result = ISC_R_SUCCESS;
dns_dnsseckeylist_t list;
@ -1337,8 +1343,8 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
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));
RETERR(findmatchingkeys(keydir, rrtypekey, 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))
@ -1352,8 +1358,8 @@ dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
dns_keystore_directory(keystore,
keydir);
RETERR(findmatchingkeys(
directory, namebuf, len, mctx,
now, &list));
directory, rrtypekey, namebuf,
len, mctx, now, &list));
break;
}
}

View file

@ -285,13 +285,16 @@ dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now);
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,
isc_stdtime_t now, bool rrtypekey, isc_mem_t *mctx,
dns_dnsseckeylist_t *keylist);
/*%<
* 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'.
*
* If 'rrtypekey' is true, then KEY type keys are matched (e.g. for SIG(0)),
* otherwise DNSKEY type keys are matched for DNSSEC.
*
* Append all such keys, along with use hints gleaned from their
* metadata, onto 'keylist'. Skip any unsupported algorithms.
*

View file

@ -500,7 +500,8 @@ static isc_result_t
keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
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_stdtime_t now, dns_dnsseckeylist_t *newkeys,
dst_key_t **dst_key) {
isc_result_t result = ISC_R_SUCCESS;
bool conflict = false;
int flags = DNS_KEYOWNER_ZONE;
@ -509,11 +510,23 @@ keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
dns_keystore_t *keystore = dns_kasp_key_keystore(kkey);
const char *dir = NULL;
int size = dns_kasp_key_size(kkey);
dns_dnsseckeylist_t keykeys;
ISC_LIST_INIT(keykeys);
if (dns_kasp_key_ksk(kkey)) {
flags |= DNS_KEYFLAG_KSK;
}
/*
* We also need to check against K* files for KEYs.
*/
result = dns_dnssec_findmatchingkeys(origin, NULL, keydir, NULL, now,
true, mctx, &keykeys);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto failure;
}
do {
if (keystore == NULL) {
RETERR(dst_key_generate(origin, alg, size, 0, flags,
@ -528,6 +541,10 @@ keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
/* Key collision? */
conflict = keymgr_keyid_conflict(newkey, kkey->tag_min,
kkey->tag_max, keylist);
if (!conflict) {
conflict = keymgr_keyid_conflict(
newkey, kkey->tag_min, kkey->tag_max, &keykeys);
}
if (!conflict) {
conflict = keymgr_keyid_conflict(
newkey, kkey->tag_min, kkey->tag_max, newkeys);
@ -552,9 +569,14 @@ keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
dst_key_setdirectory(newkey, dir);
}
*dst_key = newkey;
return ISC_R_SUCCESS;
result = ISC_R_SUCCESS;
failure:
while (!ISC_LIST_EMPTY(keykeys)) {
dns_dnsseckey_t *key = ISC_LIST_HEAD(keykeys);
ISC_LIST_UNLINK(keykeys, key, link);
dns_dnsseckey_destroy(mctx, &key);
}
return result;
}
@ -1945,9 +1967,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, kasp, rdclass, mctx,
keydir, keyring, newkeys, &dst_key);
isc_result_t result = keymgr_createkey(
kaspkey, origin, kasp, rdclass, mctx, keydir, keyring,
now, newkeys, &dst_key);
if (result != ISC_R_SUCCESS) {
return result;
}

View file

@ -1068,8 +1068,8 @@ find_zone_keys(dns_zone_t *zone, isc_mem_t *mctx, unsigned int maxkeys,
dns_zone_lock_keyfiles(zone);
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), kasp,
keydir, keystores, now, mctx,
&keylist);
keydir, keystores, now, false,
mctx, &keylist);
dns_zone_unlock_keyfiles(zone);
if (result != ISC_R_SUCCESS) {

View file

@ -6590,7 +6590,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, kasp, dir, zone->keystores,
now, dns_zone_getmctx(zone), keys);
now, false, dns_zone_getmctx(zone),
keys);
dns_zone_unlock_keyfiles(zone);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
@ -16596,8 +16597,8 @@ dns_zone_dnskey_inuse(dns_zone_t *zone, dns_rdata_t *rdata, bool *inuse) {
dns_zone_lock_keyfiles(zone);
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone), kasp,
keydir, keystores, now, mctx,
&keylist);
keydir, keystores, now, false,
mctx, &keylist);
dns_zone_unlock_keyfiles(zone);
if (result == ISC_R_NOTFOUND) {
return ISC_R_SUCCESS;
@ -22622,7 +22623,8 @@ zone_rekey(dns_zone_t *zone) {
dns_zone_lock_keyfiles(zone);
result = dns_dnssec_findmatchingkeys(&zone->origin, kasp, dir,
zone->keystores, now, mctx, &keys);
zone->keystores, now, false, mctx,
&keys);
dns_zone_unlock_keyfiles(zone);
if (result != ISC_R_SUCCESS) {

View file

@ -3174,7 +3174,7 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
ISC_LIST_INIT(keys);
ret = dns_dnssec_findmatchingkeys(origin, kasp, keydir, &kslist,
now, mctx, &keys);
now, false, mctx, &keys);
if (ret != ISC_R_SUCCESS) {
result = ret;
}

View file

@ -453,8 +453,9 @@ ISC_RUN_TEST_IMPL(skr_read) {
/* Get the KSK */
ISC_LIST_INIT(keys);
result = dns_dnssec_findmatchingkeys(
dname, NULL, TESTS_DIR "/testdata/skr/", NULL, 0, mctx, &keys);
result = dns_dnssec_findmatchingkeys(dname, NULL,
TESTS_DIR "/testdata/skr/", NULL,
0, false, mctx, &keys);
assert_int_equal(result, ISC_R_SUCCESS);
/* Create/read the SKR file */