Home | History | Annotate | Line # | Download | only in generic
      1 /*	$NetBSD: zonemd_63.c,v 1.8 2026/01/29 18:37:53 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 /* RFC 8976 */
     17 
     18 #ifndef RDATA_GENERIC_ZONEMD_63_C
     19 #define RDATA_GENERIC_ZONEMD_63_C
     20 
     21 #define RRTYPE_ZONEMD_ATTRIBUTES 0
     22 
     23 static isc_result_t
     24 fromtext_zonemd(ARGS_FROMTEXT) {
     25 	isc_token_t token;
     26 	int digest_type, length;
     27 	isc_buffer_t save;
     28 	isc_result_t result;
     29 
     30 	UNUSED(type);
     31 	UNUSED(rdclass);
     32 	UNUSED(origin);
     33 	UNUSED(options);
     34 	UNUSED(callbacks);
     35 
     36 	/*
     37 	 * Zone Serial.
     38 	 */
     39 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
     40 				      false));
     41 	RETERR(uint32_tobuffer(token.value.as_ulong, target));
     42 
     43 	/*
     44 	 * Digest Scheme.
     45 	 */
     46 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
     47 				      false));
     48 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
     49 
     50 	/*
     51 	 * Digest Type.
     52 	 */
     53 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
     54 				      false));
     55 	digest_type = token.value.as_ulong;
     56 	RETERR(uint8_tobuffer(digest_type, target));
     57 
     58 	/*
     59 	 * Digest.
     60 	 */
     61 	switch (digest_type) {
     62 	case DNS_ZONEMD_DIGEST_SHA384:
     63 		length = ISC_SHA384_DIGESTLENGTH;
     64 		break;
     65 	case DNS_ZONEMD_DIGEST_SHA512:
     66 		length = ISC_SHA512_DIGESTLENGTH;
     67 		break;
     68 	default:
     69 		length = -2;
     70 		break;
     71 	}
     72 
     73 	save = *target;
     74 	result = isc_hex_tobuffer(lexer, target, length);
     75 	/* Minimum length of digest is 12 octets. */
     76 	if (isc_buffer_usedlength(target) - isc_buffer_usedlength(&save) < 12) {
     77 		return ISC_R_UNEXPECTEDEND;
     78 	}
     79 	return result;
     80 }
     81 
     82 static isc_result_t
     83 totext_zonemd(ARGS_TOTEXT) {
     84 	isc_region_t sr;
     85 	char buf[sizeof("0123456789")];
     86 	unsigned long num;
     87 
     88 	REQUIRE(rdata->length > 6);
     89 
     90 	UNUSED(tctx);
     91 
     92 	dns_rdata_toregion(rdata, &sr);
     93 
     94 	/*
     95 	 * Zone Serial.
     96 	 */
     97 	num = uint32_fromregion(&sr);
     98 	isc_region_consume(&sr, 4);
     99 	snprintf(buf, sizeof(buf), "%lu", num);
    100 	RETERR(str_totext(buf, target));
    101 
    102 	RETERR(str_totext(" ", target));
    103 
    104 	/*
    105 	 * Digest scheme.
    106 	 */
    107 	num = uint8_fromregion(&sr);
    108 	isc_region_consume(&sr, 1);
    109 	snprintf(buf, sizeof(buf), "%lu", num);
    110 	RETERR(str_totext(buf, target));
    111 
    112 	RETERR(str_totext(" ", target));
    113 
    114 	/*
    115 	 * Digest type.
    116 	 */
    117 	num = uint8_fromregion(&sr);
    118 	isc_region_consume(&sr, 1);
    119 	snprintf(buf, sizeof(buf), "%lu", num);
    120 	RETERR(str_totext(buf, target));
    121 
    122 	/*
    123 	 * Digest.
    124 	 */
    125 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
    126 		RETERR(str_totext(" (", target));
    127 	}
    128 	RETERR(str_totext(tctx->linebreak, target));
    129 	if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
    130 		if (tctx->width == 0) { /* No splitting */
    131 			RETERR(isc_hex_totext(&sr, 0, "", target));
    132 		} else {
    133 			RETERR(isc_hex_totext(&sr, tctx->width - 2,
    134 					      tctx->linebreak, target));
    135 		}
    136 	} else {
    137 		RETERR(str_totext("[omitted]", target));
    138 	}
    139 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
    140 		RETERR(str_totext(" )", target));
    141 	}
    142 	return ISC_R_SUCCESS;
    143 }
    144 
    145 static isc_result_t
    146 fromwire_zonemd(ARGS_FROMWIRE) {
    147 	isc_region_t sr;
    148 	size_t digestlen = 0;
    149 
    150 	UNUSED(type);
    151 	UNUSED(rdclass);
    152 	UNUSED(dctx);
    153 
    154 	isc_buffer_activeregion(source, &sr);
    155 
    156 	/*
    157 	 * If we do not recognize the digest type, ensure that the digest
    158 	 * meets minimum length (12).
    159 	 *
    160 	 * If we do recognize the digest type, ensure that the digest is of the
    161 	 * correct length.
    162 	 */
    163 	if (sr.length < 18) {
    164 		return ISC_R_UNEXPECTEDEND;
    165 	}
    166 
    167 	switch (sr.base[5]) {
    168 	case DNS_ZONEMD_DIGEST_SHA384:
    169 		digestlen = ISC_SHA384_DIGESTLENGTH;
    170 		break;
    171 	case DNS_ZONEMD_DIGEST_SHA512:
    172 		digestlen = ISC_SHA512_DIGESTLENGTH;
    173 		break;
    174 	default:
    175 		break;
    176 	}
    177 
    178 	if (digestlen != 0 && sr.length < 6 + digestlen) {
    179 		return ISC_R_UNEXPECTEDEND;
    180 	}
    181 
    182 	/*
    183 	 * Only specify the number of octets to consume if we recognize the
    184 	 * digest type.
    185 	 *
    186 	 * If there is extra data, dns_rdata_fromwire() will detect that.
    187 	 */
    188 	if (digestlen != 0) {
    189 		sr.length = 6 + digestlen;
    190 	}
    191 
    192 	isc_buffer_forward(source, sr.length);
    193 	return mem_tobuffer(target, sr.base, sr.length);
    194 }
    195 
    196 static isc_result_t
    197 towire_zonemd(ARGS_TOWIRE) {
    198 	isc_region_t sr;
    199 
    200 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
    201 	REQUIRE(rdata->length != 0);
    202 
    203 	UNUSED(cctx);
    204 
    205 	dns_rdata_toregion(rdata, &sr);
    206 	return mem_tobuffer(target, sr.base, sr.length);
    207 }
    208 
    209 static int
    210 compare_zonemd(ARGS_COMPARE) {
    211 	isc_region_t r1;
    212 	isc_region_t r2;
    213 
    214 	REQUIRE(rdata1->type == rdata2->type);
    215 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
    216 	REQUIRE(rdata1->type == dns_rdatatype_zonemd);
    217 	REQUIRE(rdata1->length != 0);
    218 	REQUIRE(rdata2->length != 0);
    219 
    220 	dns_rdata_toregion(rdata1, &r1);
    221 	dns_rdata_toregion(rdata2, &r2);
    222 	return isc_region_compare(&r1, &r2);
    223 }
    224 
    225 static isc_result_t
    226 fromstruct_zonemd(ARGS_FROMSTRUCT) {
    227 	dns_rdata_zonemd_t *zonemd = source;
    228 
    229 	REQUIRE(zonemd != NULL);
    230 	REQUIRE(zonemd->common.rdtype == type);
    231 	REQUIRE(zonemd->common.rdclass == rdclass);
    232 
    233 	UNUSED(type);
    234 	UNUSED(rdclass);
    235 
    236 	switch (zonemd->digest_type) {
    237 	case DNS_ZONEMD_DIGEST_SHA384:
    238 		REQUIRE(zonemd->length == ISC_SHA384_DIGESTLENGTH);
    239 		break;
    240 	case DNS_ZONEMD_DIGEST_SHA512:
    241 		REQUIRE(zonemd->length == ISC_SHA512_DIGESTLENGTH);
    242 		break;
    243 	}
    244 
    245 	RETERR(uint32_tobuffer(zonemd->serial, target));
    246 	RETERR(uint8_tobuffer(zonemd->scheme, target));
    247 	RETERR(uint8_tobuffer(zonemd->digest_type, target));
    248 
    249 	return mem_tobuffer(target, zonemd->digest, zonemd->length);
    250 }
    251 
    252 static isc_result_t
    253 tostruct_zonemd(ARGS_TOSTRUCT) {
    254 	dns_rdata_zonemd_t *zonemd = target;
    255 	isc_region_t region;
    256 
    257 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
    258 	REQUIRE(zonemd != NULL);
    259 	REQUIRE(rdata->length != 0);
    260 
    261 	DNS_RDATACOMMON_INIT(zonemd, rdata->type, rdata->rdclass);
    262 
    263 	dns_rdata_toregion(rdata, &region);
    264 
    265 	zonemd->serial = uint32_fromregion(&region);
    266 	isc_region_consume(&region, 4);
    267 	zonemd->scheme = uint8_fromregion(&region);
    268 	isc_region_consume(&region, 1);
    269 	zonemd->digest_type = uint8_fromregion(&region);
    270 	isc_region_consume(&region, 1);
    271 	zonemd->length = region.length;
    272 
    273 	zonemd->digest = mem_maybedup(mctx, region.base, region.length);
    274 	zonemd->mctx = mctx;
    275 	return ISC_R_SUCCESS;
    276 }
    277 
    278 static void
    279 freestruct_zonemd(ARGS_FREESTRUCT) {
    280 	dns_rdata_zonemd_t *zonemd = source;
    281 
    282 	REQUIRE(zonemd != NULL);
    283 	REQUIRE(zonemd->common.rdtype == dns_rdatatype_zonemd);
    284 
    285 	if (zonemd->mctx == NULL) {
    286 		return;
    287 	}
    288 
    289 	if (zonemd->digest != NULL) {
    290 		isc_mem_free(zonemd->mctx, zonemd->digest);
    291 	}
    292 	zonemd->mctx = NULL;
    293 }
    294 
    295 static isc_result_t
    296 additionaldata_zonemd(ARGS_ADDLDATA) {
    297 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
    298 
    299 	UNUSED(rdata);
    300 	UNUSED(owner);
    301 	UNUSED(add);
    302 	UNUSED(arg);
    303 
    304 	return ISC_R_SUCCESS;
    305 }
    306 
    307 static isc_result_t
    308 digest_zonemd(ARGS_DIGEST) {
    309 	isc_region_t r;
    310 
    311 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
    312 
    313 	dns_rdata_toregion(rdata, &r);
    314 
    315 	return (digest)(arg, &r);
    316 }
    317 
    318 static bool
    319 checkowner_zonemd(ARGS_CHECKOWNER) {
    320 	REQUIRE(type == dns_rdatatype_zonemd);
    321 
    322 	UNUSED(name);
    323 	UNUSED(type);
    324 	UNUSED(rdclass);
    325 	UNUSED(wildcard);
    326 
    327 	return true;
    328 }
    329 
    330 static bool
    331 checknames_zonemd(ARGS_CHECKNAMES) {
    332 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
    333 
    334 	UNUSED(rdata);
    335 	UNUSED(owner);
    336 	UNUSED(bad);
    337 
    338 	return true;
    339 }
    340 
    341 static int
    342 casecompare_zonemd(ARGS_COMPARE) {
    343 	return compare_zonemd(rdata1, rdata2);
    344 }
    345 
    346 #endif /* RDATA_GENERIC_ZONEMD_63_C */
    347