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