1 /* $NetBSD: nsec3_50.c,v 1.10 2025/01/26 16:25:32 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 /* 17 * Copyright (C) 2004 Nominet, Ltd. 18 * 19 * Permission to use, copy, modify, and distribute this software for any 20 * purpose with or without fee is hereby granted, provided that the above 21 * copyright notice and this permission notice appear in all copies. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH 24 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 25 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 26 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 27 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 28 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 29 * PERFORMANCE OF THIS SOFTWARE. 30 */ 31 32 /* RFC 5155 */ 33 34 #ifndef RDATA_GENERIC_NSEC3_50_C 35 #define RDATA_GENERIC_NSEC3_50_C 36 37 #include <isc/base32.h> 38 #include <isc/iterated_hash.h> 39 40 #define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC 41 42 static isc_result_t 43 fromtext_nsec3(ARGS_FROMTEXT) { 44 isc_token_t token; 45 unsigned int flags; 46 unsigned char hashalg; 47 isc_buffer_t b; 48 unsigned char buf[256]; 49 50 REQUIRE(type == dns_rdatatype_nsec3); 51 52 UNUSED(type); 53 UNUSED(rdclass); 54 UNUSED(callbacks); 55 UNUSED(origin); 56 UNUSED(options); 57 58 /* Hash. */ 59 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 60 false)); 61 RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion)); 62 RETERR(uint8_tobuffer(hashalg, target)); 63 64 /* Flags. */ 65 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 66 false)); 67 flags = token.value.as_ulong; 68 if (flags > 255U) { 69 RETTOK(ISC_R_RANGE); 70 } 71 RETERR(uint8_tobuffer(flags, target)); 72 73 /* Iterations. */ 74 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 75 false)); 76 if (token.value.as_ulong > 0xffffU) { 77 RETTOK(ISC_R_RANGE); 78 } 79 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 80 81 /* salt */ 82 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 83 false)); 84 if (token.value.as_textregion.length > (255 * 2)) { 85 RETTOK(DNS_R_TEXTTOOLONG); 86 } 87 if (strcmp(DNS_AS_STR(token), "-") == 0) { 88 RETERR(uint8_tobuffer(0, target)); 89 } else { 90 RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target)); 91 RETERR(isc_hex_decodestring(DNS_AS_STR(token), target)); 92 } 93 94 /* 95 * Next hash a single base32hex word. 96 */ 97 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 98 false)); 99 isc_buffer_init(&b, buf, sizeof(buf)); 100 RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b)); 101 if (isc_buffer_usedlength(&b) > 0xffU) { 102 RETTOK(ISC_R_RANGE); 103 } 104 RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target)); 105 RETERR(mem_tobuffer(target, &buf, isc_buffer_usedlength(&b))); 106 107 return typemap_fromtext(lexer, target, true); 108 } 109 110 static isc_result_t 111 totext_nsec3(ARGS_TOTEXT) { 112 isc_region_t sr; 113 unsigned int i, j; 114 unsigned char hash; 115 unsigned char flags; 116 char buf[sizeof("TYPE65535")]; 117 uint32_t iterations; 118 119 REQUIRE(rdata->type == dns_rdatatype_nsec3); 120 REQUIRE(rdata->length != 0); 121 122 dns_rdata_toregion(rdata, &sr); 123 124 /* Hash */ 125 hash = uint8_fromregion(&sr); 126 isc_region_consume(&sr, 1); 127 snprintf(buf, sizeof(buf), "%u ", hash); 128 RETERR(str_totext(buf, target)); 129 130 /* Flags */ 131 flags = uint8_fromregion(&sr); 132 isc_region_consume(&sr, 1); 133 snprintf(buf, sizeof(buf), "%u ", flags); 134 RETERR(str_totext(buf, target)); 135 136 /* Iterations */ 137 iterations = uint16_fromregion(&sr); 138 isc_region_consume(&sr, 2); 139 snprintf(buf, sizeof(buf), "%u ", iterations); 140 RETERR(str_totext(buf, target)); 141 142 /* Salt */ 143 j = uint8_fromregion(&sr); 144 isc_region_consume(&sr, 1); 145 INSIST(j <= sr.length); 146 147 if (j != 0) { 148 i = sr.length; 149 sr.length = j; 150 RETERR(isc_hex_totext(&sr, 1, "", target)); 151 sr.length = i - j; 152 } else { 153 RETERR(str_totext("-", target)); 154 } 155 156 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 157 RETERR(str_totext(" (", target)); 158 } 159 RETERR(str_totext(tctx->linebreak, target)); 160 161 /* Next hash */ 162 j = uint8_fromregion(&sr); 163 isc_region_consume(&sr, 1); 164 INSIST(j <= sr.length); 165 166 i = sr.length; 167 sr.length = j; 168 RETERR(isc_base32hexnp_totext(&sr, 1, "", target)); 169 sr.length = i - j; 170 171 /* 172 * Don't leave a trailing space when there's no typemap present. 173 */ 174 if (((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0) && (sr.length > 0)) { 175 RETERR(str_totext(" ", target)); 176 } 177 RETERR(typemap_totext(&sr, tctx, target)); 178 179 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 180 RETERR(str_totext(" )", target)); 181 } 182 183 return ISC_R_SUCCESS; 184 } 185 186 static isc_result_t 187 fromwire_nsec3(ARGS_FROMWIRE) { 188 isc_region_t sr, rr; 189 unsigned int saltlen, hashlen; 190 191 REQUIRE(type == dns_rdatatype_nsec3); 192 193 UNUSED(type); 194 UNUSED(rdclass); 195 UNUSED(dctx); 196 197 isc_buffer_activeregion(source, &sr); 198 rr = sr; 199 200 /* hash(1), flags(1), iteration(2), saltlen(1) */ 201 if (sr.length < 5U) { 202 RETERR(DNS_R_FORMERR); 203 } 204 saltlen = sr.base[4]; 205 isc_region_consume(&sr, 5); 206 207 if (sr.length < saltlen) { 208 RETERR(DNS_R_FORMERR); 209 } 210 isc_region_consume(&sr, saltlen); 211 212 if (sr.length < 1U) { 213 RETERR(DNS_R_FORMERR); 214 } 215 hashlen = sr.base[0]; 216 isc_region_consume(&sr, 1); 217 218 if (hashlen < 1 || sr.length < hashlen) { 219 RETERR(DNS_R_FORMERR); 220 } 221 isc_region_consume(&sr, hashlen); 222 223 RETERR(typemap_test(&sr, true)); 224 225 RETERR(mem_tobuffer(target, rr.base, rr.length)); 226 isc_buffer_forward(source, rr.length); 227 return ISC_R_SUCCESS; 228 } 229 230 static isc_result_t 231 towire_nsec3(ARGS_TOWIRE) { 232 isc_region_t sr; 233 234 REQUIRE(rdata->type == dns_rdatatype_nsec3); 235 REQUIRE(rdata->length != 0); 236 237 UNUSED(cctx); 238 239 dns_rdata_toregion(rdata, &sr); 240 return mem_tobuffer(target, sr.base, sr.length); 241 } 242 243 static int 244 compare_nsec3(ARGS_COMPARE) { 245 isc_region_t r1; 246 isc_region_t r2; 247 248 REQUIRE(rdata1->type == rdata2->type); 249 REQUIRE(rdata1->rdclass == rdata2->rdclass); 250 REQUIRE(rdata1->type == dns_rdatatype_nsec3); 251 REQUIRE(rdata1->length != 0); 252 REQUIRE(rdata2->length != 0); 253 254 dns_rdata_toregion(rdata1, &r1); 255 dns_rdata_toregion(rdata2, &r2); 256 return isc_region_compare(&r1, &r2); 257 } 258 259 static isc_result_t 260 fromstruct_nsec3(ARGS_FROMSTRUCT) { 261 dns_rdata_nsec3_t *nsec3 = source; 262 isc_region_t region; 263 264 REQUIRE(type == dns_rdatatype_nsec3); 265 REQUIRE(nsec3 != NULL); 266 REQUIRE(nsec3->common.rdtype == type); 267 REQUIRE(nsec3->common.rdclass == rdclass); 268 REQUIRE(nsec3->typebits != NULL || nsec3->len == 0); 269 REQUIRE(nsec3->hash == dns_hash_sha1); 270 271 UNUSED(type); 272 UNUSED(rdclass); 273 274 RETERR(uint8_tobuffer(nsec3->hash, target)); 275 RETERR(uint8_tobuffer(nsec3->flags, target)); 276 RETERR(uint16_tobuffer(nsec3->iterations, target)); 277 RETERR(uint8_tobuffer(nsec3->salt_length, target)); 278 RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length)); 279 RETERR(uint8_tobuffer(nsec3->next_length, target)); 280 RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length)); 281 282 region.base = nsec3->typebits; 283 region.length = nsec3->len; 284 RETERR(typemap_test(®ion, true)); 285 return mem_tobuffer(target, nsec3->typebits, nsec3->len); 286 } 287 288 static isc_result_t 289 tostruct_nsec3(ARGS_TOSTRUCT) { 290 isc_region_t region; 291 dns_rdata_nsec3_t *nsec3 = target; 292 293 REQUIRE(rdata->type == dns_rdatatype_nsec3); 294 REQUIRE(nsec3 != NULL); 295 REQUIRE(rdata->length != 0); 296 297 nsec3->common.rdclass = rdata->rdclass; 298 nsec3->common.rdtype = rdata->type; 299 ISC_LINK_INIT(&nsec3->common, link); 300 301 region.base = rdata->data; 302 region.length = rdata->length; 303 nsec3->hash = uint8_consume_fromregion(®ion); 304 nsec3->flags = uint8_consume_fromregion(®ion); 305 nsec3->iterations = uint16_consume_fromregion(®ion); 306 307 nsec3->salt_length = uint8_consume_fromregion(®ion); 308 INSIST(nsec3->salt_length <= region.length); 309 nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length); 310 isc_region_consume(®ion, nsec3->salt_length); 311 312 nsec3->next_length = uint8_consume_fromregion(®ion); 313 INSIST(nsec3->next_length <= region.length); 314 nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length); 315 isc_region_consume(®ion, nsec3->next_length); 316 317 nsec3->len = region.length; 318 nsec3->typebits = mem_maybedup(mctx, region.base, region.length); 319 nsec3->mctx = mctx; 320 return ISC_R_SUCCESS; 321 } 322 323 static void 324 freestruct_nsec3(ARGS_FREESTRUCT) { 325 dns_rdata_nsec3_t *nsec3 = source; 326 327 REQUIRE(nsec3 != NULL); 328 REQUIRE(nsec3->common.rdtype == dns_rdatatype_nsec3); 329 330 if (nsec3->mctx == NULL) { 331 return; 332 } 333 334 if (nsec3->salt != NULL) { 335 isc_mem_free(nsec3->mctx, nsec3->salt); 336 } 337 if (nsec3->next != NULL) { 338 isc_mem_free(nsec3->mctx, nsec3->next); 339 } 340 if (nsec3->typebits != NULL) { 341 isc_mem_free(nsec3->mctx, nsec3->typebits); 342 } 343 nsec3->mctx = NULL; 344 } 345 346 static isc_result_t 347 additionaldata_nsec3(ARGS_ADDLDATA) { 348 REQUIRE(rdata->type == dns_rdatatype_nsec3); 349 350 UNUSED(rdata); 351 UNUSED(owner); 352 UNUSED(add); 353 UNUSED(arg); 354 355 return ISC_R_SUCCESS; 356 } 357 358 static isc_result_t 359 digest_nsec3(ARGS_DIGEST) { 360 isc_region_t r; 361 362 REQUIRE(rdata->type == dns_rdatatype_nsec3); 363 364 dns_rdata_toregion(rdata, &r); 365 return (digest)(arg, &r); 366 } 367 368 static bool 369 checkowner_nsec3(ARGS_CHECKOWNER) { 370 unsigned char owner[NSEC3_MAX_HASH_LENGTH]; 371 isc_buffer_t buffer; 372 dns_label_t label; 373 374 REQUIRE(type == dns_rdatatype_nsec3); 375 376 UNUSED(type); 377 UNUSED(rdclass); 378 UNUSED(wildcard); 379 380 /* 381 * First label is a base32hex string without padding. 382 */ 383 dns_name_getlabel(name, 0, &label); 384 isc_region_consume(&label, 1); 385 isc_buffer_init(&buffer, owner, sizeof(owner)); 386 if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS) { 387 return true; 388 } 389 390 return false; 391 } 392 393 static bool 394 checknames_nsec3(ARGS_CHECKNAMES) { 395 REQUIRE(rdata->type == dns_rdatatype_nsec3); 396 397 UNUSED(rdata); 398 UNUSED(owner); 399 UNUSED(bad); 400 401 return true; 402 } 403 404 static int 405 casecompare_nsec3(ARGS_COMPARE) { 406 return compare_nsec3(rdata1, rdata2); 407 } 408 409 #endif /* RDATA_GENERIC_NSEC3_50_C */ 410