xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/zonemd_63.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: zonemd_63.c,v 1.7 2025/01/26 16:25:34 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 	zonemd->common.rdclass = rdata->rdclass;
262 	zonemd->common.rdtype = rdata->type;
263 	ISC_LINK_INIT(&zonemd->common, link);
264 
265 	dns_rdata_toregion(rdata, &region);
266 
267 	zonemd->serial = uint32_fromregion(&region);
268 	isc_region_consume(&region, 4);
269 	zonemd->scheme = uint8_fromregion(&region);
270 	isc_region_consume(&region, 1);
271 	zonemd->digest_type = uint8_fromregion(&region);
272 	isc_region_consume(&region, 1);
273 	zonemd->length = region.length;
274 
275 	zonemd->digest = mem_maybedup(mctx, region.base, region.length);
276 	zonemd->mctx = mctx;
277 	return ISC_R_SUCCESS;
278 }
279 
280 static void
281 freestruct_zonemd(ARGS_FREESTRUCT) {
282 	dns_rdata_zonemd_t *zonemd = source;
283 
284 	REQUIRE(zonemd != NULL);
285 	REQUIRE(zonemd->common.rdtype == dns_rdatatype_zonemd);
286 
287 	if (zonemd->mctx == NULL) {
288 		return;
289 	}
290 
291 	if (zonemd->digest != NULL) {
292 		isc_mem_free(zonemd->mctx, zonemd->digest);
293 	}
294 	zonemd->mctx = NULL;
295 }
296 
297 static isc_result_t
298 additionaldata_zonemd(ARGS_ADDLDATA) {
299 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
300 
301 	UNUSED(rdata);
302 	UNUSED(owner);
303 	UNUSED(add);
304 	UNUSED(arg);
305 
306 	return ISC_R_SUCCESS;
307 }
308 
309 static isc_result_t
310 digest_zonemd(ARGS_DIGEST) {
311 	isc_region_t r;
312 
313 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
314 
315 	dns_rdata_toregion(rdata, &r);
316 
317 	return (digest)(arg, &r);
318 }
319 
320 static bool
321 checkowner_zonemd(ARGS_CHECKOWNER) {
322 	REQUIRE(type == dns_rdatatype_zonemd);
323 
324 	UNUSED(name);
325 	UNUSED(type);
326 	UNUSED(rdclass);
327 	UNUSED(wildcard);
328 
329 	return true;
330 }
331 
332 static bool
333 checknames_zonemd(ARGS_CHECKNAMES) {
334 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
335 
336 	UNUSED(rdata);
337 	UNUSED(owner);
338 	UNUSED(bad);
339 
340 	return true;
341 }
342 
343 static int
344 casecompare_zonemd(ARGS_COMPARE) {
345 	return compare_zonemd(rdata1, rdata2);
346 }
347 
348 #endif /* RDATA_GENERIC_ZONEMD_63_C */
349