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