Home | History | Annotate | Line # | Download | only in generic
      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 
     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(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 
    231 static isc_result_t
    232 towire_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 
    244 static int
    245 compare_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 
    260 static isc_result_t
    261 fromstruct_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(&region, true));
    286 	return (mem_tobuffer(target, nsec3->typebits, nsec3->len));
    287 }
    288 
    289 static isc_result_t
    290 tostruct_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(&region);
    305 	nsec3->flags = uint8_consume_fromregion(&region);
    306 	nsec3->iterations = uint16_consume_fromregion(&region);
    307 
    308 	nsec3->salt_length = uint8_consume_fromregion(&region);
    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(&region, nsec3->salt_length);
    315 
    316 	nsec3->next_length = uint8_consume_fromregion(&region);
    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(&region, 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 
    333 cleanup:
    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 
    341 static void
    342 freestruct_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 
    364 static isc_result_t
    365 additionaldata_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 
    375 static isc_result_t
    376 digest_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 
    385 static bool
    386 checkowner_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 
    410 static bool
    411 checknames_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 
    421 static int
    422 casecompare_nsec3(ARGS_COMPARE) {
    423 	return (compare_nsec3(rdata1, rdata2));
    424 }
    425 
    426 #endif /* RDATA_GENERIC_NSEC3_50_C */
    427