mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 08:50:00 -04:00
chg: usr: dnssec-ksr now supports KSK rollovers
The tool 'dnssec-ksr' now allows for KSK generation, as well as planned KSK rollovers. When signing a bundle from a Key Signing Request (KSR), only the key that is active in that time frame is being used for signing. Also, the CDS and CDNSKEY records are now added and removed at the correct time. Closes #4697 Closes #4705 Merge branch '4705-dnssec-ksr-only-sign-with-active-ksks' into 'main' See merge request isc-projects/bind9!9452
This commit is contained in:
commit
675a7f0166
8 changed files with 462 additions and 154 deletions
|
|
@ -25,6 +25,7 @@
|
|||
#include <dns/callbacks.h>
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/keymgr.h>
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rdatalist.h>
|
||||
|
|
@ -61,16 +62,19 @@ struct ksr_ctx {
|
|||
bool setstart;
|
||||
bool setend;
|
||||
/* keygen */
|
||||
bool ksk;
|
||||
dns_ttl_t ttl;
|
||||
dns_secalg_t alg;
|
||||
int size;
|
||||
time_t lifetime;
|
||||
time_t parentpropagation;
|
||||
time_t propagation;
|
||||
time_t publishsafety;
|
||||
time_t retiresafety;
|
||||
time_t sigrefresh;
|
||||
time_t sigvalidity;
|
||||
time_t signdelay;
|
||||
time_t ttlds;
|
||||
time_t ttlsig;
|
||||
};
|
||||
typedef struct ksr_ctx ksr_ctx_t;
|
||||
|
|
@ -139,6 +143,15 @@ usage(int ret) {
|
|||
exit(ret);
|
||||
}
|
||||
|
||||
static isc_stdtime_t
|
||||
between(isc_stdtime_t t, isc_stdtime_t start, isc_stdtime_t end) {
|
||||
isc_stdtime_t r = end;
|
||||
if (t > 0 && t > start && t < end) {
|
||||
r = t;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
static void
|
||||
checkparams(ksr_ctx_t *ksr, const char *command) {
|
||||
if (ksr->configfile == NULL) {
|
||||
|
|
@ -239,6 +252,7 @@ get_dnskeys(ksr_ctx_t *ksr, dns_dnsseckeylist_t *keys) {
|
|||
|
||||
static void
|
||||
setcontext(ksr_ctx_t *ksr, dns_kasp_t *kasp) {
|
||||
ksr->parentpropagation = dns_kasp_parentpropagationdelay(kasp);
|
||||
ksr->propagation = dns_kasp_zonepropagationdelay(kasp);
|
||||
ksr->publishsafety = dns_kasp_publishsafety(kasp);
|
||||
ksr->retiresafety = dns_kasp_retiresafety(kasp);
|
||||
|
|
@ -246,6 +260,7 @@ setcontext(ksr_ctx_t *ksr, dns_kasp_t *kasp) {
|
|||
ksr->sigrefresh = dns_kasp_sigrefresh(kasp);
|
||||
ksr->signdelay = dns_kasp_signdelay(kasp);
|
||||
ksr->ttl = dns_kasp_dnskeyttl(kasp);
|
||||
ksr->ttlds = dns_kasp_dsttl(kasp);
|
||||
ksr->ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||
}
|
||||
|
||||
|
|
@ -313,9 +328,9 @@ freerrset(dns_rdataset_t *rdataset) {
|
|||
}
|
||||
|
||||
static void
|
||||
create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
||||
isc_stdtime_t inception, isc_stdtime_t active,
|
||||
isc_stdtime_t *expiration) {
|
||||
create_key(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_kasp_key_t *kaspkey,
|
||||
dns_dnsseckeylist_t *keys, isc_stdtime_t inception,
|
||||
isc_stdtime_t active, isc_stdtime_t *expiration) {
|
||||
bool conflict = false;
|
||||
bool freekey = false;
|
||||
bool show_progress = true;
|
||||
|
|
@ -327,9 +342,15 @@ create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
|||
isc_buffer_t buf;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t prepub;
|
||||
uint16_t flags = DNS_KEYOWNER_ZONE;
|
||||
|
||||
isc_stdtime_tostring(inception, timestr, sizeof(timestr));
|
||||
|
||||
/* ZSK or KSK? */
|
||||
if (ksr->ksk) {
|
||||
flags |= DNS_KEYFLAG_KSK;
|
||||
}
|
||||
|
||||
/* Check algorithm and size. */
|
||||
dns_secalg_format(ksr->alg, algstr, sizeof(algstr));
|
||||
if (!dst_algorithm_supported(ksr->alg)) {
|
||||
|
|
@ -420,18 +441,18 @@ create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
|||
ret = dns_keystore_keygen(
|
||||
ksr->keystore, name, ksr->policy,
|
||||
dns_rdataclass_in, mctx, ksr->alg, ksr->size,
|
||||
DNS_KEYOWNER_ZONE, &key);
|
||||
flags, &key);
|
||||
} else if (show_progress) {
|
||||
ret = dst_key_generate(
|
||||
name, ksr->alg, ksr->size, 0, DNS_KEYOWNER_ZONE,
|
||||
DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, NULL,
|
||||
mctx, &key, &progress);
|
||||
ret = dst_key_generate(name, ksr->alg, ksr->size, 0,
|
||||
flags, DNS_KEYPROTO_DNSSEC,
|
||||
dns_rdataclass_in, NULL, mctx,
|
||||
&key, &progress);
|
||||
fflush(stderr);
|
||||
} else {
|
||||
ret = dst_key_generate(
|
||||
name, ksr->alg, ksr->size, 0, DNS_KEYOWNER_ZONE,
|
||||
DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, NULL,
|
||||
mctx, &key, NULL);
|
||||
ret = dst_key_generate(name, ksr->alg, ksr->size, 0,
|
||||
flags, DNS_KEYPROTO_DNSSEC,
|
||||
dns_rdataclass_in, NULL, mctx,
|
||||
&key, NULL);
|
||||
}
|
||||
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
|
|
@ -468,15 +489,28 @@ create_zsk(ksr_ctx_t *ksr, dns_kasp_key_t *kaspkey, dns_dnsseckeylist_t *keys,
|
|||
prepub = ksr->ttl + ksr->publishsafety + ksr->propagation;
|
||||
dst_key_setttl(key, ksr->ttl);
|
||||
dst_key_setnum(key, DST_NUM_LIFETIME, ksr->lifetime);
|
||||
dst_key_setbool(key, DST_BOOL_KSK, false);
|
||||
dst_key_setbool(key, DST_BOOL_ZSK, true);
|
||||
dst_key_setbool(key, DST_BOOL_KSK, ksr->ksk);
|
||||
dst_key_setbool(key, DST_BOOL_ZSK, !ksr->ksk);
|
||||
dst_key_settime(key, DST_TIME_CREATED, ksr->now);
|
||||
dst_key_settime(key, DST_TIME_PUBLISH, (active - prepub));
|
||||
dst_key_settime(key, DST_TIME_ACTIVATE, active);
|
||||
if (ksr->ksk) {
|
||||
dns_keymgr_settime_syncpublish(key, kasp,
|
||||
(inception == ksr->start));
|
||||
}
|
||||
|
||||
if (ksr->lifetime > 0) {
|
||||
isc_stdtime_t inactive = (active + ksr->lifetime);
|
||||
isc_stdtime_t remove = ksr->ttlsig + ksr->propagation +
|
||||
ksr->retiresafety + ksr->signdelay;
|
||||
isc_stdtime_t remove;
|
||||
|
||||
if (ksr->ksk) {
|
||||
remove = ksr->ttlds + ksr->parentpropagation +
|
||||
ksr->retiresafety;
|
||||
dst_key_settime(key, DST_TIME_SYNCDELETE, inactive);
|
||||
} else {
|
||||
remove = ksr->ttlsig + ksr->propagation +
|
||||
ksr->retiresafety + ksr->signdelay;
|
||||
}
|
||||
dst_key_settime(key, DST_TIME_INACTIVE, inactive);
|
||||
dst_key_settime(key, DST_TIME_DELETE, (inactive + remove));
|
||||
*expiration = inactive;
|
||||
|
|
@ -610,12 +644,13 @@ fail:
|
|||
return (next_bundle);
|
||||
}
|
||||
|
||||
static void
|
||||
static isc_stdtime_t
|
||||
sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration,
|
||||
dns_rdataset_t *rrset, dns_dnsseckeylist_t *keys) {
|
||||
dns_rdatalist_t *rrsiglist = NULL;
|
||||
dns_rdataset_t rrsigset = DNS_RDATASET_INIT;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t next_bundle = expiration;
|
||||
|
||||
UNUSED(ksr);
|
||||
|
||||
|
|
@ -659,6 +694,25 @@ sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration,
|
|||
unsigned char rdatabuf[SIG_FORMATSIZE];
|
||||
isc_stdtime_t clockskew = inception - 3600;
|
||||
|
||||
isc_stdtime_t pub = 0, act = 0, inact = 0, del = 0;
|
||||
|
||||
/* Determine next bundle. */
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_PUBLISH, &pub);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_ACTIVATE, &act);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_INACTIVE, &inact);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_DELETE, &del);
|
||||
next_bundle = between(pub, inception, next_bundle);
|
||||
next_bundle = between(act, inception, next_bundle);
|
||||
next_bundle = between(inact, inception, next_bundle);
|
||||
next_bundle = between(del, inception, next_bundle);
|
||||
|
||||
if (act > inception) {
|
||||
continue;
|
||||
}
|
||||
if (inact != 0 && inception >= inact) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rrsig = isc_mem_get(mctx, sizeof(*rrsig));
|
||||
dns_rdata_init(rrsig);
|
||||
isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
|
||||
|
|
@ -680,21 +734,25 @@ sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration,
|
|||
dns_rdatalist_tordataset(rrsiglist, &rrsigset);
|
||||
print_rdata(&rrsigset);
|
||||
freerrset(&rrsigset);
|
||||
|
||||
return (next_bundle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the DNSKEY, CDS, and CDNSKEY records beloing to the KSKs
|
||||
* listed in 'keys'.
|
||||
*/
|
||||
static void
|
||||
create_ksk(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys,
|
||||
dns_rdataset_t *dnskeyset, dns_rdataset_t *cdnskeyset,
|
||||
dns_rdataset_t *cdsset) {
|
||||
static isc_stdtime_t
|
||||
get_keymaterial(ksr_ctx_t *ksr, dns_kasp_t *kasp, isc_stdtime_t inception,
|
||||
isc_stdtime_t next_inception, dns_dnsseckeylist_t *keys,
|
||||
dns_rdataset_t *dnskeyset, dns_rdataset_t *cdnskeyset,
|
||||
dns_rdataset_t *cdsset) {
|
||||
dns_kasp_digestlist_t digests = dns_kasp_digests(kasp);
|
||||
dns_rdatalist_t *dnskeylist = isc_mem_get(mctx, sizeof(*dnskeylist));
|
||||
dns_rdatalist_t *cdnskeylist = isc_mem_get(mctx, sizeof(*cdnskeylist));
|
||||
dns_rdatalist_t *cdslist = isc_mem_get(mctx, sizeof(*cdslist));
|
||||
isc_result_t ret = ISC_R_SUCCESS;
|
||||
dns_kasp_digestlist_t digests = dns_kasp_digests(kasp);
|
||||
isc_stdtime_t next_bundle = next_inception;
|
||||
|
||||
dns_rdatalist_init(dnskeylist);
|
||||
dnskeylist->rdclass = dns_rdataclass_in;
|
||||
|
|
@ -714,31 +772,73 @@ create_ksk(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys,
|
|||
for (dns_dnsseckey_t *dk = ISC_LIST_HEAD(*keys); dk != NULL;
|
||||
dk = ISC_LIST_NEXT(dk, link))
|
||||
{
|
||||
bool published = true;
|
||||
isc_buffer_t buf;
|
||||
isc_buffer_t *newbuf;
|
||||
dns_rdata_t *rdata;
|
||||
isc_region_t r;
|
||||
isc_region_t rcds;
|
||||
isc_stdtime_t pub = 0, del = 0;
|
||||
unsigned char kskbuf[DST_KEY_MAXSIZE];
|
||||
unsigned char cdnskeybuf[DST_KEY_MAXSIZE];
|
||||
unsigned char cdsbuf[DNS_DS_BUFFERSIZE];
|
||||
|
||||
/* KSK */
|
||||
newbuf = NULL;
|
||||
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
||||
dns_rdata_init(rdata);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_PUBLISH, &pub);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_DELETE, &del);
|
||||
next_bundle = between(pub, inception, next_bundle);
|
||||
next_bundle = between(del, inception, next_bundle);
|
||||
|
||||
isc_buffer_init(&buf, kskbuf, sizeof(kskbuf));
|
||||
CHECK(dst_key_todns(dk->key, &buf));
|
||||
isc_buffer_usedregion(&buf, &r);
|
||||
isc_buffer_allocate(mctx, &newbuf, r.length);
|
||||
isc_buffer_putmem(newbuf, r.base, r.length);
|
||||
isc_buffer_usedregion(newbuf, &r);
|
||||
dns_rdata_fromregion(rdata, dns_rdataclass_in,
|
||||
dns_rdatatype_dnskey, &r);
|
||||
ISC_LIST_APPEND(dnskeylist->rdata, rdata, link);
|
||||
ISC_LIST_APPEND(cleanup_list, newbuf, link);
|
||||
isc_buffer_clear(newbuf);
|
||||
if (pub > inception) {
|
||||
published = false;
|
||||
}
|
||||
if (del != 0 && inception >= del) {
|
||||
published = false;
|
||||
}
|
||||
|
||||
if (published) {
|
||||
newbuf = NULL;
|
||||
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
||||
dns_rdata_init(rdata);
|
||||
|
||||
isc_buffer_init(&buf, kskbuf, sizeof(kskbuf));
|
||||
CHECK(dst_key_todns(dk->key, &buf));
|
||||
isc_buffer_usedregion(&buf, &r);
|
||||
isc_buffer_allocate(mctx, &newbuf, r.length);
|
||||
isc_buffer_putmem(newbuf, r.base, r.length);
|
||||
isc_buffer_usedregion(newbuf, &r);
|
||||
dns_rdata_fromregion(rdata, dns_rdataclass_in,
|
||||
dns_rdatatype_dnskey, &r);
|
||||
ISC_LIST_APPEND(dnskeylist->rdata, rdata, link);
|
||||
ISC_LIST_APPEND(cleanup_list, newbuf, link);
|
||||
isc_buffer_clear(newbuf);
|
||||
}
|
||||
|
||||
published = true;
|
||||
if (dns_kasp_cdnskey(kasp) || !ISC_LIST_EMPTY(digests)) {
|
||||
pub = 0;
|
||||
del = 0;
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_SYNCPUBLISH,
|
||||
&pub);
|
||||
(void)dst_key_gettime(dk->key, DST_TIME_SYNCDELETE,
|
||||
&del);
|
||||
|
||||
next_bundle = between(pub, inception, next_bundle);
|
||||
next_bundle = between(del, inception, next_bundle);
|
||||
|
||||
if (pub != 0 && pub > inception) {
|
||||
published = false;
|
||||
}
|
||||
if (del != 0 && inception >= del) {
|
||||
published = false;
|
||||
}
|
||||
} else {
|
||||
published = false;
|
||||
}
|
||||
|
||||
if (!published) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* CDNSKEY */
|
||||
newbuf = NULL;
|
||||
|
|
@ -792,35 +892,98 @@ create_ksk(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys,
|
|||
dns_rdatalist_tordataset(dnskeylist, dnskeyset);
|
||||
dns_rdatalist_tordataset(cdnskeylist, cdnskeyset);
|
||||
dns_rdatalist_tordataset(cdslist, cdsset);
|
||||
return;
|
||||
|
||||
return (next_bundle);
|
||||
|
||||
fail:
|
||||
fatal("failed to create KSK/CDS/CDNSKEY");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
sign_bundle(ksr_ctx_t *ksr, isc_stdtime_t inception,
|
||||
isc_stdtime_t next_inception, dns_rdatalist_t *rdatalist,
|
||||
dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
|
||||
sign_bundle(ksr_ctx_t *ksr, dns_kasp_t *kasp, isc_stdtime_t inception,
|
||||
isc_stdtime_t next_inception, dns_rdatalist_t *zsklist,
|
||||
dns_dnsseckeylist_t *keys) {
|
||||
dns_rdataset_t rrset = DNS_RDATASET_INIT;
|
||||
isc_stdtime_t expiration;
|
||||
isc_stdtime_t expiration = inception + ksr->sigvalidity;
|
||||
isc_stdtime_t next_bundle = next_inception;
|
||||
dns_rdataset_t zsk;
|
||||
|
||||
dns_rdataset_init(&zsk);
|
||||
dns_rdatalist_tordataset(zsklist, &zsk);
|
||||
|
||||
dns_rdataset_init(&rrset);
|
||||
dns_rdatalist_tordataset(rdatalist, &rrset);
|
||||
expiration = inception + ksr->sigvalidity;
|
||||
while (inception <= next_inception) {
|
||||
sign_rrset(ksr, inception, expiration, &rrset, keys);
|
||||
if (dns_rdataset_count(cdnskey) > 0) {
|
||||
sign_rrset(ksr, inception, expiration, cdnskey, keys);
|
||||
isc_stdtime_t next_time = next_bundle;
|
||||
|
||||
/* DNSKEY RRset */
|
||||
dns_rdatalist_t *dnskeylist;
|
||||
dnskeylist = isc_mem_get(mctx, sizeof(*dnskeylist));
|
||||
dns_rdatalist_init(dnskeylist);
|
||||
dnskeylist->rdclass = dns_rdataclass_in;
|
||||
dnskeylist->type = dns_rdatatype_dnskey;
|
||||
dnskeylist->ttl = ksr->ttl;
|
||||
|
||||
dns_rdataset_t ksk, cdnskey, cds, rrset;
|
||||
dns_rdataset_init(&ksk);
|
||||
dns_rdataset_init(&cdnskey);
|
||||
dns_rdataset_init(&cds);
|
||||
dns_rdataset_init(&rrset);
|
||||
next_time = get_keymaterial(ksr, kasp, inception, next_time,
|
||||
keys, &ksk, &cdnskey, &cds);
|
||||
if (next_bundle > next_time) {
|
||||
next_bundle = next_time;
|
||||
}
|
||||
if (dns_rdataset_count(cds) > 0) {
|
||||
sign_rrset(ksr, inception, expiration, cds, keys);
|
||||
|
||||
for (isc_result_t r = dns_rdatalist_first(&ksk);
|
||||
r == ISC_R_SUCCESS; r = dns_rdatalist_next(&ksk))
|
||||
{
|
||||
dns_rdata_t *clone = isc_mem_get(mctx, sizeof(*clone));
|
||||
dns_rdata_init(clone);
|
||||
dns_rdatalist_current(&ksk, clone);
|
||||
ISC_LIST_APPEND(dnskeylist->rdata, clone, link);
|
||||
}
|
||||
|
||||
for (isc_result_t r = dns_rdatalist_first(&zsk);
|
||||
r == ISC_R_SUCCESS; r = dns_rdatalist_next(&zsk))
|
||||
{
|
||||
dns_rdata_t *clone = isc_mem_get(mctx, sizeof(*clone));
|
||||
dns_rdata_init(clone);
|
||||
dns_rdatalist_current(&zsk, clone);
|
||||
ISC_LIST_APPEND(dnskeylist->rdata, clone, link);
|
||||
}
|
||||
|
||||
dns_rdatalist_tordataset(dnskeylist, &rrset);
|
||||
next_time = sign_rrset(ksr, inception, expiration, &rrset,
|
||||
keys);
|
||||
if (next_bundle > next_time) {
|
||||
next_bundle = next_time;
|
||||
}
|
||||
freerrset(&ksk);
|
||||
freerrset(&rrset);
|
||||
|
||||
/* CDNSKEY */
|
||||
if (dns_rdataset_count(&cdnskey) > 0) {
|
||||
(void)sign_rrset(ksr, inception, expiration, &cdnskey,
|
||||
keys);
|
||||
}
|
||||
freerrset(&cdnskey);
|
||||
|
||||
/* CDS */
|
||||
if (dns_rdataset_count(&cds) > 0) {
|
||||
(void)sign_rrset(ksr, inception, expiration, &cds,
|
||||
keys);
|
||||
}
|
||||
freerrset(&cds);
|
||||
|
||||
/* Next response bundle. */
|
||||
inception = expiration - ksr->sigrefresh;
|
||||
if (inception > next_bundle) {
|
||||
inception = next_bundle;
|
||||
}
|
||||
expiration = inception + ksr->sigvalidity;
|
||||
next_bundle = expiration;
|
||||
}
|
||||
freerrset(&rrset);
|
||||
|
||||
freerrset(&zsk);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -907,9 +1070,12 @@ keygen(ksr_ctx_t *ksr) {
|
|||
for (dns_kasp_key_t *kk = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kk != NULL; kk = ISC_LIST_NEXT(kk, link))
|
||||
{
|
||||
if (dns_kasp_key_ksk(kk)) {
|
||||
if (dns_kasp_key_ksk(kk) && !ksr->ksk) {
|
||||
/* only ZSKs allowed */
|
||||
continue;
|
||||
} else if (dns_kasp_key_zsk(kk) && ksr->ksk) {
|
||||
/* only KSKs allowed */
|
||||
continue;
|
||||
}
|
||||
ksr->alg = dns_kasp_key_algorithm(kk);
|
||||
ksr->lifetime = dns_kasp_key_lifetime(kk);
|
||||
|
|
@ -920,7 +1086,7 @@ keygen(ksr_ctx_t *ksr) {
|
|||
for (isc_stdtime_t inception = ksr->start, act = ksr->start;
|
||||
inception < ksr->end; inception += ksr->lifetime)
|
||||
{
|
||||
create_zsk(ksr, kk, &keys, inception, act, &act);
|
||||
create_key(ksr, kasp, kk, &keys, inception, act, &act);
|
||||
if (ksr->lifetime == 0) {
|
||||
/* unlimited lifetime, but not infinite loop */
|
||||
break;
|
||||
|
|
@ -928,7 +1094,7 @@ keygen(ksr_ctx_t *ksr) {
|
|||
}
|
||||
}
|
||||
if (noop) {
|
||||
fatal("policy '%s' has no zsks", ksr->policy);
|
||||
fatal("no keys created for policy '%s'", ksr->policy);
|
||||
}
|
||||
/* Cleanup */
|
||||
cleanup(&keys, kasp);
|
||||
|
|
@ -1007,9 +1173,6 @@ sign(ksr_ctx_t *ksr) {
|
|||
dns_dnsseckeylist_t keys;
|
||||
dns_kasp_t *kasp = NULL;
|
||||
dns_rdatalist_t *rdatalist = NULL;
|
||||
dns_rdataset_t ksk = DNS_RDATASET_INIT;
|
||||
dns_rdataset_t cdnskey = DNS_RDATASET_INIT;
|
||||
dns_rdataset_t cds = DNS_RDATASET_INIT;
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t inception;
|
||||
isc_lex_t *lex = NULL;
|
||||
|
|
@ -1042,9 +1205,6 @@ sign(ksr_ctx_t *ksr) {
|
|||
isc_result_totext(ret));
|
||||
}
|
||||
|
||||
/* KSK, CDS and CDNSKEY */
|
||||
create_ksk(ksr, kasp, &keys, &ksk, &cdnskey, &cds);
|
||||
|
||||
for (ret = isc_lex_gettoken(lex, opt, &token); ret == ISC_R_SUCCESS;
|
||||
ret = isc_lex_gettoken(lex, opt, &token))
|
||||
{
|
||||
|
|
@ -1094,8 +1254,8 @@ sign(ksr_ctx_t *ksr) {
|
|||
|
||||
if (have_bundle) {
|
||||
/* Sign previous bundle */
|
||||
sign_bundle(ksr, inception, next_inception,
|
||||
rdatalist, &cds, &cdnskey, &keys);
|
||||
sign_bundle(ksr, kasp, inception,
|
||||
next_inception, rdatalist, &keys);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
|
|
@ -1105,15 +1265,7 @@ sign(ksr_ctx_t *ksr) {
|
|||
rdatalist->rdclass = dns_rdataclass_in;
|
||||
rdatalist->type = dns_rdatatype_dnskey;
|
||||
rdatalist->ttl = ksr->ttl;
|
||||
for (isc_result_t r = dns_rdatalist_first(&ksk);
|
||||
r == ISC_R_SUCCESS; r = dns_rdatalist_next(&ksk))
|
||||
{
|
||||
dns_rdata_t *clone =
|
||||
isc_mem_get(mctx, sizeof(*clone));
|
||||
dns_rdata_init(clone);
|
||||
dns_rdatalist_current(&ksk, clone);
|
||||
ISC_LIST_APPEND(rdatalist->rdata, clone, link);
|
||||
}
|
||||
|
||||
inception = next_inception;
|
||||
have_bundle = true;
|
||||
|
||||
|
|
@ -1172,8 +1324,7 @@ sign(ksr_ctx_t *ksr) {
|
|||
|
||||
/* Final bundle */
|
||||
if (have_bundle && rdatalist != NULL) {
|
||||
sign_bundle(ksr, inception, ksr->end, rdatalist, &cds, &cdnskey,
|
||||
&keys);
|
||||
sign_bundle(ksr, kasp, inception, ksr->end, rdatalist, &keys);
|
||||
} else {
|
||||
fatal("bad KSR file %s(%lu): no bundles", ksr->file,
|
||||
isc_lex_getsourceline(lex));
|
||||
|
|
@ -1185,11 +1336,6 @@ sign(ksr_ctx_t *ksr) {
|
|||
timestr, PACKAGE_VERSION);
|
||||
|
||||
fail:
|
||||
/* Clean up */
|
||||
freerrset(&ksk);
|
||||
freerrset(&cdnskey);
|
||||
freerrset(&cds);
|
||||
|
||||
isc_lex_destroy(&lex);
|
||||
cleanup(&keys, kasp);
|
||||
}
|
||||
|
|
@ -1212,7 +1358,7 @@ main(int argc, char *argv[]) {
|
|||
|
||||
isc_commandline_errprint = false;
|
||||
|
||||
#define OPTIONS "E:e:Ff:hi:K:k:l:v:V"
|
||||
#define OPTIONS "E:e:Ff:hi:K:k:l:ov:V"
|
||||
while ((ch = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
|
||||
switch (ch) {
|
||||
case 'E':
|
||||
|
|
@ -1249,6 +1395,9 @@ main(int argc, char *argv[]) {
|
|||
case 'l':
|
||||
ksr.configfile = isc_commandline_argument;
|
||||
break;
|
||||
case 'o':
|
||||
ksr.ksk = true;
|
||||
break;
|
||||
case 'V':
|
||||
version(program);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ dnssec-ksr - Create signed key response (SKR) files for offline KSK setups
|
|||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
:program:`dnssec-ksr` [**-e** date/offset] [**-F**] [**-h**] [**-i** date/offset] [**-K** directory] [**-k** policy] [**-l** file] [**-V**] [**-v** level] {command} {zone}
|
||||
:program:`dnssec-ksr` [**-e** date/offset] [**-F**] [**-f** file] [**-h**] [**-i** date/offset] [**-K** directory] [**-k** policy] [**-l** file] [**-o**] [**-V**] [**-v** level] {command} {zone}
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
|
@ -51,6 +51,10 @@ Options
|
|||
mode if the underlying crytographic library supports running in FIPS
|
||||
mode.
|
||||
|
||||
.. option:: -f
|
||||
|
||||
This option sets the SKR file to be signed when issuing a ``sign`` command.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
This option prints a short summary of the options and arguments to
|
||||
|
|
@ -76,6 +80,11 @@ Options
|
|||
This option provides a configuration file that contains a ``dnssec-policy``
|
||||
statement (matching the policy set with :option:`-k`).
|
||||
|
||||
.. option:: -o
|
||||
|
||||
Normally when pregenerating keys, ZSKs are created. When this option is
|
||||
set, create KSKs instead.
|
||||
|
||||
.. option:: -V
|
||||
|
||||
This option prints version information.
|
||||
|
|
@ -98,9 +107,8 @@ Commands
|
|||
|
||||
.. option:: keygen
|
||||
|
||||
Pregenerate a number of zone signing keys (ZSKs), given a DNSSEC policy and
|
||||
an interval. The number of generated keys depends on the interval and the
|
||||
ZSK lifetime.
|
||||
Pregenerate a number of keys, given a DNSSEC policy and an interval. The
|
||||
number of generated keys depends on the interval and the key lifetime.
|
||||
|
||||
.. option:: request
|
||||
|
||||
|
|
@ -123,7 +131,7 @@ occurred.
|
|||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
When you need to generate keys for the zone "example.com" for the next year,
|
||||
When you need to generate ZSKs for the zone "example.com" for the next year,
|
||||
given a ``dnssec-policy`` named "mypolicy":
|
||||
|
||||
::
|
||||
|
|
@ -136,7 +144,8 @@ Creating a KSR for the same zone and period can be done with:
|
|||
|
||||
dnssec-ksr -i now -e +1y -k mypolicy -l named.conf request example.com > ksr.txt
|
||||
|
||||
Typically you would now transfer the KSR to the system that has access to the KSK.
|
||||
Typically you would now transfer the KSR to the system that has access to
|
||||
the KSK.
|
||||
|
||||
Signing the KSR created above can be done with:
|
||||
|
||||
|
|
@ -144,7 +153,8 @@ Signing the KSR created above can be done with:
|
|||
|
||||
dnssec-ksr -i now -e +1y -k kskpolicy -l named.conf -f ksr.txt sign example.com
|
||||
|
||||
Make sure that the DNSSEC parameters in ``kskpolicy`` match those in ``mypolicy``.
|
||||
Make sure that the DNSSEC parameters in ``kskpolicy`` match those
|
||||
in ``mypolicy``.
|
||||
|
||||
See Also
|
||||
~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -431,8 +431,11 @@ def _check_dnskeys(dnskeys, keys, cdnskey=False):
|
|||
has_dnskey = True
|
||||
break
|
||||
|
||||
assert has_dnskey
|
||||
numkeys += 1
|
||||
if not cdnskey:
|
||||
assert has_dnskey
|
||||
|
||||
if has_dnskey:
|
||||
numkeys += 1
|
||||
|
||||
return numkeys
|
||||
|
||||
|
|
@ -541,17 +544,17 @@ def check_apex(server, zone, ksks, zsks):
|
|||
|
||||
# test cdnskey query
|
||||
cdnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDNSKEY)
|
||||
assert len(cdnskeys) > 0
|
||||
check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True)
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDNSKEY, fqdn, ksks, zsks)
|
||||
if len(cdnskeys) > 0:
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDNSKEY, fqdn, ksks, zsks)
|
||||
|
||||
# test cds query
|
||||
cds, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDS)
|
||||
assert len(cds) > 0
|
||||
check_cds(cds, ksks)
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDS, fqdn, ksks, zsks)
|
||||
if len(cds) > 0:
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDS, fqdn, ksks, zsks)
|
||||
|
||||
|
||||
def check_subdomain(server, zone, ksks, zsks):
|
||||
|
|
|
|||
|
|
@ -85,3 +85,11 @@ dnssec-policy "two-tone" {
|
|||
zsk lifetime P3M algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
||||
dnssec-policy "ksk-roll" {
|
||||
offline-ksk yes;
|
||||
keys {
|
||||
ksk lifetime P6M algorithm @DEFAULT_ALGORITHM@;
|
||||
zsk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@ cp template.db.in last-bundle.test.db
|
|||
cp template.db.in in-the-middle.test.db
|
||||
cp template.db.in unlimited.test.db
|
||||
cp template.db.in two-tone.test.db
|
||||
cp template.db.in ksk-roll.test.db
|
||||
|
|
|
|||
|
|
@ -55,28 +55,6 @@ def keystr_to_keylist(keystr: str, keydir: Optional[str] = None) -> List[Key]:
|
|||
return [Key(name, keydir) for name in keystr.split()]
|
||||
|
||||
|
||||
def keygen(zone, policy, keydir, when="now"):
|
||||
keygen_command = [
|
||||
os.environ.get("KEYGEN"),
|
||||
"-l",
|
||||
"ns1/named.conf",
|
||||
"-fK",
|
||||
"-K",
|
||||
keydir,
|
||||
"-k",
|
||||
policy,
|
||||
"-P",
|
||||
when,
|
||||
"-A",
|
||||
when,
|
||||
"-P",
|
||||
"sync",
|
||||
when,
|
||||
zone,
|
||||
]
|
||||
return isctest.run.cmd(keygen_command, log_stdout=True).stdout.decode("utf-8")
|
||||
|
||||
|
||||
def ksr(zone, policy, action, options="", raise_on_exception=True):
|
||||
ksr_command = [
|
||||
os.environ.get("KSR"),
|
||||
|
|
@ -123,12 +101,22 @@ def check_keys(
|
|||
# retired: zsk-lifetime
|
||||
if lifetime is not None:
|
||||
retired = active + lifetime
|
||||
# removed: ttlsig + retire-safety + sign-delay + propagation
|
||||
removed = retired + timedelta(days=10, hours=1, minutes=5)
|
||||
|
||||
if key.is_ksk():
|
||||
# removed: ttlds + retire-safety + parent-propagation
|
||||
removed = retired + timedelta(days=1, hours=2)
|
||||
else:
|
||||
# removed: ttlsig + retire-safety + sign-delay + propagation
|
||||
removed = retired + timedelta(days=10, hours=1, minutes=5)
|
||||
else:
|
||||
retired = None
|
||||
removed = None
|
||||
|
||||
goal = "hidden"
|
||||
state_dnskey = "hidden"
|
||||
state_zrrsig = "hidden"
|
||||
state_krrsig = "hidden"
|
||||
state_ds = "hidden"
|
||||
if retired is None or between(now, published, retired):
|
||||
goal = "omnipresent"
|
||||
pubdelay = published + timedelta(hours=2, minutes=5)
|
||||
|
|
@ -136,24 +124,34 @@ def check_keys(
|
|||
|
||||
if between(now, published, pubdelay):
|
||||
state_dnskey = "rumoured"
|
||||
state_krrsig = "rumoured"
|
||||
else:
|
||||
state_dnskey = "omnipresent"
|
||||
state_krrsig = "omnipresent"
|
||||
|
||||
if between(now, active, signdelay):
|
||||
state_zrrsig = "rumoured"
|
||||
if key.is_ksk():
|
||||
state_ds = "hidden"
|
||||
else:
|
||||
state_zrrsig = "omnipresent"
|
||||
else:
|
||||
goal = "hidden"
|
||||
state_dnskey = "hidden"
|
||||
state_zrrsig = "hidden"
|
||||
if between(now, active, signdelay):
|
||||
state_zrrsig = "rumoured"
|
||||
else:
|
||||
state_zrrsig = "omnipresent"
|
||||
|
||||
with open(key.statefile, "r", encoding="utf-8") as file:
|
||||
metadata = file.read()
|
||||
assert f"Algorithm: {alg}" in metadata
|
||||
assert f"Length: {size}" in metadata
|
||||
assert "KSK: no" in metadata
|
||||
assert "ZSK: yes" in metadata
|
||||
|
||||
if key.is_ksk():
|
||||
assert "KSK: yes" in metadata
|
||||
else:
|
||||
assert "KSK: no" in metadata
|
||||
|
||||
if key.is_zsk():
|
||||
assert "ZSK: yes" in metadata
|
||||
else:
|
||||
assert "ZSK: no" in metadata
|
||||
|
||||
assert f"Published: {published}" in metadata
|
||||
assert f"Active: {active}" in metadata
|
||||
|
||||
|
|
@ -169,9 +167,18 @@ def check_keys(
|
|||
if with_state:
|
||||
assert f"GoalState: {goal}" in metadata
|
||||
assert f"DNSKEYState: {state_dnskey}" in metadata
|
||||
assert f"ZRRSIGState: {state_zrrsig}" in metadata
|
||||
assert "KRRSIGState:" not in metadata
|
||||
assert "DSState:" not in metadata
|
||||
|
||||
if key.is_ksk():
|
||||
assert f"KRRSIGState: {state_krrsig}" in metadata
|
||||
assert f"DSState: {state_ds}" in metadata
|
||||
else:
|
||||
assert "KRRSIGState:" not in metadata
|
||||
assert "DSState:" not in metadata
|
||||
|
||||
if key.is_zsk():
|
||||
assert f"ZRRSIGState: {state_zrrsig}" in metadata
|
||||
else:
|
||||
assert "ZRRSIGState:" not in metadata
|
||||
|
||||
num += 1
|
||||
|
||||
|
|
@ -264,6 +271,9 @@ def check_signedkeyresponse(
|
|||
# expect ksks
|
||||
for key in sorted(ksks):
|
||||
published = key.get_timing("Publish")
|
||||
if between(published, inception, next_bundle):
|
||||
next_bundle = published
|
||||
|
||||
removed = key.get_timing("Delete", must_exist=False)
|
||||
|
||||
if published > inception:
|
||||
|
|
@ -271,6 +281,9 @@ def check_signedkeyresponse(
|
|||
if removed is not None and inception >= removed:
|
||||
continue
|
||||
|
||||
if between(removed, inception, next_bundle):
|
||||
next_bundle = removed
|
||||
|
||||
# this ksk must be in the ksr
|
||||
assert key.dnskey_equals(lines[line_no])
|
||||
line_no += 1
|
||||
|
|
@ -311,10 +324,17 @@ def check_signedkeyresponse(
|
|||
line_no += 1
|
||||
|
||||
# expect cdnskey
|
||||
have_cdnskey = False
|
||||
if cdnskey:
|
||||
for key in sorted(ksks):
|
||||
published = key.get_timing("Publish")
|
||||
removed = key.get_timing("Delete", must_exist=False)
|
||||
published = key.get_timing("SyncPublish")
|
||||
if between(published, inception, next_bundle):
|
||||
next_bundle = published
|
||||
|
||||
removed = key.get_timing("SyncDelete", must_exist=False)
|
||||
if between(removed, inception, next_bundle):
|
||||
next_bundle = removed
|
||||
|
||||
if published > inception:
|
||||
continue
|
||||
if removed is not None and inception >= removed:
|
||||
|
|
@ -323,7 +343,9 @@ def check_signedkeyresponse(
|
|||
# the cdnskey of this ksk must be in the ksr
|
||||
assert key.dnskey_equals(lines[line_no], cdnskey=True)
|
||||
line_no += 1
|
||||
have_cdnskey = True
|
||||
|
||||
if have_cdnskey:
|
||||
# expect rrsig(cdnskey)
|
||||
for key in sorted(ksks):
|
||||
active = key.get_timing("Activate")
|
||||
|
|
@ -341,10 +363,17 @@ def check_signedkeyresponse(
|
|||
line_no += 1
|
||||
|
||||
# expect cds
|
||||
have_cds = False
|
||||
if cds != "":
|
||||
for key in sorted(ksks):
|
||||
published = key.get_timing("Publish")
|
||||
removed = key.get_timing("Delete", must_exist=False)
|
||||
published = key.get_timing("SyncPublish")
|
||||
if between(published, inception, next_bundle):
|
||||
next_bundle = published
|
||||
|
||||
removed = key.get_timing("SyncDelete", must_exist=False)
|
||||
if between(removed, inception, next_bundle):
|
||||
next_bundle = removed
|
||||
|
||||
if published > inception:
|
||||
continue
|
||||
if removed is not None and inception >= removed:
|
||||
|
|
@ -355,7 +384,9 @@ def check_signedkeyresponse(
|
|||
for alg in expected_cds:
|
||||
assert key.cds_equals(lines[line_no], alg.strip())
|
||||
line_no += 1
|
||||
have_cds = True
|
||||
|
||||
if have_cds:
|
||||
# expect rrsig(cds)
|
||||
for key in sorted(ksks):
|
||||
active = key.get_timing("Activate")
|
||||
|
|
@ -399,7 +430,7 @@ def test_ksr_errors():
|
|||
_, err = ksr(
|
||||
"csk.test", "csk", "keygen", options="-K ns1 -e +2y", raise_on_exception=False
|
||||
)
|
||||
assert "dnssec-ksr: fatal: policy 'csk' has no zsks" in err
|
||||
assert "dnssec-ksr: fatal: no keys created for policy 'csk'" in err
|
||||
|
||||
# check that 'dnssec-ksr request' errors on missing end date
|
||||
_, err = ksr("common.test", "common", "request", raise_on_exception=False)
|
||||
|
|
@ -424,10 +455,12 @@ def test_ksr_common(servers):
|
|||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out = keygen(zone, policy, kskdir)
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
out, _ = ksr(zone, policy, "keygen", options="-i now -e +1y")
|
||||
zsks = keystr_to_keylist(out)
|
||||
|
|
@ -611,13 +644,13 @@ def test_ksr_lastbundle(servers):
|
|||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
now = KeyTimingMetadata.now()
|
||||
offset = -timedelta(days=365)
|
||||
when = now + offset - timedelta(days=1)
|
||||
out = keygen(zone, policy, kskdir, when=str(when))
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1d -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None, offset=offset)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1d")
|
||||
|
|
@ -690,13 +723,13 @@ def test_ksr_inthemiddle(servers):
|
|||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
now = KeyTimingMetadata.now()
|
||||
offset = -timedelta(days=365)
|
||||
when = now + offset - timedelta(days=1)
|
||||
out = keygen(zone, policy, kskdir, when=str(when))
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1y -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None, offset=offset)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1y")
|
||||
|
|
@ -771,7 +804,7 @@ def check_ksr_rekey_logs_error(server, zone, policy, offset, end):
|
|||
now = KeyTimingMetadata.now()
|
||||
then = now + offset
|
||||
until = now + end
|
||||
out = keygen(zone, policy, kskdir, when=str(then))
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i {then} -e {until} -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
|
|
@ -844,10 +877,12 @@ def test_ksr_unlimited(servers):
|
|||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out = keygen(zone, policy, kskdir)
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +2y -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +2y")
|
||||
|
|
@ -959,10 +994,28 @@ def test_ksr_twotone(servers):
|
|||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out = keygen(zone, policy, kskdir)
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 2
|
||||
|
||||
ksks_defalg = []
|
||||
ksks_altalg = []
|
||||
for ksk in ksks:
|
||||
alg = ksk.get_metadata("Algorithm")
|
||||
if alg == os.environ.get("DEFAULT_ALGORITHM_NUMBER"):
|
||||
ksks_defalg.append(ksk)
|
||||
elif alg == os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER"):
|
||||
ksks_altalg.append(ksk)
|
||||
|
||||
assert len(ksks_defalg) == 1
|
||||
assert len(ksks_altalg) == 1
|
||||
|
||||
check_keys(ksks_defalg, None)
|
||||
|
||||
alg = os.environ.get("ALTERNATIVE_ALGORITHM_NUMBER")
|
||||
size = os.environ.get("ALTERNATIVE_BITS")
|
||||
check_keys(ksks_altalg, None, alg, size)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
|
||||
|
|
@ -1050,3 +1103,77 @@ def test_ksr_twotone(servers):
|
|||
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
|
||||
# - check subdomain
|
||||
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
|
||||
|
||||
|
||||
def test_ksr_kskroll(servers):
|
||||
zone = "ksk-roll.test"
|
||||
policy = "ksk-roll"
|
||||
n = 1
|
||||
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 2
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
check_keys(ksks, lifetime)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 1
|
||||
|
||||
check_keys(zsks, None)
|
||||
|
||||
# check that 'dnssec-ksr request' creates correct ksr
|
||||
now = zsks[0].get_timing("Created")
|
||||
until = now + timedelta(days=365)
|
||||
out, _ = ksr(zone, policy, "request", options=f"-K {zskdir} -i {now} -e +1y")
|
||||
|
||||
fname = f"{zone}.ksr.{n}"
|
||||
with open(fname, "w", encoding="utf-8") as file:
|
||||
file.write(out)
|
||||
|
||||
check_keysigningrequest(out, zsks, now, until)
|
||||
|
||||
# check that 'dnssec-ksr sign' creates correct skr
|
||||
out, _ = ksr(
|
||||
zone, policy, "sign", options=f"-K {kskdir} -f {fname} -i {now} -e +1y"
|
||||
)
|
||||
|
||||
skrfile = f"{zone}.skr.{n}"
|
||||
with open(skrfile, "w", encoding="utf-8") as file:
|
||||
file.write(out)
|
||||
|
||||
refresh = -432000 # 5 days
|
||||
check_signedkeyresponse(out, zone, ksks, zsks, now, until, refresh)
|
||||
|
||||
# add zone
|
||||
ns1 = servers["ns1"]
|
||||
ns1.rndc(
|
||||
f"addzone {zone} "
|
||||
+ "{ type primary; file "
|
||||
+ f'"{zone}.db"; dnssec-policy {policy}; '
|
||||
+ "};",
|
||||
log=False,
|
||||
)
|
||||
|
||||
# import skr
|
||||
shutil.copyfile(skrfile, f"ns1/{skrfile}")
|
||||
ns1.rndc(f"skr -import {skrfile} {zone}", log=False)
|
||||
|
||||
# test zone is correctly signed
|
||||
# - check rndc dnssec -status output
|
||||
isctest.kasp.check_dnssecstatus(ns1, zone, zsks, policy=policy)
|
||||
# - zone is signed
|
||||
isctest.kasp.check_zone_is_signed(ns1, zone)
|
||||
# - dnssec_verify
|
||||
isctest.kasp.check_dnssec_verify(ns1, zone)
|
||||
# - check keys
|
||||
check_keys(zsks, None, with_state=True)
|
||||
# - check apex
|
||||
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
|
||||
# - check subdomain
|
||||
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,17 @@
|
|||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
void
|
||||
dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first);
|
||||
/*%<
|
||||
* Set the SyncPublish time (when the DS may be submitted to the parent).
|
||||
* If 'first' is true, also make sure that the zone signatures are omnipresent.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'key' is a valid DNSSEC key.
|
||||
*\li 'kasp' is a valid DNSSEC policy.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
isc_mem_t *mctx, dns_dnsseckeylist_t *keyring,
|
||||
|
|
|
|||
|
|
@ -163,26 +163,25 @@ keymgr_settime_remove(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
|
|||
* Set the SyncPublish time (when the DS may be submitted to the parent).
|
||||
*
|
||||
*/
|
||||
static void
|
||||
keymgr_settime_syncpublish(dns_dnsseckey_t *key, dns_kasp_t *kasp, bool first) {
|
||||
void
|
||||
dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first) {
|
||||
isc_stdtime_t published, syncpublish;
|
||||
bool ksk = false;
|
||||
isc_result_t ret;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
REQUIRE(key->key != NULL);
|
||||
|
||||
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &published);
|
||||
ret = dst_key_gettime(key, DST_TIME_PUBLISH, &published);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
|
||||
ret = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
|
||||
if (ret != ISC_R_SUCCESS || !ksk) {
|
||||
return;
|
||||
}
|
||||
|
||||
syncpublish = published + dst_key_getttl(key->key) +
|
||||
syncpublish = published + dst_key_getttl(key) +
|
||||
dns_kasp_zonepropagationdelay(kasp) +
|
||||
dns_kasp_publishsafety(kasp);
|
||||
if (first) {
|
||||
|
|
@ -196,7 +195,7 @@ keymgr_settime_syncpublish(dns_dnsseckey_t *key, dns_kasp_t *kasp, bool first) {
|
|||
syncpublish = zrrsig_present;
|
||||
}
|
||||
}
|
||||
dst_key_settime(key->key, DST_TIME_SYNCPUBLISH, syncpublish);
|
||||
dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncpublish);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1862,7 +1861,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
|||
*/
|
||||
dst_key_settime(new_key->key, DST_TIME_PUBLISH, now);
|
||||
dst_key_settime(new_key->key, DST_TIME_ACTIVATE, now);
|
||||
keymgr_settime_syncpublish(new_key, kasp, true);
|
||||
dns_keymgr_settime_syncpublish(new_key->key, kasp, true);
|
||||
active = now;
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -1894,7 +1893,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
|||
}
|
||||
dst_key_settime(new_key->key, DST_TIME_PUBLISH, prepub);
|
||||
dst_key_settime(new_key->key, DST_TIME_ACTIVATE, active);
|
||||
keymgr_settime_syncpublish(new_key, kasp, false);
|
||||
dns_keymgr_settime_syncpublish(new_key->key, kasp, false);
|
||||
|
||||
/*
|
||||
* Retire predecessor.
|
||||
|
|
|
|||
Loading…
Reference in a new issue