1 /*	$NetBSD: zonemd_63.c,v 1.5 2022/09/23 12:15:31 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
fromtext_zonemd(ARGS_FROMTEXT)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
totext_zonemd(ARGS_TOTEXT)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
fromwire_zonemd(ARGS_FROMWIRE)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 	UNUSED(options);
154 
155 	isc_buffer_activeregion(source, &sr);
156 
157 	/*
158 	 * If we do not recognize the digest type, ensure that the digest
159 	 * meets minimum length (12).
160 	 *
161 	 * If we do recognize the digest type, ensure that the digest is of the
162 	 * correct length.
163 	 */
164 	if (sr.length < 18) {
165 		return (ISC_R_UNEXPECTEDEND);
166 	}
167 
168 	switch (sr.base[5]) {
169 	case DNS_ZONEMD_DIGEST_SHA384:
170 		digestlen = ISC_SHA384_DIGESTLENGTH;
171 		break;
172 	case DNS_ZONEMD_DIGEST_SHA512:
173 		digestlen = ISC_SHA512_DIGESTLENGTH;
174 		break;
175 	default:
176 		break;
177 	}
178 
179 	if (digestlen != 0 && sr.length < 6 + digestlen) {
180 		return (ISC_R_UNEXPECTEDEND);
181 	}
182 
183 	/*
184 	 * Only specify the number of octets to consume if we recognize the
185 	 * digest type.
186 	 *
187 	 * If there is extra data, dns_rdata_fromwire() will detect that.
188 	 */
189 	if (digestlen != 0) {
190 		sr.length = 6 + digestlen;
191 	}
192 
193 	isc_buffer_forward(source, sr.length);
194 	return (mem_tobuffer(target, sr.base, sr.length));
195 }
196 
197 static isc_result_t
towire_zonemd(ARGS_TOWIRE)198 towire_zonemd(ARGS_TOWIRE) {
199 	isc_region_t sr;
200 
201 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
202 	REQUIRE(rdata->length != 0);
203 
204 	UNUSED(cctx);
205 
206 	dns_rdata_toregion(rdata, &sr);
207 	return (mem_tobuffer(target, sr.base, sr.length));
208 }
209 
210 static int
compare_zonemd(ARGS_COMPARE)211 compare_zonemd(ARGS_COMPARE) {
212 	isc_region_t r1;
213 	isc_region_t r2;
214 
215 	REQUIRE(rdata1->type == rdata2->type);
216 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
217 	REQUIRE(rdata1->type == dns_rdatatype_zonemd);
218 	REQUIRE(rdata1->length != 0);
219 	REQUIRE(rdata2->length != 0);
220 
221 	dns_rdata_toregion(rdata1, &r1);
222 	dns_rdata_toregion(rdata2, &r2);
223 	return (isc_region_compare(&r1, &r2));
224 }
225 
226 static isc_result_t
fromstruct_zonemd(ARGS_FROMSTRUCT)227 fromstruct_zonemd(ARGS_FROMSTRUCT) {
228 	dns_rdata_zonemd_t *zonemd = source;
229 
230 	REQUIRE(zonemd != NULL);
231 	REQUIRE(zonemd->common.rdtype == type);
232 	REQUIRE(zonemd->common.rdclass == rdclass);
233 
234 	UNUSED(type);
235 	UNUSED(rdclass);
236 
237 	switch (zonemd->digest_type) {
238 	case DNS_ZONEMD_DIGEST_SHA384:
239 		REQUIRE(zonemd->length == ISC_SHA384_DIGESTLENGTH);
240 		break;
241 	case DNS_ZONEMD_DIGEST_SHA512:
242 		REQUIRE(zonemd->length == ISC_SHA512_DIGESTLENGTH);
243 		break;
244 	}
245 
246 	RETERR(uint32_tobuffer(zonemd->serial, target));
247 	RETERR(uint8_tobuffer(zonemd->scheme, target));
248 	RETERR(uint8_tobuffer(zonemd->digest_type, target));
249 
250 	return (mem_tobuffer(target, zonemd->digest, zonemd->length));
251 }
252 
253 static isc_result_t
tostruct_zonemd(ARGS_TOSTRUCT)254 tostruct_zonemd(ARGS_TOSTRUCT) {
255 	dns_rdata_zonemd_t *zonemd = target;
256 	isc_region_t region;
257 
258 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
259 	REQUIRE(zonemd != NULL);
260 	REQUIRE(rdata->length != 0);
261 
262 	zonemd->common.rdclass = rdata->rdclass;
263 	zonemd->common.rdtype = rdata->type;
264 	ISC_LINK_INIT(&zonemd->common, link);
265 
266 	dns_rdata_toregion(rdata, &region);
267 
268 	zonemd->serial = uint32_fromregion(&region);
269 	isc_region_consume(&region, 4);
270 	zonemd->scheme = uint8_fromregion(&region);
271 	isc_region_consume(&region, 1);
272 	zonemd->digest_type = uint8_fromregion(&region);
273 	isc_region_consume(&region, 1);
274 	zonemd->length = region.length;
275 
276 	zonemd->digest = mem_maybedup(mctx, region.base, region.length);
277 	if (zonemd->digest == NULL) {
278 		return (ISC_R_NOMEMORY);
279 	}
280 
281 	zonemd->mctx = mctx;
282 	return (ISC_R_SUCCESS);
283 }
284 
285 static void
freestruct_zonemd(ARGS_FREESTRUCT)286 freestruct_zonemd(ARGS_FREESTRUCT) {
287 	dns_rdata_zonemd_t *zonemd = source;
288 
289 	REQUIRE(zonemd != NULL);
290 	REQUIRE(zonemd->common.rdtype == dns_rdatatype_zonemd);
291 
292 	if (zonemd->mctx == NULL) {
293 		return;
294 	}
295 
296 	if (zonemd->digest != NULL) {
297 		isc_mem_free(zonemd->mctx, zonemd->digest);
298 	}
299 	zonemd->mctx = NULL;
300 }
301 
302 static isc_result_t
additionaldata_zonemd(ARGS_ADDLDATA)303 additionaldata_zonemd(ARGS_ADDLDATA) {
304 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
305 
306 	UNUSED(rdata);
307 	UNUSED(add);
308 	UNUSED(arg);
309 
310 	return (ISC_R_SUCCESS);
311 }
312 
313 static isc_result_t
digest_zonemd(ARGS_DIGEST)314 digest_zonemd(ARGS_DIGEST) {
315 	isc_region_t r;
316 
317 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
318 
319 	dns_rdata_toregion(rdata, &r);
320 
321 	return ((digest)(arg, &r));
322 }
323 
324 static bool
checkowner_zonemd(ARGS_CHECKOWNER)325 checkowner_zonemd(ARGS_CHECKOWNER) {
326 	REQUIRE(type == dns_rdatatype_zonemd);
327 
328 	UNUSED(name);
329 	UNUSED(type);
330 	UNUSED(rdclass);
331 	UNUSED(wildcard);
332 
333 	return (true);
334 }
335 
336 static bool
checknames_zonemd(ARGS_CHECKNAMES)337 checknames_zonemd(ARGS_CHECKNAMES) {
338 	REQUIRE(rdata->type == dns_rdatatype_zonemd);
339 
340 	UNUSED(rdata);
341 	UNUSED(owner);
342 	UNUSED(bad);
343 
344 	return (true);
345 }
346 
347 static int
casecompare_zonemd(ARGS_COMPARE)348 casecompare_zonemd(ARGS_COMPARE) {
349 	return (compare_zonemd(rdata1, rdata2));
350 }
351 
352 #endif /* RDATA_GENERIC_ZONEMD_63_C */
353