Add NSEC3PARAM unit test, refactor zone.c
Add unit test to ensure the right NSEC3PARAM event is scheduled in 'dns_zone_setnsec3param()'. To avoid scheduling and managing actual tasks, split up the 'dns_zone_setnsec3param()' function in two parts: 1. 'dns__zone_lookup_nsec3param()' that will check if the requested NSEC3 parameters already exist, and if a new salt needs to be generated. 2. The actual scheduling of the new NSEC3PARAM event (if needed).
This commit is contained in:
302
lib/dns/tests/nsec3param_test.c
Normal file
302
lib/dns/tests/nsec3param_test.c
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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 https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#if HAVE_CMOCKA
|
||||
|
||||
#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/hex.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/db.h>
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/result.h>
|
||||
|
||||
#include "../zone_p.h"
|
||||
#include "dnstest.h"
|
||||
|
||||
#define HASH 1
|
||||
#define FLAGS 0
|
||||
#define ITER 5
|
||||
#define SALTLEN 4
|
||||
#define SALT "FEDCBA98"
|
||||
|
||||
static int
|
||||
_setup(void **state) {
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(state);
|
||||
|
||||
result = dns_test_begin(NULL, false);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
_teardown(void **state) {
|
||||
UNUSED(state);
|
||||
|
||||
dns_test_end();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Structures containing parameters for nsec3param_salttotext_test().
|
||||
*/
|
||||
typedef struct {
|
||||
dns_hash_t hash;
|
||||
unsigned char flags;
|
||||
dns_iterations_t iterations;
|
||||
unsigned char salt_length;
|
||||
const char *salt;
|
||||
} nsec3param_rdata_test_params_t;
|
||||
|
||||
typedef struct {
|
||||
nsec3param_rdata_test_params_t lookup;
|
||||
nsec3param_rdata_test_params_t expect;
|
||||
bool resalt;
|
||||
isc_result_t expected_result;
|
||||
} nsec3param_change_test_params_t;
|
||||
|
||||
static void
|
||||
decode_salt(const char *string, unsigned char *salt, size_t saltlen) {
|
||||
isc_buffer_t buf;
|
||||
isc_result_t result;
|
||||
|
||||
isc_buffer_init(&buf, salt, saltlen);
|
||||
result = isc_hex_decodestring(string, &buf);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_params(nsec3param_rdata_test_params_t from, dns_rdata_nsec3param_t *to,
|
||||
unsigned char *saltbuf, size_t saltlen) {
|
||||
to->hash = from.hash;
|
||||
to->flags = from.flags;
|
||||
to->iterations = from.iterations;
|
||||
to->salt_length = from.salt_length;
|
||||
if (from.salt == NULL) {
|
||||
to->salt = NULL;
|
||||
} else if (strcmp(from.salt, "-") == 0) {
|
||||
DE_CONST("-", to->salt);
|
||||
} else {
|
||||
decode_salt(from.salt, saltbuf, saltlen);
|
||||
to->salt = saltbuf;
|
||||
}
|
||||
}
|
||||
|
||||
static nsec3param_rdata_test_params_t
|
||||
rdata_fromparams(uint8_t hash, uint8_t flags, uint16_t iter, uint8_t saltlen,
|
||||
const char *salt) {
|
||||
nsec3param_rdata_test_params_t nsec3param;
|
||||
nsec3param.hash = hash;
|
||||
nsec3param.flags = flags;
|
||||
nsec3param.iterations = iter;
|
||||
nsec3param.salt_length = saltlen;
|
||||
nsec3param.salt = salt;
|
||||
return (nsec3param);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Check whether zone_lookup_nsec3param() finds the correct NSEC3PARAM
|
||||
* and sets the correct parameters to use in dns_zone_setnsec3param().
|
||||
*/
|
||||
static void
|
||||
nsec3param_change_test(const nsec3param_change_test_params_t *test) {
|
||||
dns_zone_t *zone = NULL;
|
||||
dns_rdata_nsec3param_t param, lookup, expect;
|
||||
isc_result_t result;
|
||||
unsigned char lookupsalt[255];
|
||||
unsigned char expectsalt[255];
|
||||
unsigned char saltbuf[255];
|
||||
|
||||
/*
|
||||
* Prepare a zone along with its signing keys.
|
||||
*/
|
||||
result = dns_test_makezone("nsec3", &zone, NULL, false);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_zone_setfile(zone, "testdata/nsec3param/nsec3.db.signed",
|
||||
dns_masterformat_text,
|
||||
&dns_master_style_default);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_zone_load(zone, false);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
* Copy parameters.
|
||||
*/
|
||||
copy_params(test->lookup, &lookup, lookupsalt, sizeof(lookupsalt));
|
||||
copy_params(test->expect, &expect, expectsalt, sizeof(expectsalt));
|
||||
|
||||
/*
|
||||
* Test dns__zone_lookup_nsec3param().
|
||||
*/
|
||||
result = dns__zone_lookup_nsec3param(zone, &lookup, ¶m, saltbuf,
|
||||
test->resalt);
|
||||
|
||||
assert_int_equal(param.hash, expect.hash);
|
||||
assert_int_equal(param.flags, expect.flags);
|
||||
assert_int_equal(param.iterations, expect.iterations);
|
||||
assert_int_equal(param.salt_length, expect.salt_length);
|
||||
assert_non_null(param.salt);
|
||||
if (expect.salt != NULL) {
|
||||
int ret = memcmp(param.salt, expect.salt, expect.salt_length);
|
||||
assert_true(ret == 0);
|
||||
} else {
|
||||
/*
|
||||
* We don't know what the new salt is, but we can compare it
|
||||
* to the previous salt and test that it has changed.
|
||||
*/
|
||||
unsigned char salt[SALTLEN];
|
||||
int ret;
|
||||
decode_salt(SALT, salt, SALTLEN);
|
||||
ret = memcmp(param.salt, salt, SALTLEN);
|
||||
assert_false(ret == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detach.
|
||||
*/
|
||||
dns_zone_detach(&zone);
|
||||
}
|
||||
|
||||
static void
|
||||
nsec3param_change(void **state) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Define tests.
|
||||
*/
|
||||
const nsec3param_change_test_params_t tests[] = {
|
||||
/*
|
||||
* 1. Change nothing (don't care about salt).
|
||||
* This should return ISC_R_SUCCESS because we are already
|
||||
* using these NSEC3 parameters.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
|
||||
ISC_R_SUCCESS },
|
||||
/*
|
||||
* 2. Change nothing, but force a resalt.
|
||||
* This should change the salt. Set 'expect.salt' to NULL to
|
||||
* test a new salt has been generated.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
|
||||
DNS_R_NSEC3RESALT },
|
||||
/*
|
||||
* 3. Change iterations.
|
||||
* The NSEC3 paarameters are not found, and there is no
|
||||
* need to resalt because an explicit salt has been set,
|
||||
* and resalt is not enforced.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT),
|
||||
rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT), false,
|
||||
ISC_R_NOTFOUND },
|
||||
/*
|
||||
* 4. Change iterations, don't care about the salt.
|
||||
* We don't care about the salt. Since we need to change the
|
||||
* NSEC3 parameters, we will also resalt.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL),
|
||||
rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL), false,
|
||||
DNS_R_NSEC3RESALT },
|
||||
/*
|
||||
* 5. Change salt length.
|
||||
* Changing salt length means we need to resalt.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, 16, NULL),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, 16, NULL), false,
|
||||
DNS_R_NSEC3RESALT },
|
||||
/*
|
||||
* 6. Set explicit salt.
|
||||
* A different salt, so the NSEC3 parameters are not found.
|
||||
* No need to resalt because an explicit salt is available.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"), false,
|
||||
ISC_R_NOTFOUND },
|
||||
/*
|
||||
* 7. Same salt.
|
||||
* Nothing changed, so expect ISC_R_SUCCESS as a result.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
|
||||
ISC_R_SUCCESS },
|
||||
/*
|
||||
* 8. Same salt, and force resalt.
|
||||
* Nothing changed, but a resalt is enforced.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
|
||||
DNS_R_NSEC3RESALT },
|
||||
/*
|
||||
* 9. No salt.
|
||||
* Change parameters to use no salt. These parameters are
|
||||
* not found, and no new salt needs to be generated.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, 0, NULL),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
|
||||
ISC_R_NOTFOUND },
|
||||
/*
|
||||
* 10. No salt, explicit.
|
||||
* Same as above, but set no salt explicitly.
|
||||
*/
|
||||
{ rdata_fromparams(HASH, FLAGS, ITER, 0, "-"),
|
||||
rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
|
||||
ISC_R_NOTFOUND },
|
||||
};
|
||||
|
||||
UNUSED(state);
|
||||
|
||||
/*
|
||||
* Run tests.
|
||||
*/
|
||||
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
nsec3param_change_test(&tests[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(nsec3param_change, _setup,
|
||||
_teardown),
|
||||
};
|
||||
|
||||
return (cmocka_run_group_tests(tests, NULL, NULL));
|
||||
}
|
||||
|
||||
#else /* HAVE_CMOCKA */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(void) {
|
||||
printf("1..0 # Skipped: cmocka not available\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* if HAVE_CMOCKA */
|
||||
Reference in New Issue
Block a user