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