1/* $NetBSD: nsec3_50.c,v 1.1 2024/02/18 20:57:43 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 42static isc_result_t 43fromtext_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 110static isc_result_t 111totext_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 186static isc_result_t 187fromwire_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(options); 196 UNUSED(dctx); 197 198 isc_buffer_activeregion(source, &sr); 199 rr = sr; 200 201 /* hash(1), flags(1), iteration(2), saltlen(1) */ 202 if (sr.length < 5U) { 203 RETERR(DNS_R_FORMERR); 204 } 205 saltlen = sr.base[4]; 206 isc_region_consume(&sr, 5); 207 208 if (sr.length < saltlen) { 209 RETERR(DNS_R_FORMERR); 210 } 211 isc_region_consume(&sr, saltlen); 212 213 if (sr.length < 1U) { 214 RETERR(DNS_R_FORMERR); 215 } 216 hashlen = sr.base[0]; 217 isc_region_consume(&sr, 1); 218 219 if (hashlen < 1 || sr.length < hashlen) { 220 RETERR(DNS_R_FORMERR); 221 } 222 isc_region_consume(&sr, hashlen); 223 224 RETERR(typemap_test(&sr, true)); 225 226 RETERR(mem_tobuffer(target, rr.base, rr.length)); 227 isc_buffer_forward(source, rr.length); 228 return (ISC_R_SUCCESS); 229} 230 231static isc_result_t 232towire_nsec3(ARGS_TOWIRE) { 233 isc_region_t sr; 234 235 REQUIRE(rdata->type == dns_rdatatype_nsec3); 236 REQUIRE(rdata->length != 0); 237 238 UNUSED(cctx); 239 240 dns_rdata_toregion(rdata, &sr); 241 return (mem_tobuffer(target, sr.base, sr.length)); 242} 243 244static int 245compare_nsec3(ARGS_COMPARE) { 246 isc_region_t r1; 247 isc_region_t r2; 248 249 REQUIRE(rdata1->type == rdata2->type); 250 REQUIRE(rdata1->rdclass == rdata2->rdclass); 251 REQUIRE(rdata1->type == dns_rdatatype_nsec3); 252 REQUIRE(rdata1->length != 0); 253 REQUIRE(rdata2->length != 0); 254 255 dns_rdata_toregion(rdata1, &r1); 256 dns_rdata_toregion(rdata2, &r2); 257 return (isc_region_compare(&r1, &r2)); 258} 259 260static isc_result_t 261fromstruct_nsec3(ARGS_FROMSTRUCT) { 262 dns_rdata_nsec3_t *nsec3 = source; 263 isc_region_t region; 264 265 REQUIRE(type == dns_rdatatype_nsec3); 266 REQUIRE(nsec3 != NULL); 267 REQUIRE(nsec3->common.rdtype == type); 268 REQUIRE(nsec3->common.rdclass == rdclass); 269 REQUIRE(nsec3->typebits != NULL || nsec3->len == 0); 270 REQUIRE(nsec3->hash == dns_hash_sha1); 271 272 UNUSED(type); 273 UNUSED(rdclass); 274 275 RETERR(uint8_tobuffer(nsec3->hash, target)); 276 RETERR(uint8_tobuffer(nsec3->flags, target)); 277 RETERR(uint16_tobuffer(nsec3->iterations, target)); 278 RETERR(uint8_tobuffer(nsec3->salt_length, target)); 279 RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length)); 280 RETERR(uint8_tobuffer(nsec3->next_length, target)); 281 RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length)); 282 283 region.base = nsec3->typebits; 284 region.length = nsec3->len; 285 RETERR(typemap_test(®ion, true)); 286 return (mem_tobuffer(target, nsec3->typebits, nsec3->len)); 287} 288 289static isc_result_t 290tostruct_nsec3(ARGS_TOSTRUCT) { 291 isc_region_t region; 292 dns_rdata_nsec3_t *nsec3 = target; 293 294 REQUIRE(rdata->type == dns_rdatatype_nsec3); 295 REQUIRE(nsec3 != NULL); 296 REQUIRE(rdata->length != 0); 297 298 nsec3->common.rdclass = rdata->rdclass; 299 nsec3->common.rdtype = rdata->type; 300 ISC_LINK_INIT(&nsec3->common, link); 301 302 region.base = rdata->data; 303 region.length = rdata->length; 304 nsec3->hash = uint8_consume_fromregion(®ion); 305 nsec3->flags = uint8_consume_fromregion(®ion); 306 nsec3->iterations = uint16_consume_fromregion(®ion); 307 308 nsec3->salt_length = uint8_consume_fromregion(®ion); 309 INSIST(nsec3->salt_length <= region.length); 310 nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length); 311 if (nsec3->salt == NULL) { 312 return (ISC_R_NOMEMORY); 313 } 314 isc_region_consume(®ion, nsec3->salt_length); 315 316 nsec3->next_length = uint8_consume_fromregion(®ion); 317 INSIST(nsec3->next_length <= region.length); 318 nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length); 319 if (nsec3->next == NULL) { 320 goto cleanup; 321 } 322 isc_region_consume(®ion, nsec3->next_length); 323 324 nsec3->len = region.length; 325 nsec3->typebits = mem_maybedup(mctx, region.base, region.length); 326 if (nsec3->typebits == NULL) { 327 goto cleanup; 328 } 329 330 nsec3->mctx = mctx; 331 return (ISC_R_SUCCESS); 332 333cleanup: 334 if (nsec3->next != NULL) { 335 isc_mem_free(mctx, nsec3->next); 336 } 337 isc_mem_free(mctx, nsec3->salt); 338 return (ISC_R_NOMEMORY); 339} 340 341static void 342freestruct_nsec3(ARGS_FREESTRUCT) { 343 dns_rdata_nsec3_t *nsec3 = source; 344 345 REQUIRE(nsec3 != NULL); 346 REQUIRE(nsec3->common.rdtype == dns_rdatatype_nsec3); 347 348 if (nsec3->mctx == NULL) { 349 return; 350 } 351 352 if (nsec3->salt != NULL) { 353 isc_mem_free(nsec3->mctx, nsec3->salt); 354 } 355 if (nsec3->next != NULL) { 356 isc_mem_free(nsec3->mctx, nsec3->next); 357 } 358 if (nsec3->typebits != NULL) { 359 isc_mem_free(nsec3->mctx, nsec3->typebits); 360 } 361 nsec3->mctx = NULL; 362} 363 364static isc_result_t 365additionaldata_nsec3(ARGS_ADDLDATA) { 366 REQUIRE(rdata->type == dns_rdatatype_nsec3); 367 368 UNUSED(rdata); 369 UNUSED(add); 370 UNUSED(arg); 371 372 return (ISC_R_SUCCESS); 373} 374 375static isc_result_t 376digest_nsec3(ARGS_DIGEST) { 377 isc_region_t r; 378 379 REQUIRE(rdata->type == dns_rdatatype_nsec3); 380 381 dns_rdata_toregion(rdata, &r); 382 return ((digest)(arg, &r)); 383} 384 385static bool 386checkowner_nsec3(ARGS_CHECKOWNER) { 387 unsigned char owner[NSEC3_MAX_HASH_LENGTH]; 388 isc_buffer_t buffer; 389 dns_label_t label; 390 391 REQUIRE(type == dns_rdatatype_nsec3); 392 393 UNUSED(type); 394 UNUSED(rdclass); 395 UNUSED(wildcard); 396 397 /* 398 * First label is a base32hex string without padding. 399 */ 400 dns_name_getlabel(name, 0, &label); 401 isc_region_consume(&label, 1); 402 isc_buffer_init(&buffer, owner, sizeof(owner)); 403 if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS) { 404 return (true); 405 } 406 407 return (false); 408} 409 410static bool 411checknames_nsec3(ARGS_CHECKNAMES) { 412 REQUIRE(rdata->type == dns_rdatatype_nsec3); 413 414 UNUSED(rdata); 415 UNUSED(owner); 416 UNUSED(bad); 417 418 return (true); 419} 420 421static int 422casecompare_nsec3(ARGS_COMPARE) { 423 return (compare_nsec3(rdata1, rdata2)); 424} 425 426#endif /* RDATA_GENERIC_NSEC3_50_C */ 427