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