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, ¶m, 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