Home | History | Annotate | Line # | Download | only in generic
      1 /*	$NetBSD: nsec3_50.c,v 1.11 2026/01/29 18:37:52 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(&region, 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 	DNS_RDATACOMMON_INIT(nsec3, rdata->type, rdata->rdclass);
    298 
    299 	region.base = rdata->data;
    300 	region.length = rdata->length;
    301 	nsec3->hash = uint8_consume_fromregion(&region);
    302 	nsec3->flags = uint8_consume_fromregion(&region);
    303 	nsec3->iterations = uint16_consume_fromregion(&region);
    304 
    305 	nsec3->salt_length = uint8_consume_fromregion(&region);
    306 	INSIST(nsec3->salt_length <= region.length);
    307 	nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length);
    308 	isc_region_consume(&region, nsec3->salt_length);
    309 
    310 	nsec3->next_length = uint8_consume_fromregion(&region);
    311 	INSIST(nsec3->next_length <= region.length);
    312 	nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length);
    313 	isc_region_consume(&region, nsec3->next_length);
    314 
    315 	nsec3->len = region.length;
    316 	nsec3->typebits = mem_maybedup(mctx, region.base, region.length);
    317 	nsec3->mctx = mctx;
    318 	return ISC_R_SUCCESS;
    319 }
    320 
    321 static void
    322 freestruct_nsec3(ARGS_FREESTRUCT) {
    323 	dns_rdata_nsec3_t *nsec3 = source;
    324 
    325 	REQUIRE(nsec3 != NULL);
    326 	REQUIRE(nsec3->common.rdtype == dns_rdatatype_nsec3);
    327 
    328 	if (nsec3->mctx == NULL) {
    329 		return;
    330 	}
    331 
    332 	if (nsec3->salt != NULL) {
    333 		isc_mem_free(nsec3->mctx, nsec3->salt);
    334 	}
    335 	if (nsec3->next != NULL) {
    336 		isc_mem_free(nsec3->mctx, nsec3->next);
    337 	}
    338 	if (nsec3->typebits != NULL) {
    339 		isc_mem_free(nsec3->mctx, nsec3->typebits);
    340 	}
    341 	nsec3->mctx = NULL;
    342 }
    343 
    344 static isc_result_t
    345 additionaldata_nsec3(ARGS_ADDLDATA) {
    346 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
    347 
    348 	UNUSED(rdata);
    349 	UNUSED(owner);
    350 	UNUSED(add);
    351 	UNUSED(arg);
    352 
    353 	return ISC_R_SUCCESS;
    354 }
    355 
    356 static isc_result_t
    357 digest_nsec3(ARGS_DIGEST) {
    358 	isc_region_t r;
    359 
    360 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
    361 
    362 	dns_rdata_toregion(rdata, &r);
    363 	return (digest)(arg, &r);
    364 }
    365 
    366 static bool
    367 checkowner_nsec3(ARGS_CHECKOWNER) {
    368 	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
    369 	isc_buffer_t buffer;
    370 	dns_label_t label;
    371 
    372 	REQUIRE(type == dns_rdatatype_nsec3);
    373 
    374 	UNUSED(type);
    375 	UNUSED(rdclass);
    376 	UNUSED(wildcard);
    377 
    378 	/*
    379 	 * First label is a base32hex string without padding.
    380 	 */
    381 	dns_name_getlabel(name, 0, &label);
    382 	isc_region_consume(&label, 1);
    383 	isc_buffer_init(&buffer, owner, sizeof(owner));
    384 	if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS) {
    385 		return true;
    386 	}
    387 
    388 	return false;
    389 }
    390 
    391 static bool
    392 checknames_nsec3(ARGS_CHECKNAMES) {
    393 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
    394 
    395 	UNUSED(rdata);
    396 	UNUSED(owner);
    397 	UNUSED(bad);
    398 
    399 	return true;
    400 }
    401 
    402 static int
    403 casecompare_nsec3(ARGS_COMPARE) {
    404 	return compare_nsec3(rdata1, rdata2);
    405 }
    406 
    407 #endif /* RDATA_GENERIC_NSEC3_50_C */
    408