diff --git a/bin/dnssec/dnssec-ksr.c b/bin/dnssec/dnssec-ksr.c index b8bc348508..493c483d6e 100644 --- a/bin/dnssec/dnssec-ksr.c +++ b/bin/dnssec/dnssec-ksr.c @@ -87,7 +87,6 @@ static int min_dh = 128; #define KSR_LINESIZE 1500 /* should be long enough for any DNSKEY record */ #define DATETIME_INDEX 25 -#define TTL_MAX INT32_MAX #define MAXWIRE (64 * 1024) #define STR(t) ((t).value.as_textregion.base) @@ -523,10 +522,7 @@ print_rdata(dns_rdataset_t *rrset) { static isc_stdtime_t print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys, isc_stdtime_t inception, isc_stdtime_t next_inception) { - bool ksk = dns_kasp_key_ksk(kaspkey); - bool zsk = dns_kasp_key_zsk(kaspkey); char algstr[DNS_SECALG_FORMATSIZE]; - char rolestr[4]; char timestr[26]; /* Minimal buf as per ctime_r() spec. */ dns_rdatalist_t *rdatalist = NULL; dns_rdataset_t rdataset = DNS_RDATASET_INIT; @@ -536,13 +532,6 @@ print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys, isc_stdtime_tostring(inception, timestr, sizeof(timestr)); dns_secalg_format(dns_kasp_key_algorithm(kaspkey), algstr, sizeof(algstr)); - if (ksk && zsk) { - snprintf(rolestr, sizeof(rolestr), "csk"); - } else if (ksk) { - snprintf(rolestr, sizeof(rolestr), "ksk"); - } else { - snprintf(rolestr, sizeof(rolestr), "zsk"); - } /* Fetch matching key pair. */ rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); @@ -598,8 +587,8 @@ print_dnskeys(dns_kasp_key_t *kaspkey, dns_ttl_t ttl, dns_dnsseckeylist_t *keys, } /* Error if no key pair found. */ if (ISC_LIST_EMPTY(rdatalist->rdata)) { - fatal("no %s/%s %s key pair found for bundle %s", namestr, - algstr, rolestr, timestr); + fatal("no %s/%s zsk key pair found for bundle %s", namestr, + algstr, timestr); } /* All good, print DNSKEY RRset. */ @@ -611,8 +600,8 @@ fail: freerrset(&rdataset); if (ret != ISC_R_SUCCESS) { - fatal("failed to print %s/%s %s key pair found for bundle %s", - namestr, algstr, rolestr, timestr); + fatal("failed to print %s/%s zsk key pair found for bundle %s", + namestr, algstr, timestr); } return (next_bundle); @@ -690,14 +679,25 @@ sign_rrset(ksr_ctx_t *ksr, isc_stdtime_t inception, isc_stdtime_t expiration, freerrset(&rrsigset); } +/* + * Create the DNSKEY, CDS, and CDNSKEY records beloing to the KSKs + * listed in 'keys'. + */ static void -create_cds(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys, - dns_rdataset_t *cdnskeyset, dns_rdataset_t *cdsset) { +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) { + 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); + dns_rdatalist_init(dnskeylist); + dnskeylist->rdclass = dns_rdataclass_in; + dnskeylist->type = dns_rdatatype_dnskey; + dnskeylist->ttl = ksr->ttl; + dns_rdatalist_init(cdnskeylist); cdnskeylist->rdclass = dns_rdataclass_in; cdnskeylist->type = dns_rdatatype_cdnskey; @@ -712,17 +712,37 @@ create_cds(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys, dk = ISC_LIST_NEXT(dk, link)) { isc_buffer_t buf; - isc_buffer_t *newbuf = NULL; - dns_rdata_t *rdata = NULL; + isc_buffer_t *newbuf; + dns_rdata_t *rdata; isc_region_t r; isc_region_t rcds; - unsigned char rdatabuf[DST_KEY_MAXSIZE]; + 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); - isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf)); + 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); + + /* CDNSKEY */ + newbuf = NULL; + rdata = isc_mem_get(mctx, sizeof(*rdata)); + dns_rdata_init(rdata); + + isc_buffer_init(&buf, cdnskeybuf, sizeof(cdnskeybuf)); CHECK(dst_key_todns(dk->key, &buf)); isc_buffer_usedregion(&buf, &r); isc_buffer_allocate(mctx, &newbuf, r.length); @@ -736,6 +756,7 @@ create_cds(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys, ISC_LIST_APPEND(cleanup_list, newbuf, link); isc_buffer_clear(newbuf); + /* CDS */ for (dns_kasp_digest_t *alg = ISC_LIST_HEAD(digests); alg != NULL; alg = ISC_LIST_NEXT(alg, link)) { @@ -765,12 +786,13 @@ create_cds(ksr_ctx_t *ksr, dns_kasp_t *kasp, dns_dnsseckeylist_t *keys, } } /* All good */ + dns_rdatalist_tordataset(dnskeylist, dnskeyset); dns_rdatalist_tordataset(cdnskeylist, cdnskeyset); dns_rdatalist_tordataset(cdslist, cdsset); return; fail: - fatal("failed to create CDS/CDNSKEY"); + fatal("failed to create KSK/CDS/CDNSKEY"); } static void @@ -956,6 +978,11 @@ request(ksr_ctx_t *ksr) { * or withdrawal of a key that is after the current * inception. */ + if (dns_kasp_key_ksk(kk)) { + /* We only want ZSKs in the request. */ + continue; + } + next = print_dnskeys(kk, ksr->ttl, &keys, inception, next); } @@ -977,6 +1004,7 @@ 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; @@ -1011,8 +1039,8 @@ sign(ksr_ctx_t *ksr) { isc_result_totext(ret)); } - /* CDS and CDNSKEY */ - create_cds(ksr, kasp, &keys, &cdnskey, &cds); + /* 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)) @@ -1073,7 +1101,16 @@ sign(ksr_ctx_t *ksr) { dns_rdatalist_init(rdatalist); rdatalist->rdclass = dns_rdataclass_in; rdatalist->type = dns_rdatatype_dnskey; - rdatalist->ttl = TTL_MAX; + 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; @@ -1091,7 +1128,7 @@ sign(ksr_ctx_t *ksr) { } while (token.type != isc_tokentype_eol); } else { /* Parse DNSKEY */ - dns_ttl_t ttl = TTL_MAX; + dns_ttl_t ttl = ksr->ttl; isc_buffer_t buf; isc_buffer_t *newbuf = NULL; dns_rdata_t *rdata = NULL; @@ -1146,8 +1183,9 @@ sign(ksr_ctx_t *ksr) { fail: /* Clean up */ - freerrset(&cds); + freerrset(&ksk); freerrset(&cdnskey); + freerrset(&cds); isc_lex_destroy(&lex); cleanup(&keys, kasp); diff --git a/bin/dnssec/dnssec-ksr.rst b/bin/dnssec/dnssec-ksr.rst index 1e5b57e3be..1ed7275aca 100644 --- a/bin/dnssec/dnssec-ksr.rst +++ b/bin/dnssec/dnssec-ksr.rst @@ -113,11 +113,14 @@ Commands .. option:: request Create a Key Signing Request (KSR), given a DNSSEC policy and an interval. + This will generate a file with a number of key bundles, where each bundle + contains the currently published ZSKs (according to the timing metadata). .. option:: sign Sign a Key Signing Request (KSR), given a DNSSEC policy and an interval, - creating a Signed Key Response (SKR). + creating a Signed Key Response (SKR). This will add the corresponding DNSKEY, + CDS, and CDNSKEY records for the KSK that is being used for signing. Exit Status ~~~~~~~~~~~ diff --git a/bin/tests/system/ksr/tests.sh b/bin/tests/system/ksr/tests.sh index ad14d992cf..fb991a8cde 100644 --- a/bin/tests/system/ksr/tests.sh +++ b/bin/tests/system/ksr/tests.sh @@ -190,19 +190,16 @@ ksr common -i $now -e +1y request common.test >ksr.request.out.$n 2>&1 || ret=1 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id) inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n # Bundle 2: KSK + ZSK1 + ZSK2 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id) inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n print_dnskeys common.test 1 2 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect # Bundle 3: KSK + ZSK2 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id) inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n # Footer cp ksr.request.expect.$n ksr.request.expect.base @@ -249,7 +246,7 @@ _update_expected_zsks() { fi } -check_ksr() { +check_skr() { _ret=0 zone=$1 file=$2 @@ -261,7 +258,7 @@ check_ksr() { cds4=$($DSFROMKEY -T 3600 -a SHA-384 -C -w $(cat "${zone}.ksk1.id")) cdnskey=$(awk '{sub(/DNSKEY/,"CDNSKEY")}1' <${zone}.ksk1) - echo_i "check ksr: zone $1 file $2 from $3 to $4 num-zsk $5" + echo_i "check skr: zone $1 file $2 from $3 to $4 num-zsk $5" # Initial state: not in a rollover, expect a SignedKeyResponse header # on the first line, start with the first ZSK (set zsk=0 so when we @@ -273,7 +270,7 @@ check_ksr() { rollover_done=$start _update_expected_zsks - echo_i "check ksr: inception $inception rollover-start $rollover_start rollover-done $rollover_done" + echo_i "check skr: inception $inception rollover-start $rollover_start rollover-done $rollover_done" lineno=0 complete=0 @@ -435,7 +432,7 @@ check_ksr() { zsk1=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id) start=$(cat $zsk1.state | grep "Generated" | awk '{print $2}') end=$(addtime $start 31536000) # one year -check_ksr "common.test" "ksr.sign.out.$n" $start $end 2 || ret=1 +check_skr "common.test" "ksr.sign.out.$n" $start $end 2 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) @@ -500,25 +497,21 @@ cp ksr.request.expect.base ksr.request.expect.$n key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3.id) inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n print_dnskeys common.test 2 3 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect # Bundle 5: KSK + ZSK3 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id) inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3 >>ksr.request.expect.$n # Bundle 6: KSK + ZSK3 + ZSK4 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk4.id) inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n print_dnskeys common.test 3 4 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect # Bundle 7: KSK + ZSK4 key=$(cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk3.id) inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat common.test.ksk1 >>ksr.request.expect.$n cat common.test.$DEFAULT_ALGORITHM_NUMBER.zsk4 >>ksr.request.expect.$n # Footer cp ksr.request.expect.$n ksr.request.expect.base @@ -545,7 +538,7 @@ ret=0 ksr common -i $now -e +2y -K offline -f ksr.request.expect sign common.test >ksr.sign.out.$n 2>&1 || ret=1 start=$(cat $zsk1.state | grep "Generated" | awk '{print $2}') end=$(addtime $start 63072000) # two years -check_ksr "common.test" "ksr.sign.out.$n" $start $end 4 || ret=1 +check_skr "common.test" "ksr.sign.out.$n" $start $end 4 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) @@ -593,7 +586,6 @@ ksr unlimited -i $created -e +4y request unlimited.test >ksr.request.out.$n 2>&1 # Only one bundle: KSK + ZSK inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n -cat unlimited.test.ksk1 >>ksr.request.expect.$n cat unlimited.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n # Footer grep ";; KeySigningRequest 1.0 generated at" ksr.request.out.$n >footer.$n || ret=1 @@ -611,7 +603,7 @@ ret=0 ksr unlimited -i $created -e +4y -K offline -f ksr.request.expect sign unlimited.test >ksr.sign.out.$n 2>&1 || ret=1 start=$(cat $key.state | grep "Generated" | awk '{print $2}') end=$(addtime $start 126144000) # four years -check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 +check_skr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) @@ -626,7 +618,7 @@ CDNSKEY="no" CDS_SHA1="yes" CDS_SHA256="yes" CDS_SHA384="yes" -check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 +check_skr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) @@ -641,7 +633,7 @@ CDNSKEY="yes" CDS_SHA1="no" CDS_SHA256="no" CDS_SHA384="no" -check_ksr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 +check_skr "unlimited.test" "ksr.sign.out.$n" $start $end 1 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) @@ -695,40 +687,30 @@ ksr two-tone -i $created -e +6mo request two-tone.test >ksr.request.out.$n 2>&1 key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id) inception=$(cat $key.state | grep "Generated" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >ksr.request.expect.$n -cat two-tone.test.ksk1 >>ksr.request.expect.$n -cat two-tone.test.ksk2 >>ksr.request.expect.$n cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n # Bundle 2: KSK-A1, KSK-B1, ZSK-A1 + ZSK-A2, ZSK-B1 key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2.id) inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat two-tone.test.ksk1 >>ksr.request.expect.$n -cat two-tone.test.ksk2 >>ksr.request.expect.$n print_dnskeys two-tone.test 1 2 $DEFAULT_ALGORITHM_NUMBER ksr.keygen.out.expect.$DEFAULT_ALGORITHM_NUMBER >>ksr.request.expect.$n cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n # Bundle 3: KSK-A1, KSK-B1, ZSK-A2, ZSK-B1 key=$(cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk1.id) inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat two-tone.test.ksk1 >>ksr.request.expect.$n -cat two-tone.test.ksk2 >>ksr.request.expect.$n cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1 >>ksr.request.expect.$n # Bundle 4: KSK-A1, KSK-B1, ZSK-A2, ZSK-B1 + ZSK-B2 key=$(cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk2.id) inception=$(cat $key.state | grep "Published" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat two-tone.test.ksk1 >>ksr.request.expect.$n -cat two-tone.test.ksk2 >>ksr.request.expect.$n cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n print_dnskeys two-tone.test 1 2 $ALTERNATIVE_ALGORITHM_NUMBER ksr.keygen.out.expect.$ALTERNATIVE_ALGORITHM_NUMBER >>ksr.request.expect.$n # Bundle 5: KSK-A1, KSK-B1, ZSK-A2, ZSK-B2 key=$(cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk1.id) inception=$(cat $key.state | grep "Removed" | cut -d' ' -f 2-) echo ";; KeySigningRequest 1.0 $inception" >>ksr.request.expect.$n -cat two-tone.test.ksk1 >>ksr.request.expect.$n -cat two-tone.test.ksk2 >>ksr.request.expect.$n cat two-tone.test.$DEFAULT_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n cat two-tone.test.$ALTERNATIVE_ALGORITHM_NUMBER.zsk2 >>ksr.request.expect.$n # Footer