mirror of
https://github.com/isc-projects/bind9.git
synced 2026-03-16 15:44:00 -04:00
This file was initially created for unit testing, but later code was added to generate the file. The static file should have been removed from the git repo.
501 lines
14 KiB
C
501 lines
14 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <sched.h> /* IWYU pragma: keep */
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define UNIT_TESTING
|
|
#include <cmocka.h>
|
|
|
|
#include <isc/file.h>
|
|
#include <isc/hex.h>
|
|
#include <isc/lex.h>
|
|
#include <isc/result.h>
|
|
#include <isc/stdio.h>
|
|
#include <isc/string.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/dnssec.h>
|
|
#include <dns/name.h>
|
|
#include <dns/rdatalist.h>
|
|
#include <dns/rdataset.h>
|
|
#include <dns/secalg.h>
|
|
#include <dns/skr.h>
|
|
#include <dns/time.h>
|
|
|
|
#include "zone_p.h"
|
|
|
|
#include <tests/dns.h>
|
|
|
|
typedef struct {
|
|
isc_stdtime_t btime;
|
|
isc_stdtime_t inception;
|
|
isc_stdtime_t expiration;
|
|
|
|
char kskbuf[1024];
|
|
dns_rdata_t ksk;
|
|
|
|
char zsk1buf[1024];
|
|
dns_rdata_t zsk1;
|
|
|
|
char zsk2buf[1024];
|
|
dns_rdata_t zsk2;
|
|
|
|
char cdnskeybuf[1024];
|
|
dns_rdata_t cdnskey;
|
|
|
|
char cdsbuf[1024];
|
|
dns_rdata_t cds;
|
|
|
|
char rrsig1buf[1024];
|
|
dns_rdata_t dnskey_rrsig;
|
|
|
|
char rrsig2buf[1024];
|
|
dns_rdata_t cdnskey_rrsig;
|
|
|
|
char rrsig3buf[1024];
|
|
dns_rdata_t cds_rrsig;
|
|
} skr__testbundle_t;
|
|
|
|
static skr__testbundle_t test_bundles[42];
|
|
|
|
static dns_dnsseckeylist_t keys;
|
|
|
|
static const char *testskr = TESTS_DIR "/testdata/skr/test.skr";
|
|
static const char *kskstr =
|
|
"257 3 13 evPZ03dt9VeWNQKqw1fpuL0V1RcyPRge4s306hGOVYg1a1IttOf3ZKIm "
|
|
"McMgdT1K4nxJ+S7BtX6RVECqzp1rAA==";
|
|
static const char *zsk1str =
|
|
"256 3 13 GIyBcxr9uBJvybXw2eOeZ1nWjRd+0INxUPlKaWI1KQxJwWRJTOJMw33g "
|
|
"SSCz++TBmKyXm5ghl+56vOkoO33ppg==";
|
|
static const char *zsk2str =
|
|
"256 3 13 1oC9YpShKeL5HQnYIMX7y77b9qbnAsKIjVuU0AUoo2kTA1D2fXxB9W95 "
|
|
"+uqIiJuiteHK/oGmeDy4UsiTd2W1DQ==";
|
|
static const char *cdsstr =
|
|
"52433 13 2 90C4668A53D8BE06049BABD2DFC93F4C6B46C9055E20D91166381E22 "
|
|
"11BD9615";
|
|
|
|
static dns_name_t *dname = NULL;
|
|
|
|
#define BUNDLE_HAS_ZSK1 10
|
|
#define BUNDLE_HAS_ZSK2 20
|
|
|
|
#define OFFSET 3600
|
|
#define TTL 3600
|
|
#define LIFETIME 864000
|
|
|
|
#define SIG_FORMATSIZE \
|
|
(DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + sizeof("65535"))
|
|
|
|
static void
|
|
print_rdata(FILE *fp, dns_rdata_t *rdata) {
|
|
dns_rdataset_t rrset = DNS_RDATASET_INIT;
|
|
|
|
dns_rdatalist_t *rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
|
|
dns_rdatalist_init(rdatalist);
|
|
rdatalist->rdclass = dns_rdataclass_in;
|
|
rdatalist->type = rdata->type;
|
|
rdatalist->ttl = TTL;
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
dns_rdatalist_tordataset(rdatalist, &rrset);
|
|
|
|
isc_buffer_t target;
|
|
isc_region_t r;
|
|
isc_result_t ret;
|
|
char buf[4096];
|
|
|
|
isc_buffer_init(&target, buf, sizeof(buf));
|
|
ret = dns_rdataset_totext(&rrset, dname, false, false, &target);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
isc_buffer_usedregion(&target, &r);
|
|
fprintf(fp, "%.*s", (int)r.length, (char *)r.base);
|
|
|
|
for (dns_rdata_t *rd = ISC_LIST_HEAD(rdatalist->rdata); rd != NULL;
|
|
rd = ISC_LIST_HEAD(rdatalist->rdata))
|
|
{
|
|
ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
|
|
}
|
|
isc_mem_put(mctx, rdatalist, sizeof(*rdatalist));
|
|
}
|
|
|
|
static void
|
|
sign_rrset(FILE *fp, isc_stdtime_t inception, isc_stdtime_t expiration,
|
|
dns_rdataset_t *rrset, char *target_mem, dns_rdata_t *rrsig) {
|
|
dns_dnsseckey_t *ksk = ISC_LIST_HEAD(keys);
|
|
isc_stdtime_t clockskew = inception - OFFSET;
|
|
isc_result_t ret;
|
|
isc_buffer_t target;
|
|
|
|
isc_buffer_init(&target, target_mem, 1024);
|
|
ret = dns_dnssec_sign(dname, rrset, ksk->key, &clockskew, &expiration,
|
|
mctx, &target, rrsig);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
print_rdata(fp, rrsig);
|
|
}
|
|
|
|
static void
|
|
write_record(FILE *fp, dns_rdatatype_t rdtype, const char *rdatastr,
|
|
char *target_mem, dns_rdata_t *rdata) {
|
|
isc_buffer_t source, target;
|
|
isc_lex_t *lex = NULL;
|
|
isc_lexspecials_t specials = { 0 };
|
|
isc_result_t ret;
|
|
|
|
/* Set up source to hold the input string. */
|
|
isc_buffer_init(&target, target_mem, 1024);
|
|
isc_buffer_constinit(&source, rdatastr, strlen(rdatastr));
|
|
isc_buffer_add(&source, strlen(rdatastr));
|
|
|
|
/* Create a lexer as one is required by dns_rdata_fromtext(). */
|
|
isc_lex_create(mctx, 64, &lex);
|
|
specials[0] = 1;
|
|
specials['('] = 1;
|
|
specials[')'] = 1;
|
|
specials['"'] = 1;
|
|
isc_lex_setspecials(lex, specials);
|
|
isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
|
|
ret = isc_lex_openbuffer(lex, &source);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
ret = dns_rdata_fromtext(rdata, dns_rdataclass_in, rdtype, lex, dname,
|
|
0, mctx, &target, NULL);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
print_rdata(fp, rdata);
|
|
|
|
isc_lex_destroy(&lex);
|
|
}
|
|
|
|
static void
|
|
create_bundle(FILE *fp, isc_stdtime_t btime, int bnum) {
|
|
char timestr[26]; /* Minimal buf as per ctime_r() spec. */
|
|
char utc[sizeof("YYYYMMDDHHSSMM")];
|
|
dns_rdatalist_t *dnskeylist, *cdnskeylist, *cdslist;
|
|
dns_rdataset_t *dnskeyset = NULL;
|
|
dns_rdataset_t *cdnskeyset = NULL;
|
|
dns_rdataset_t *cdsset = NULL;
|
|
isc_buffer_t b, timebuf;
|
|
isc_region_t r;
|
|
isc_result_t ret;
|
|
|
|
/* Write header to file. */
|
|
test_bundles[bnum].btime = btime;
|
|
isc_buffer_init(&timebuf, timestr, sizeof(timestr));
|
|
isc_stdtime_tostring(btime, timestr, sizeof(timestr));
|
|
isc_buffer_init(&b, utc, sizeof(utc));
|
|
ret = dns_time32_totext(btime, &b);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
isc_buffer_usedregion(&b, &r);
|
|
fprintf(fp, ";; SignedKeyResponse 1.0 %.*s (%s)\n", (int)r.length,
|
|
r.base, timestr);
|
|
|
|
/* Write records to file. */
|
|
dns_rdata_init(&test_bundles[bnum].ksk);
|
|
write_record(fp, dns_rdatatype_dnskey, kskstr,
|
|
test_bundles[bnum].kskbuf, &test_bundles[bnum].ksk);
|
|
|
|
if (bnum < BUNDLE_HAS_ZSK2) {
|
|
dns_rdata_init(&test_bundles[bnum].zsk1);
|
|
write_record(fp, dns_rdatatype_dnskey, zsk1str,
|
|
test_bundles[bnum].zsk1buf,
|
|
&test_bundles[bnum].zsk1);
|
|
}
|
|
if (bnum > BUNDLE_HAS_ZSK1) {
|
|
dns_rdata_init(&test_bundles[bnum].zsk2);
|
|
write_record(fp, dns_rdatatype_dnskey, zsk2str,
|
|
test_bundles[bnum].zsk2buf,
|
|
&test_bundles[bnum].zsk2);
|
|
}
|
|
/* Create the DNSKEY signature. */
|
|
dnskeylist = isc_mem_get(mctx, sizeof(*dnskeylist));
|
|
dnskeyset = isc_mem_get(mctx, sizeof(*dnskeyset));
|
|
dns_rdatalist_init(dnskeylist);
|
|
dns_rdataset_init(dnskeyset);
|
|
dnskeylist->rdclass = dns_rdataclass_in;
|
|
dnskeylist->type = dns_rdatatype_dnskey;
|
|
dnskeylist->ttl = TTL;
|
|
ISC_LIST_APPEND(dnskeylist->rdata, &test_bundles[bnum].ksk, link);
|
|
dns_rdatalist_tordataset(dnskeylist, dnskeyset);
|
|
dns_rdata_init(&test_bundles[bnum].dnskey_rrsig);
|
|
sign_rrset(fp, btime, (btime + LIFETIME), dnskeyset,
|
|
test_bundles[bnum].rrsig1buf,
|
|
&test_bundles[bnum].dnskey_rrsig);
|
|
for (dns_rdata_t *rd = ISC_LIST_HEAD(dnskeylist->rdata); rd != NULL;
|
|
rd = ISC_LIST_HEAD(dnskeylist->rdata))
|
|
{
|
|
ISC_LIST_UNLINK(dnskeylist->rdata, rd, link);
|
|
}
|
|
isc_mem_put(mctx, dnskeylist, sizeof(*dnskeylist));
|
|
isc_mem_put(mctx, dnskeyset, sizeof(*dnskeyset));
|
|
|
|
/* CDNSKEY */
|
|
dns_rdata_init(&test_bundles[bnum].cdnskey);
|
|
write_record(fp, dns_rdatatype_cdnskey, kskstr,
|
|
test_bundles[bnum].cdnskeybuf,
|
|
&test_bundles[bnum].cdnskey);
|
|
|
|
cdnskeylist = isc_mem_get(mctx, sizeof(*cdnskeylist));
|
|
cdnskeyset = isc_mem_get(mctx, sizeof(*cdnskeyset));
|
|
dns_rdatalist_init(cdnskeylist);
|
|
dns_rdataset_init(cdnskeyset);
|
|
cdnskeylist->rdclass = dns_rdataclass_in;
|
|
cdnskeylist->type = dns_rdatatype_cdnskey;
|
|
cdnskeylist->ttl = TTL;
|
|
ISC_LIST_APPEND(cdnskeylist->rdata, &test_bundles[bnum].cdnskey, link);
|
|
dns_rdatalist_tordataset(cdnskeylist, cdnskeyset);
|
|
dns_rdata_init(&test_bundles[bnum].cdnskey_rrsig);
|
|
sign_rrset(fp, btime, (btime + LIFETIME), cdnskeyset,
|
|
test_bundles[bnum].rrsig2buf,
|
|
&test_bundles[bnum].cdnskey_rrsig);
|
|
for (dns_rdata_t *rd = ISC_LIST_HEAD(cdnskeylist->rdata); rd != NULL;
|
|
rd = ISC_LIST_HEAD(cdnskeylist->rdata))
|
|
{
|
|
ISC_LIST_UNLINK(cdnskeylist->rdata, rd, link);
|
|
}
|
|
isc_mem_put(mctx, cdnskeylist, sizeof(*cdnskeylist));
|
|
isc_mem_put(mctx, cdnskeyset, sizeof(*cdnskeyset));
|
|
|
|
/* CDS */
|
|
dns_rdata_init(&test_bundles[bnum].cds);
|
|
write_record(fp, dns_rdatatype_cds, cdsstr, test_bundles[bnum].cdsbuf,
|
|
&test_bundles[bnum].cds);
|
|
|
|
cdslist = isc_mem_get(mctx, sizeof(*cdslist));
|
|
cdsset = isc_mem_get(mctx, sizeof(*cdsset));
|
|
dns_rdatalist_init(cdslist);
|
|
dns_rdataset_init(cdsset);
|
|
cdslist->rdclass = dns_rdataclass_in;
|
|
cdslist->type = dns_rdatatype_cds;
|
|
cdslist->ttl = TTL;
|
|
ISC_LIST_APPEND(cdslist->rdata, &test_bundles[bnum].cds, link);
|
|
dns_rdatalist_tordataset(cdslist, cdsset);
|
|
dns_rdata_init(&test_bundles[bnum].cds_rrsig);
|
|
sign_rrset(fp, btime, (btime + LIFETIME), cdsset,
|
|
test_bundles[bnum].rrsig3buf, &test_bundles[bnum].cds_rrsig);
|
|
for (dns_rdata_t *rd = ISC_LIST_HEAD(cdslist->rdata); rd != NULL;
|
|
rd = ISC_LIST_HEAD(cdslist->rdata))
|
|
{
|
|
ISC_LIST_UNLINK(cdslist->rdata, rd, link);
|
|
}
|
|
isc_mem_put(mctx, cdslist, sizeof(*cdslist));
|
|
isc_mem_put(mctx, cdsset, sizeof(*cdsset));
|
|
|
|
/* Signature times. */
|
|
test_bundles[bnum].btime = btime;
|
|
test_bundles[bnum].inception = (btime - OFFSET);
|
|
test_bundles[bnum].expiration = (btime + LIFETIME);
|
|
}
|
|
|
|
static void
|
|
check_rrsig(dns_skrbundle_t *bundle, skr__testbundle_t *tb,
|
|
dns_rdatatype_t rrtype, isc_result_t ret) {
|
|
isc_result_t r;
|
|
dns_dnsseckey_t *key = ISC_LIST_HEAD(keys);
|
|
dns_rdata_t sigrdata = DNS_RDATA_INIT;
|
|
|
|
r = dns_skrbundle_getsig(bundle, key->key, rrtype, &sigrdata);
|
|
assert_int_equal(r, ret);
|
|
|
|
if (r == ISC_R_SUCCESS) {
|
|
int cmp = 1;
|
|
dns_rdata_rrsig_t sig;
|
|
|
|
switch (rrtype) {
|
|
case dns_rdatatype_dnskey:
|
|
cmp = dns_rdata_compare(&sigrdata, &tb->dnskey_rrsig);
|
|
break;
|
|
case dns_rdatatype_cdnskey:
|
|
cmp = dns_rdata_compare(&sigrdata, &tb->cdnskey_rrsig);
|
|
break;
|
|
case dns_rdatatype_cds:
|
|
cmp = dns_rdata_compare(&sigrdata, &tb->cds_rrsig);
|
|
break;
|
|
default:
|
|
cmp = 1;
|
|
}
|
|
|
|
assert_int_equal(cmp, 0);
|
|
|
|
r = dns_rdata_tostruct(&sigrdata, &sig, NULL);
|
|
assert_int_equal(r, ISC_R_SUCCESS);
|
|
|
|
assert_int_equal(sig.timesigned, tb->inception);
|
|
assert_int_equal(sig.timeexpire, tb->expiration);
|
|
}
|
|
}
|
|
|
|
static void
|
|
check_bundle(dns_skrbundle_t *bundle, skr__testbundle_t *tb, int bnum) {
|
|
int dnskey = 0;
|
|
|
|
assert_int_equal(bundle->inception, tb->btime);
|
|
|
|
dns_difftuple_t *tuple = ISC_LIST_HEAD(bundle->diff.tuples);
|
|
while (tuple != NULL) {
|
|
int cmp = 1;
|
|
|
|
switch (tuple->rdata.type) {
|
|
case dns_rdatatype_dnskey:
|
|
switch (dnskey) {
|
|
case 0:
|
|
cmp = dns_rdata_compare(&tuple->rdata,
|
|
&tb->ksk);
|
|
break;
|
|
case 1:
|
|
if (bnum < BUNDLE_HAS_ZSK2) {
|
|
cmp = dns_rdata_compare(&tuple->rdata,
|
|
&tb->zsk1);
|
|
} else {
|
|
cmp = dns_rdata_compare(&tuple->rdata,
|
|
&tb->zsk2);
|
|
}
|
|
break;
|
|
case 2:
|
|
cmp = dns_rdata_compare(&tuple->rdata,
|
|
&tb->zsk2);
|
|
break;
|
|
default:
|
|
cmp = 1;
|
|
}
|
|
dnskey++;
|
|
break;
|
|
case dns_rdatatype_cdnskey:
|
|
cmp = dns_rdata_compare(&tuple->rdata, &tb->cdnskey);
|
|
break;
|
|
case dns_rdatatype_cds:
|
|
cmp = dns_rdata_compare(&tuple->rdata, &tb->cds);
|
|
break;
|
|
case dns_rdatatype_rrsig:
|
|
cmp = 0;
|
|
break;
|
|
default:
|
|
cmp = 1;
|
|
}
|
|
|
|
assert_int_equal(cmp, 0);
|
|
tuple = ISC_LIST_NEXT(tuple, link);
|
|
}
|
|
|
|
check_rrsig(bundle, tb, dns_rdatatype_dnskey, ISC_R_SUCCESS);
|
|
check_rrsig(bundle, tb, dns_rdatatype_cdnskey, ISC_R_SUCCESS);
|
|
check_rrsig(bundle, tb, dns_rdatatype_cds, ISC_R_SUCCESS);
|
|
check_rrsig(bundle, tb, dns_rdatatype_a, ISC_R_NOTFOUND);
|
|
}
|
|
|
|
static void
|
|
create_skr_file(void) {
|
|
isc_result_t ret;
|
|
isc_stdtime_t start_time;
|
|
size_t tempfilelen;
|
|
char *tempfile = NULL;
|
|
FILE *outfp = NULL;
|
|
|
|
/* Set up output file */
|
|
tempfilelen = strlen(TESTS_DIR "/testdata/skr/") + 20;
|
|
tempfile = isc_mem_get(mctx, tempfilelen);
|
|
ret = isc_file_mktemplate(testskr, tempfile, tempfilelen);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
ret = isc_file_openunique(tempfile, &outfp);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
start_time = isc_stdtime_now();
|
|
for (int i = 0; i < 42; i++) {
|
|
create_bundle(outfp, start_time, i);
|
|
start_time += LIFETIME;
|
|
}
|
|
|
|
fprintf(outfp, ";; SignedKeyResponse 1.0 generated by test-dev\n");
|
|
|
|
ret = isc_stdio_close(outfp);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
ret = isc_file_rename(tempfile, testskr);
|
|
assert_int_equal(ret, ISC_R_SUCCESS);
|
|
|
|
isc_file_remove(tempfile);
|
|
isc_mem_put(mctx, tempfile, tempfilelen);
|
|
}
|
|
|
|
ISC_RUN_TEST_IMPL(skr_read) {
|
|
char *name = UNCONST("test");
|
|
dns_fixedname_t dfname;
|
|
dns_skr_t *skr = NULL;
|
|
isc_buffer_t b;
|
|
isc_result_t result;
|
|
size_t count = 0;
|
|
|
|
/* Owner name */
|
|
dname = dns_fixedname_initname(&dfname);
|
|
isc_buffer_init(&b, name, strlen(name));
|
|
isc_buffer_add(&b, strlen(name));
|
|
result = dns_name_fromtext(dname, &b, dns_rootname, 0, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/* Get the KSK */
|
|
ISC_LIST_INIT(keys);
|
|
result = dns_dnssec_findmatchingkeys(
|
|
dname, NULL, TESTS_DIR "/testdata/skr/", NULL, 0, mctx, &keys);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/* Create/read the SKR file */
|
|
create_skr_file();
|
|
dns_skr_create(mctx, testskr, dname, dns_rdataclass_in, &skr);
|
|
result = dns_skr_read(mctx, testskr, dname, dns_rdataclass_in, TTL,
|
|
&skr);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
isc_file_remove(testskr);
|
|
|
|
/* Test bundles */
|
|
for (dns_skrbundle_t *bundle = ISC_LIST_HEAD(skr->bundles);
|
|
bundle != NULL; bundle = ISC_LIST_NEXT(bundle, link))
|
|
{
|
|
count++;
|
|
}
|
|
assert_int_equal(count, 42);
|
|
|
|
for (int i = 0; i < 42; i++) {
|
|
skr__testbundle_t tb = test_bundles[i];
|
|
dns_skrbundle_t *lb;
|
|
|
|
lb = dns_skr_lookup(skr, tb.btime, LIFETIME);
|
|
check_bundle(lb, &tb, i);
|
|
|
|
lb = dns_skr_lookup(skr, tb.btime + 1, LIFETIME);
|
|
check_bundle(lb, &tb, i);
|
|
}
|
|
|
|
/* Clean up */
|
|
dns_skr_destroy(skr);
|
|
|
|
while (!ISC_LIST_EMPTY(keys)) {
|
|
dns_dnsseckey_t *key = ISC_LIST_HEAD(keys);
|
|
ISC_LIST_UNLINK(keys, key, link);
|
|
dst_key_free(&key->key);
|
|
dns_dnsseckey_destroy(mctx, &key);
|
|
}
|
|
}
|
|
|
|
ISC_TEST_LIST_START
|
|
ISC_TEST_ENTRY(skr_read)
|
|
ISC_TEST_LIST_END
|
|
|
|
ISC_TEST_MAIN
|