summaryrefslogtreecommitdiffstats
path: root/lib/dns/tests/sigs_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/tests/sigs_test.c')
-rw-r--r--lib/dns/tests/sigs_test.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/lib/dns/tests/sigs_test.c b/lib/dns/tests/sigs_test.c
new file mode 100644
index 0000000..20fd4b6
--- /dev/null
+++ b/lib/dns/tests/sigs_test.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <isc/util.h>
+
+#if defined(OPENSSL) || defined(PKCS11CRYPTO)
+#include <string.h>
+
+#include <dns/db.h>
+#include <dns/diff.h>
+#include <dns/dnssec.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/types.h>
+#include <dns/zone.h>
+
+#include <dst/dst.h>
+
+#include <isc/buffer.h>
+#include <isc/list.h>
+#include <isc/region.h>
+#include <isc/stdtime.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+#include "../zone_p.h"
+
+#include "dnstest.h"
+
+/*%
+ * Structure characterizing a single diff tuple in the dns_diff_t structure
+ * prepared by dns__zone_updatesigs().
+ */
+typedef struct {
+ dns_diffop_t op;
+ const char *owner;
+ dns_ttl_t ttl;
+ const char *type;
+} zonediff_t;
+
+#define ZONEDIFF_SENTINEL { 0, NULL, 0, NULL }
+
+/*%
+ * Structure defining a dns__zone_updatesigs() test.
+ */
+typedef struct {
+ const char *description; /* test description */
+ const zonechange_t *changes; /* array of "raw" zone changes */
+ const zonediff_t *zonediff; /* array of "processed" zone changes */
+} updatesigs_test_params_t;
+
+/*%
+ * Check whether the 'found' tuple matches the 'expected' tuple. 'found' is
+ * the 'index'th tuple output by dns__zone_updatesigs() in test 'test'.
+ */
+static void
+compare_tuples(const zonediff_t *expected, dns_difftuple_t *found,
+ const updatesigs_test_params_t *test, size_t index)
+{
+ char found_covers[DNS_RDATATYPE_FORMATSIZE] = { };
+ char found_type[DNS_RDATATYPE_FORMATSIZE] = { };
+ char found_name[DNS_NAME_FORMATSIZE];
+ isc_consttextregion_t typeregion;
+ dns_fixedname_t expected_fname;
+ dns_rdatatype_t expected_type;
+ dns_name_t *expected_name;
+ dns_rdata_rrsig_t rrsig;
+ isc_buffer_t typebuf;
+ isc_result_t result;
+
+ REQUIRE(expected != NULL);
+ REQUIRE(found != NULL);
+ REQUIRE(index > 0);
+
+ /*
+ * Check operation.
+ */
+ ATF_CHECK_EQ_MSG(expected->op, found->op,
+ "test \"%s\": tuple %zu: "
+ "expected op %d, found %d",
+ test->description, index,
+ expected->op, found->op);
+
+ /*
+ * Check owner name.
+ */
+ expected_name = dns_fixedname_initname(&expected_fname);
+ result = dns_name_fromstring(expected_name, expected->owner, 0, mctx);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ dns_name_format(&found->name, found_name, sizeof(found_name));
+ ATF_CHECK_MSG(dns_name_equal(expected_name, &found->name),
+ "test \"%s\": tuple %zu: "
+ "expected owner \"%s\", found \"%s\"",
+ test->description, index,
+ expected->owner, found_name);
+
+ /*
+ * Check TTL.
+ */
+ ATF_CHECK_EQ_MSG(expected->ttl, found->ttl,
+ "test \"%s\": tuple %zu: "
+ "expected TTL %u, found %u",
+ test->description, index,
+ expected->ttl, found->ttl);
+
+ /*
+ * Parse expected RR type.
+ */
+ typeregion.base = expected->type;
+ typeregion.length = strlen(expected->type);
+ result = dns_rdatatype_fromtext(&expected_type,
+ (isc_textregion_t*)&typeregion);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Format found RR type for reporting purposes.
+ */
+ isc_buffer_init(&typebuf, found_type, sizeof(found_type));
+ result = dns_rdatatype_totext(found->rdata.type, &typebuf);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Check RR type.
+ */
+ switch (expected->op) {
+ case DNS_DIFFOP_ADDRESIGN:
+ case DNS_DIFFOP_DELRESIGN:
+ /*
+ * Found tuple must be of type RRSIG.
+ */
+ ATF_CHECK_EQ_MSG(found->rdata.type, dns_rdatatype_rrsig,
+ "test \"%s\": tuple %zu: "
+ "expected type RRSIG, found %s",
+ test->description, index,
+ found_type);
+ if (found->rdata.type != dns_rdatatype_rrsig) {
+ break;
+ }
+ /*
+ * The signature must cover an RRset of type 'expected->type'.
+ */
+ result = dns_rdata_tostruct(&found->rdata, &rrsig, NULL);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_buffer_init(&typebuf, found_covers, sizeof(found_covers));
+ result = dns_rdatatype_totext(rrsig.covered, &typebuf);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_EQ_MSG(expected_type, rrsig.covered,
+ "test \"%s\": tuple %zu: "
+ "expected RRSIG to cover %s, found covers %s",
+ test->description, index,
+ expected->type, found_covers);
+ break;
+ default:
+ /*
+ * Found tuple must be of type 'expected->type'.
+ */
+ ATF_CHECK_EQ_MSG(expected_type, found->rdata.type,
+ "test \"%s\": tuple %zu: "
+ "expected type %s, found %s",
+ test->description, index,
+ expected->type, found_type);
+ break;
+ }
+}
+
+/*%
+ * Perform a single dns__zone_updatesigs() test defined in 'test'. All other
+ * arguments are expected to remain constant between subsequent invocations of
+ * this function.
+ */
+static void
+updatesigs_test(const updatesigs_test_params_t *test, dns_zone_t *zone,
+ dns_db_t *db, dst_key_t *zone_keys[], unsigned int nkeys,
+ isc_stdtime_t now)
+{
+ size_t tuples_expected, tuples_found, index;
+ dns_dbversion_t *version = NULL;
+ dns_diff_t raw_diff, zone_diff;
+ const zonediff_t *expected;
+ dns_difftuple_t *found;
+ isc_result_t result;
+
+ dns__zonediff_t zonediff = {
+ .diff = &zone_diff,
+ .offline = false,
+ };
+
+ REQUIRE(test != NULL);
+ REQUIRE(test->description != NULL);
+ REQUIRE(test->changes != NULL);
+ REQUIRE(zone != NULL);
+ REQUIRE(db != NULL);
+ REQUIRE(zone_keys != NULL);
+
+ /*
+ * Create a new version of the zone's database.
+ */
+ result = dns_db_newversion(db, &version);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Create a diff representing the supplied changes.
+ */
+ result = dns_test_difffromchanges(&raw_diff, test->changes);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Apply the "raw" diff to the new version of the zone's database as
+ * this is what dns__zone_updatesigs() expects to happen before it is
+ * called.
+ */
+ dns_diff_apply(&raw_diff, db, version);
+
+ /*
+ * Initialize the structure dns__zone_updatesigs() will modify.
+ */
+ dns_diff_init(mctx, &zone_diff);
+
+ /*
+ * Check whether dns__zone_updatesigs() behaves as expected.
+ */
+ result = dns__zone_updatesigs(&raw_diff, db, version, zone_keys, nkeys,
+ zone, now - 3600, now + 3600, now,
+ true, false, &zonediff);
+ ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS,
+ "test \"%s\": expected success, got %s",
+ test->description, isc_result_totext(result));
+ ATF_CHECK_MSG(ISC_LIST_EMPTY(raw_diff.tuples),
+ "test \"%s\": raw diff was not emptied",
+ test->description);
+ ATF_CHECK_MSG(!ISC_LIST_EMPTY(zone_diff.tuples),
+ "test \"%s\": zone diff was not created",
+ test->description);
+
+ /*
+ * Ensure that the number of tuples in the zone diff is as expected.
+ */
+
+ tuples_expected = 0;
+ for (expected = test->zonediff;
+ expected->owner != NULL;
+ expected++)
+ {
+ tuples_expected++;
+ }
+
+ tuples_found = 0;
+ for (found = ISC_LIST_HEAD(zone_diff.tuples);
+ found != NULL;
+ found = ISC_LIST_NEXT(found, link))
+ {
+ tuples_found++;
+ }
+
+ ATF_REQUIRE_EQ_MSG(tuples_expected, tuples_found,
+ "test \"%s\": "
+ "expected %zu tuples in output, found %zu",
+ test->description,
+ tuples_expected, tuples_found);
+
+ /*
+ * Ensure that every tuple in the zone diff matches expectations.
+ */
+ expected = test->zonediff;
+ index = 1;
+ for (found = ISC_LIST_HEAD(zone_diff.tuples);
+ found != NULL;
+ found = ISC_LIST_NEXT(found, link))
+ {
+ compare_tuples(expected, found, test, index);
+ expected++;
+ index++;
+ }
+
+ /*
+ * Apply changes to zone database contents and clean up.
+ */
+ dns_db_closeversion(db, &version, true);
+ dns_diff_clear(&zone_diff);
+ dns_diff_clear(&raw_diff);
+}
+
+ATF_TC(updatesigs);
+ATF_TC_HEAD(updatesigs, tc) {
+ atf_tc_set_md_var(tc, "descr", "dns__zone_updatesigs() tests");
+}
+ATF_TC_BODY(updatesigs, tc) {
+ dst_key_t *zone_keys[DNS_MAXZONEKEYS];
+ dns_zone_t *zone = NULL;
+ dns_db_t *db = NULL;
+ isc_result_t result;
+ unsigned int nkeys;
+ isc_stdtime_t now;
+ size_t i;
+
+ result = dns_test_begin(NULL, true);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /*
+ * Prepare a zone along with its signing keys.
+ */
+
+ result = dns_test_makezone("example", &zone, NULL, false);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_loaddb(&db, dns_dbtype_zone, "example",
+ "testdata/master/master18.data");
+ ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE);
+
+ result = dns_zone_setkeydirectory(zone, "testkeys");
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_stdtime_get(&now);
+ result = dns__zone_findkeys(zone, db, NULL, now, mctx, DNS_MAXZONEKEYS,
+ zone_keys, &nkeys);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(nkeys, 2);
+
+ /*
+ * Define the tests to be run. Note that changes to zone database
+ * contents introduced by each test are preserved between tests.
+ */
+
+ const zonechange_t changes_add[] = {
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "bar" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_add[] = {
+ { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_add = {
+ .description = "add new RRsets",
+ .changes = changes_add,
+ .zonediff = zonediff_add,
+ };
+
+ const zonechange_t changes_append[] = {
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo1" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT", "foo2" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_append[] = {
+ { DNS_DIFFOP_DELRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ { DNS_DIFFOP_ADD, "foo.example", 300, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_append = {
+ .description = "append multiple RRs to an existing RRset",
+ .changes = changes_append,
+ .zonediff = zonediff_append,
+ };
+
+ const zonechange_t changes_replace[] = {
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "bar" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT", "rab" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_replace[] = {
+ { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_ADD, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_replace = {
+ .description = "replace an existing RRset",
+ .changes = changes_replace,
+ .zonediff = zonediff_replace,
+ };
+
+ const zonechange_t changes_delete[] = {
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT", "rab" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_delete[] = {
+ { DNS_DIFFOP_DELRESIGN, "bar.example", 600, "TXT" },
+ { DNS_DIFFOP_DEL, "bar.example", 600, "TXT" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_delete = {
+ .description = "delete an existing RRset",
+ .changes = changes_delete,
+ .zonediff = zonediff_delete,
+ };
+
+ const zonechange_t changes_mixed[] = {
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz1" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "A", "127.0.0.1" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT", "baz2" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA", "::1" },
+ ZONECHANGE_SENTINEL,
+ };
+ const zonediff_t zonediff_mixed[] = {
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "TXT" },
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "A" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "A" },
+ { DNS_DIFFOP_ADDRESIGN, "baz.example", 900, "AAAA" },
+ { DNS_DIFFOP_ADD, "baz.example", 900, "AAAA" },
+ ZONEDIFF_SENTINEL,
+ };
+ const updatesigs_test_params_t test_mixed = {
+ .description = "add different RRsets with common owner name",
+ .changes = changes_mixed,
+ .zonediff = zonediff_mixed,
+ };
+
+ const updatesigs_test_params_t *tests[] = {
+ &test_add,
+ &test_append,
+ &test_replace,
+ &test_delete,
+ &test_mixed,
+ };
+
+ /*
+ * Run tests.
+ */
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+ updatesigs_test(tests[i], zone, db, zone_keys, nkeys, now);
+ }
+
+ /*
+ * Clean up.
+ */
+ for (i = 0; i < nkeys; i++) {
+ dst_key_free(&zone_keys[i]);
+ }
+ dns_db_detach(&db);
+ dns_zone_detach(&zone);
+
+ dns_test_end();
+}
+#else
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping dns__zone_updatesigs() test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("DNSSEC support not compiled in");
+}
+#endif
+
+ATF_TP_ADD_TCS(tp) {
+#if defined(OPENSSL) || defined(PKCS11CRYPTO)
+ ATF_TP_ADD_TC(tp, updatesigs);
+#else
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+
+ return (atf_no_error());
+}