xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/ds_43.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: ds_43.c,v 1.12 2025/01/26 16:25: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 /* RFC3658 */
17 
18 #ifndef RDATA_GENERIC_DS_43_C
19 #define RDATA_GENERIC_DS_43_C
20 
21 #define RRTYPE_DS_ATTRIBUTES                                        \
22 	(DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \
23 	 DNS_RDATATYPEATTR_ATPARENT)
24 
25 #include <isc/md.h>
26 
27 #include <dns/ds.h>
28 
29 static isc_result_t
30 generic_fromtext_ds(ARGS_FROMTEXT) {
31 	isc_token_t token;
32 	unsigned char c;
33 	int length;
34 
35 	UNUSED(type);
36 	UNUSED(rdclass);
37 	UNUSED(origin);
38 	UNUSED(options);
39 	UNUSED(callbacks);
40 
41 	/*
42 	 * Key tag.
43 	 */
44 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
45 				      false));
46 	if (token.value.as_ulong > 0xffffU) {
47 		RETTOK(ISC_R_RANGE);
48 	}
49 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
50 
51 	/*
52 	 * Algorithm.
53 	 */
54 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
55 				      false));
56 	RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
57 	RETERR(mem_tobuffer(target, &c, 1));
58 
59 	/*
60 	 * Digest type.
61 	 */
62 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
63 				      false));
64 	RETTOK(dns_dsdigest_fromtext(&c, &token.value.as_textregion));
65 	RETERR(mem_tobuffer(target, &c, 1));
66 
67 	/*
68 	 * Digest.
69 	 */
70 	switch (c) {
71 	case DNS_DSDIGEST_SHA1:
72 		length = ISC_SHA1_DIGESTLENGTH;
73 		break;
74 	case DNS_DSDIGEST_SHA256:
75 		length = ISC_SHA256_DIGESTLENGTH;
76 		break;
77 	case DNS_DSDIGEST_SHA384:
78 		length = ISC_SHA384_DIGESTLENGTH;
79 		break;
80 	default:
81 		length = -2;
82 		break;
83 	}
84 	return isc_hex_tobuffer(lexer, target, length);
85 }
86 
87 static isc_result_t
88 fromtext_ds(ARGS_FROMTEXT) {
89 	REQUIRE(type == dns_rdatatype_ds);
90 
91 	return generic_fromtext_ds(CALL_FROMTEXT);
92 }
93 
94 static isc_result_t
95 generic_totext_ds(ARGS_TOTEXT) {
96 	isc_region_t sr;
97 	char buf[sizeof("64000 ")];
98 	unsigned int n;
99 
100 	REQUIRE(rdata->length != 0);
101 
102 	UNUSED(tctx);
103 
104 	dns_rdata_toregion(rdata, &sr);
105 
106 	/*
107 	 * Key tag.
108 	 */
109 	n = uint16_fromregion(&sr);
110 	isc_region_consume(&sr, 2);
111 	snprintf(buf, sizeof(buf), "%u ", n);
112 	RETERR(str_totext(buf, target));
113 
114 	/*
115 	 * Algorithm.
116 	 */
117 	n = uint8_fromregion(&sr);
118 	isc_region_consume(&sr, 1);
119 	snprintf(buf, sizeof(buf), "%u ", n);
120 	RETERR(str_totext(buf, target));
121 
122 	/*
123 	 * Digest type.
124 	 */
125 	n = uint8_fromregion(&sr);
126 	isc_region_consume(&sr, 1);
127 	snprintf(buf, sizeof(buf), "%u", n);
128 	RETERR(str_totext(buf, target));
129 
130 	/*
131 	 * Digest.
132 	 */
133 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
134 		RETERR(str_totext(" (", target));
135 	}
136 	RETERR(str_totext(tctx->linebreak, target));
137 	if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
138 		if (tctx->width == 0) { /* No splitting */
139 			RETERR(isc_hex_totext(&sr, 0, "", target));
140 		} else {
141 			RETERR(isc_hex_totext(&sr, tctx->width - 2,
142 					      tctx->linebreak, target));
143 		}
144 	} else {
145 		RETERR(str_totext("[omitted]", target));
146 	}
147 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
148 		RETERR(str_totext(" )", target));
149 	}
150 	return ISC_R_SUCCESS;
151 }
152 
153 static isc_result_t
154 totext_ds(ARGS_TOTEXT) {
155 	REQUIRE(rdata != NULL);
156 	REQUIRE(rdata->type == dns_rdatatype_ds);
157 
158 	return generic_totext_ds(CALL_TOTEXT);
159 }
160 
161 static isc_result_t
162 generic_fromwire_ds(ARGS_FROMWIRE) {
163 	isc_region_t sr;
164 
165 	UNUSED(type);
166 	UNUSED(rdclass);
167 	UNUSED(dctx);
168 
169 	isc_buffer_activeregion(source, &sr);
170 
171 	/*
172 	 * Check digest lengths if we know them.
173 	 */
174 	if (sr.length < 5 ||
175 	    (sr.base[3] == DNS_DSDIGEST_SHA1 &&
176 	     sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
177 	    (sr.base[3] == DNS_DSDIGEST_SHA256 &&
178 	     sr.length < 4 + ISC_SHA256_DIGESTLENGTH) ||
179 	    (sr.base[3] == DNS_DSDIGEST_SHA384 &&
180 	     sr.length < 4 + ISC_SHA384_DIGESTLENGTH))
181 	{
182 		return ISC_R_UNEXPECTEDEND;
183 	}
184 
185 	/*
186 	 * Only copy digest lengths if we know them.
187 	 * If there is extra data dns_rdata_fromwire() will
188 	 * detect that.
189 	 */
190 	if (sr.base[3] == DNS_DSDIGEST_SHA1) {
191 		sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
192 	} else if (sr.base[3] == DNS_DSDIGEST_SHA256) {
193 		sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
194 	} else if (sr.base[3] == DNS_DSDIGEST_SHA384) {
195 		sr.length = 4 + ISC_SHA384_DIGESTLENGTH;
196 	}
197 
198 	isc_buffer_forward(source, sr.length);
199 	return mem_tobuffer(target, sr.base, sr.length);
200 }
201 
202 static isc_result_t
203 fromwire_ds(ARGS_FROMWIRE) {
204 	REQUIRE(type == dns_rdatatype_ds);
205 
206 	return generic_fromwire_ds(CALL_FROMWIRE);
207 }
208 
209 static isc_result_t
210 towire_ds(ARGS_TOWIRE) {
211 	isc_region_t sr;
212 
213 	REQUIRE(rdata->type == dns_rdatatype_ds);
214 	REQUIRE(rdata->length != 0);
215 
216 	UNUSED(cctx);
217 
218 	dns_rdata_toregion(rdata, &sr);
219 	return mem_tobuffer(target, sr.base, sr.length);
220 }
221 
222 static int
223 compare_ds(ARGS_COMPARE) {
224 	isc_region_t r1;
225 	isc_region_t r2;
226 
227 	REQUIRE(rdata1->type == rdata2->type);
228 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
229 	REQUIRE(rdata1->type == dns_rdatatype_ds);
230 	REQUIRE(rdata1->length != 0);
231 	REQUIRE(rdata2->length != 0);
232 
233 	dns_rdata_toregion(rdata1, &r1);
234 	dns_rdata_toregion(rdata2, &r2);
235 	return isc_region_compare(&r1, &r2);
236 }
237 
238 static isc_result_t
239 generic_fromstruct_ds(ARGS_FROMSTRUCT) {
240 	dns_rdata_ds_t *ds = source;
241 
242 	REQUIRE(ds != NULL);
243 	REQUIRE(ds->common.rdtype == type);
244 	REQUIRE(ds->common.rdclass == rdclass);
245 
246 	UNUSED(type);
247 	UNUSED(rdclass);
248 
249 	switch (ds->digest_type) {
250 	case DNS_DSDIGEST_SHA1:
251 		REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH);
252 		break;
253 	case DNS_DSDIGEST_SHA256:
254 		REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH);
255 		break;
256 	case DNS_DSDIGEST_SHA384:
257 		REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH);
258 		break;
259 	}
260 
261 	RETERR(uint16_tobuffer(ds->key_tag, target));
262 	RETERR(uint8_tobuffer(ds->algorithm, target));
263 	RETERR(uint8_tobuffer(ds->digest_type, target));
264 
265 	return mem_tobuffer(target, ds->digest, ds->length);
266 }
267 
268 static isc_result_t
269 fromstruct_ds(ARGS_FROMSTRUCT) {
270 	REQUIRE(type == dns_rdatatype_ds);
271 
272 	return generic_fromstruct_ds(CALL_FROMSTRUCT);
273 }
274 
275 static isc_result_t
276 generic_tostruct_ds(ARGS_TOSTRUCT) {
277 	dns_rdata_ds_t *ds = target;
278 	isc_region_t region;
279 
280 	REQUIRE(ds != NULL);
281 	REQUIRE(rdata->length != 0);
282 	REQUIRE(ds->common.rdtype == rdata->type);
283 	REQUIRE(ds->common.rdclass == rdata->rdclass);
284 	REQUIRE(!ISC_LINK_LINKED(&ds->common, link));
285 
286 	dns_rdata_toregion(rdata, &region);
287 
288 	ds->key_tag = uint16_fromregion(&region);
289 	isc_region_consume(&region, 2);
290 	ds->algorithm = uint8_fromregion(&region);
291 	isc_region_consume(&region, 1);
292 	ds->digest_type = uint8_fromregion(&region);
293 	isc_region_consume(&region, 1);
294 	ds->length = region.length;
295 
296 	ds->digest = mem_maybedup(mctx, region.base, region.length);
297 	ds->mctx = mctx;
298 	return ISC_R_SUCCESS;
299 }
300 
301 static isc_result_t
302 tostruct_ds(ARGS_TOSTRUCT) {
303 	dns_rdata_ds_t *ds = target;
304 
305 	REQUIRE(rdata->type == dns_rdatatype_ds);
306 	REQUIRE(ds != NULL);
307 
308 	ds->common.rdclass = rdata->rdclass;
309 	ds->common.rdtype = rdata->type;
310 	ISC_LINK_INIT(&ds->common, link);
311 
312 	return generic_tostruct_ds(CALL_TOSTRUCT);
313 }
314 
315 static void
316 freestruct_ds(ARGS_FREESTRUCT) {
317 	dns_rdata_ds_t *ds = source;
318 
319 	REQUIRE(ds != NULL);
320 	REQUIRE(ds->common.rdtype == dns_rdatatype_ds);
321 
322 	if (ds->mctx == NULL) {
323 		return;
324 	}
325 
326 	if (ds->digest != NULL) {
327 		isc_mem_free(ds->mctx, ds->digest);
328 	}
329 	ds->mctx = NULL;
330 }
331 
332 static isc_result_t
333 additionaldata_ds(ARGS_ADDLDATA) {
334 	REQUIRE(rdata->type == dns_rdatatype_ds);
335 
336 	UNUSED(rdata);
337 	UNUSED(owner);
338 	UNUSED(add);
339 	UNUSED(arg);
340 
341 	return ISC_R_SUCCESS;
342 }
343 
344 static isc_result_t
345 digest_ds(ARGS_DIGEST) {
346 	isc_region_t r;
347 
348 	REQUIRE(rdata->type == dns_rdatatype_ds);
349 
350 	dns_rdata_toregion(rdata, &r);
351 
352 	return (digest)(arg, &r);
353 }
354 
355 static bool
356 checkowner_ds(ARGS_CHECKOWNER) {
357 	REQUIRE(type == dns_rdatatype_ds);
358 
359 	UNUSED(name);
360 	UNUSED(type);
361 	UNUSED(rdclass);
362 	UNUSED(wildcard);
363 
364 	return true;
365 }
366 
367 static bool
368 checknames_ds(ARGS_CHECKNAMES) {
369 	REQUIRE(rdata->type == dns_rdatatype_ds);
370 
371 	UNUSED(rdata);
372 	UNUSED(owner);
373 	UNUSED(bad);
374 
375 	return true;
376 }
377 
378 static int
379 casecompare_ds(ARGS_COMPARE) {
380 	return compare_ds(rdata1, rdata2);
381 }
382 
383 #endif /* RDATA_GENERIC_DS_43_C */
384