Home | History | Annotate | Line # | Download | only in dns
      1  1.1  christos /*	$NetBSD: nsec3param_test.c,v 1.3 2025/01/26 16:25:47 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.1  christos  *
      8  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.1  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  1.1  christos  *
     12  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13  1.1  christos  * information regarding copyright ownership.
     14  1.1  christos  */
     15  1.1  christos 
     16  1.1  christos #include <inttypes.h>
     17  1.1  christos #include <sched.h> /* IWYU pragma: keep */
     18  1.1  christos #include <setjmp.h>
     19  1.1  christos #include <stdarg.h>
     20  1.1  christos #include <stddef.h>
     21  1.1  christos #include <stdlib.h>
     22  1.1  christos #include <string.h>
     23  1.1  christos #include <unistd.h>
     24  1.1  christos 
     25  1.1  christos #define UNIT_TESTING
     26  1.1  christos #include <cmocka.h>
     27  1.1  christos 
     28  1.1  christos #include <isc/hex.h>
     29  1.1  christos #include <isc/result.h>
     30  1.1  christos #include <isc/string.h>
     31  1.1  christos #include <isc/util.h>
     32  1.1  christos 
     33  1.1  christos #include <dns/db.h>
     34  1.1  christos #include <dns/nsec3.h>
     35  1.1  christos 
     36  1.1  christos #include "zone_p.h"
     37  1.1  christos 
     38  1.1  christos #include <tests/dns.h>
     39  1.1  christos 
     40  1.1  christos #define HASH	1
     41  1.1  christos #define FLAGS	0
     42  1.1  christos #define ITER	5
     43  1.1  christos #define SALTLEN 4
     44  1.1  christos #define SALT	"FEDCBA98"
     45  1.1  christos 
     46  1.1  christos /*%
     47  1.1  christos  * Structures containing parameters for nsec3param_salttotext_test().
     48  1.1  christos  */
     49  1.1  christos typedef struct {
     50  1.1  christos 	dns_hash_t hash;
     51  1.1  christos 	unsigned char flags;
     52  1.1  christos 	dns_iterations_t iterations;
     53  1.1  christos 	unsigned char salt_length;
     54  1.1  christos 	const char *salt;
     55  1.1  christos } nsec3param_rdata_test_params_t;
     56  1.1  christos 
     57  1.1  christos typedef struct {
     58  1.1  christos 	nsec3param_rdata_test_params_t lookup;
     59  1.1  christos 	nsec3param_rdata_test_params_t expect;
     60  1.1  christos 	bool resalt;
     61  1.1  christos 	isc_result_t expected_result;
     62  1.1  christos } nsec3param_change_test_params_t;
     63  1.1  christos 
     64  1.1  christos static void
     65  1.1  christos decode_salt(const char *string, unsigned char *salt, size_t saltlen) {
     66  1.1  christos 	isc_buffer_t buf;
     67  1.1  christos 	isc_result_t result;
     68  1.1  christos 
     69  1.1  christos 	isc_buffer_init(&buf, salt, saltlen);
     70  1.1  christos 	result = isc_hex_decodestring(string, &buf);
     71  1.1  christos 	assert_int_equal(result, ISC_R_SUCCESS);
     72  1.1  christos }
     73  1.1  christos 
     74  1.1  christos static void
     75  1.1  christos copy_params(nsec3param_rdata_test_params_t from, dns_rdata_nsec3param_t *to,
     76  1.1  christos 	    unsigned char *saltbuf, size_t saltlen) {
     77  1.1  christos 	to->hash = from.hash;
     78  1.1  christos 	to->flags = from.flags;
     79  1.1  christos 	to->iterations = from.iterations;
     80  1.1  christos 	to->salt_length = from.salt_length;
     81  1.1  christos 	if (from.salt == NULL) {
     82  1.1  christos 		to->salt = NULL;
     83  1.1  christos 	} else if (strcmp(from.salt, "-") == 0) {
     84  1.3  christos 		to->salt = (unsigned char *)"-";
     85  1.1  christos 	} else {
     86  1.1  christos 		decode_salt(from.salt, saltbuf, saltlen);
     87  1.1  christos 		to->salt = saltbuf;
     88  1.1  christos 	}
     89  1.1  christos }
     90  1.1  christos 
     91  1.1  christos static nsec3param_rdata_test_params_t
     92  1.1  christos rdata_fromparams(uint8_t hash, uint8_t flags, uint16_t iter, uint8_t saltlen,
     93  1.1  christos 		 const char *salt) {
     94  1.1  christos 	nsec3param_rdata_test_params_t nsec3param;
     95  1.1  christos 	nsec3param.hash = hash;
     96  1.1  christos 	nsec3param.flags = flags;
     97  1.1  christos 	nsec3param.iterations = iter;
     98  1.1  christos 	nsec3param.salt_length = saltlen;
     99  1.1  christos 	nsec3param.salt = salt;
    100  1.3  christos 	return nsec3param;
    101  1.1  christos }
    102  1.1  christos 
    103  1.1  christos /*%
    104  1.1  christos  * Check whether zone_lookup_nsec3param() finds the correct NSEC3PARAM
    105  1.1  christos  * and sets the correct parameters to use in dns_zone_setnsec3param().
    106  1.1  christos  */
    107  1.1  christos static void
    108  1.1  christos nsec3param_change_test(const nsec3param_change_test_params_t *test) {
    109  1.1  christos 	dns_zone_t *zone = NULL;
    110  1.1  christos 	dns_rdata_nsec3param_t param, lookup, expect;
    111  1.1  christos 	isc_result_t result;
    112  1.1  christos 	unsigned char lookupsalt[255];
    113  1.1  christos 	unsigned char expectsalt[255];
    114  1.1  christos 	unsigned char saltbuf[255];
    115  1.1  christos 
    116  1.1  christos 	/*
    117  1.1  christos 	 * Prepare a zone along with its signing keys.
    118  1.1  christos 	 */
    119  1.1  christos 	result = dns_test_makezone("nsec3", &zone, NULL, false);
    120  1.1  christos 	assert_int_equal(result, ISC_R_SUCCESS);
    121  1.1  christos 
    122  1.1  christos 	result = dns_zone_setfile(
    123  1.1  christos 		zone, TESTS_DIR "/testdata/nsec3param/nsec3.db.signed",
    124  1.1  christos 		dns_masterformat_text, &dns_master_style_default);
    125  1.1  christos 	assert_int_equal(result, ISC_R_SUCCESS);
    126  1.1  christos 
    127  1.1  christos 	result = dns_zone_load(zone, false);
    128  1.1  christos 	assert_int_equal(result, ISC_R_SUCCESS);
    129  1.1  christos 
    130  1.1  christos 	/*
    131  1.1  christos 	 * Copy parameters.
    132  1.1  christos 	 */
    133  1.1  christos 	copy_params(test->lookup, &lookup, lookupsalt, sizeof(lookupsalt));
    134  1.1  christos 	copy_params(test->expect, &expect, expectsalt, sizeof(expectsalt));
    135  1.1  christos 
    136  1.1  christos 	/*
    137  1.1  christos 	 * Test dns__zone_lookup_nsec3param().
    138  1.1  christos 	 */
    139  1.1  christos 	result = dns__zone_lookup_nsec3param(zone, &lookup, &param, saltbuf,
    140  1.1  christos 					     test->resalt);
    141  1.1  christos 	assert_int_equal(result, test->expected_result);
    142  1.1  christos 	assert_int_equal(param.hash, expect.hash);
    143  1.1  christos 	assert_int_equal(param.flags, expect.flags);
    144  1.1  christos 	assert_int_equal(param.iterations, expect.iterations);
    145  1.1  christos 	assert_int_equal(param.salt_length, expect.salt_length);
    146  1.1  christos 	assert_non_null(param.salt);
    147  1.1  christos 	if (expect.salt != NULL) {
    148  1.1  christos 		int ret = memcmp(param.salt, expect.salt, expect.salt_length);
    149  1.1  christos 		assert_true(ret == 0);
    150  1.1  christos 	} else {
    151  1.1  christos 		/*
    152  1.1  christos 		 * We don't know what the new salt is, but we can compare it
    153  1.1  christos 		 * to the previous salt and test that it has changed.
    154  1.1  christos 		 */
    155  1.1  christos 		unsigned char salt[SALTLEN];
    156  1.1  christos 		int ret;
    157  1.1  christos 		decode_salt(SALT, salt, SALTLEN);
    158  1.1  christos 		ret = memcmp(param.salt, salt, SALTLEN);
    159  1.1  christos 		assert_false(ret == 0);
    160  1.1  christos 	}
    161  1.1  christos 
    162  1.1  christos 	/*
    163  1.1  christos 	 * Detach.
    164  1.1  christos 	 */
    165  1.1  christos 	dns_zone_detach(&zone);
    166  1.1  christos }
    167  1.1  christos 
    168  1.1  christos ISC_RUN_TEST_IMPL(nsec3param_change) {
    169  1.1  christos 	size_t i;
    170  1.1  christos 
    171  1.1  christos 	/*
    172  1.1  christos 	 * Define tests.
    173  1.1  christos 	 */
    174  1.1  christos 	const nsec3param_change_test_params_t tests[] = {
    175  1.1  christos 		/*
    176  1.1  christos 		 * 1. Change nothing (don't care about salt).
    177  1.1  christos 		 * This should return ISC_R_SUCCESS because we are already
    178  1.1  christos 		 * using these NSEC3 parameters.
    179  1.1  christos 		 */
    180  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
    181  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
    182  1.1  christos 		  ISC_R_SUCCESS },
    183  1.1  christos 		/*
    184  1.1  christos 		 * 2. Change nothing, but force a resalt.
    185  1.1  christos 		 * This should change the salt. Set 'expect.salt' to NULL to
    186  1.1  christos 		 * test a new salt has been generated.
    187  1.1  christos 		 */
    188  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
    189  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
    190  1.1  christos 		  DNS_R_NSEC3RESALT },
    191  1.1  christos 		/*
    192  1.1  christos 		 * 3. Change iterations.
    193  1.1  christos 		 * The NSEC3 paarameters are not found, and there is no
    194  1.1  christos 		 * need to resalt because an explicit salt has been set,
    195  1.1  christos 		 * and resalt is not enforced.
    196  1.1  christos 		 */
    197  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT),
    198  1.1  christos 		  rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT), false,
    199  1.1  christos 		  ISC_R_NOTFOUND },
    200  1.1  christos 		/*
    201  1.1  christos 		 * 4. Change iterations, don't care about the salt.
    202  1.1  christos 		 * We don't care about the salt. Since we need to change the
    203  1.1  christos 		 * NSEC3 parameters, we will also resalt.
    204  1.1  christos 		 */
    205  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL),
    206  1.1  christos 		  rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL), false,
    207  1.1  christos 		  DNS_R_NSEC3RESALT },
    208  1.1  christos 		/*
    209  1.1  christos 		 * 5. Change salt length.
    210  1.1  christos 		 * Changing salt length means we need to resalt.
    211  1.1  christos 		 */
    212  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, 16, NULL),
    213  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, 16, NULL), false,
    214  1.1  christos 		  DNS_R_NSEC3RESALT },
    215  1.1  christos 		/*
    216  1.1  christos 		 * 6. Set explicit salt.
    217  1.1  christos 		 * A different salt, so the NSEC3 parameters are not found.
    218  1.1  christos 		 * No need to resalt because an explicit salt is available.
    219  1.1  christos 		 */
    220  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"),
    221  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"), false,
    222  1.1  christos 		  ISC_R_NOTFOUND },
    223  1.1  christos 		/*
    224  1.1  christos 		 * 7. Same salt.
    225  1.1  christos 		 * Nothing changed, so expect ISC_R_SUCCESS as a result.
    226  1.1  christos 		 */
    227  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
    228  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
    229  1.1  christos 		  ISC_R_SUCCESS },
    230  1.1  christos 		/*
    231  1.1  christos 		 * 8. Same salt, and force resalt.
    232  1.1  christos 		 * Nothing changed, but a resalt is enforced.
    233  1.1  christos 		 */
    234  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
    235  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
    236  1.1  christos 		  DNS_R_NSEC3RESALT },
    237  1.1  christos 		/*
    238  1.1  christos 		 * 9. No salt.
    239  1.1  christos 		 * Change parameters to use no salt. These parameters are
    240  1.1  christos 		 * not found, and no new salt needs to be generated.
    241  1.1  christos 		 */
    242  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, 0, NULL),
    243  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
    244  1.1  christos 		  ISC_R_NOTFOUND },
    245  1.1  christos 		/*
    246  1.1  christos 		 * 10. No salt, explicit.
    247  1.1  christos 		 * Same as above, but set no salt explicitly.
    248  1.1  christos 		 */
    249  1.1  christos 		{ rdata_fromparams(HASH, FLAGS, ITER, 0, "-"),
    250  1.1  christos 		  rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
    251  1.1  christos 		  ISC_R_NOTFOUND },
    252  1.1  christos 	};
    253  1.1  christos 
    254  1.1  christos 	UNUSED(state);
    255  1.1  christos 
    256  1.1  christos 	/*
    257  1.1  christos 	 * Run tests.
    258  1.1  christos 	 */
    259  1.1  christos 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
    260  1.1  christos 		nsec3param_change_test(&tests[i]);
    261  1.1  christos 	}
    262  1.1  christos }
    263  1.1  christos 
    264  1.1  christos ISC_TEST_LIST_START
    265  1.1  christos ISC_TEST_ENTRY(nsec3param_change)
    266  1.1  christos ISC_TEST_LIST_END
    267  1.1  christos 
    268  1.1  christos ISC_TEST_MAIN
    269