ds_43.c revision 1.7
1/*	$NetBSD: ds_43.c,v 1.7 2020/05/24 19:46:24 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14/* RFC3658 */
15
16#ifndef RDATA_GENERIC_DS_43_C
17#define RDATA_GENERIC_DS_43_C
18
19#define RRTYPE_DS_ATTRIBUTES                                        \
20	(DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \
21	 DNS_RDATATYPEATTR_ATPARENT)
22
23#include <isc/md.h>
24
25#include <dns/ds.h>
26
27static inline isc_result_t
28generic_fromtext_ds(ARGS_FROMTEXT) {
29	isc_token_t token;
30	unsigned char c;
31	int length;
32
33	UNUSED(type);
34	UNUSED(rdclass);
35	UNUSED(origin);
36	UNUSED(options);
37	UNUSED(callbacks);
38
39	/*
40	 * Key tag.
41	 */
42	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
43				      false));
44	if (token.value.as_ulong > 0xffffU) {
45		RETTOK(ISC_R_RANGE);
46	}
47	RETERR(uint16_tobuffer(token.value.as_ulong, target));
48
49	/*
50	 * Algorithm.
51	 */
52	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
53				      false));
54	RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
55	RETERR(mem_tobuffer(target, &c, 1));
56
57	/*
58	 * Digest type.
59	 */
60	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
61				      false));
62	RETTOK(dns_dsdigest_fromtext(&c, &token.value.as_textregion));
63	RETERR(mem_tobuffer(target, &c, 1));
64
65	/*
66	 * Digest.
67	 */
68	switch (c) {
69	case DNS_DSDIGEST_SHA1:
70		length = ISC_SHA1_DIGESTLENGTH;
71		break;
72	case DNS_DSDIGEST_SHA256:
73		length = ISC_SHA256_DIGESTLENGTH;
74		break;
75	case DNS_DSDIGEST_SHA384:
76		length = ISC_SHA384_DIGESTLENGTH;
77		break;
78	default:
79		length = -2;
80		break;
81	}
82	return (isc_hex_tobuffer(lexer, target, length));
83}
84
85static inline isc_result_t
86fromtext_ds(ARGS_FROMTEXT) {
87	REQUIRE(type == dns_rdatatype_ds);
88
89	return (generic_fromtext_ds(rdclass, type, lexer, origin, options,
90				    target, callbacks));
91}
92
93static inline isc_result_t
94generic_totext_ds(ARGS_TOTEXT) {
95	isc_region_t sr;
96	char buf[sizeof("64000 ")];
97	unsigned int n;
98
99	REQUIRE(rdata->length != 0);
100
101	UNUSED(tctx);
102
103	dns_rdata_toregion(rdata, &sr);
104
105	/*
106	 * Key tag.
107	 */
108	n = uint16_fromregion(&sr);
109	isc_region_consume(&sr, 2);
110	snprintf(buf, sizeof(buf), "%u ", n);
111	RETERR(str_totext(buf, target));
112
113	/*
114	 * Algorithm.
115	 */
116	n = uint8_fromregion(&sr);
117	isc_region_consume(&sr, 1);
118	snprintf(buf, sizeof(buf), "%u ", n);
119	RETERR(str_totext(buf, target));
120
121	/*
122	 * Digest type.
123	 */
124	n = uint8_fromregion(&sr);
125	isc_region_consume(&sr, 1);
126	snprintf(buf, sizeof(buf), "%u", n);
127	RETERR(str_totext(buf, target));
128
129	/*
130	 * Digest.
131	 */
132	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
133		RETERR(str_totext(" (", target));
134	}
135	RETERR(str_totext(tctx->linebreak, target));
136	if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
137		if (tctx->width == 0) { /* No splitting */
138			RETERR(isc_hex_totext(&sr, 0, "", target));
139		} else {
140			RETERR(isc_hex_totext(&sr, tctx->width - 2,
141					      tctx->linebreak, target));
142		}
143	} else {
144		RETERR(str_totext("[omitted]", target));
145	}
146	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
147		RETERR(str_totext(" )", target));
148	}
149	return (ISC_R_SUCCESS);
150}
151
152static inline isc_result_t
153totext_ds(ARGS_TOTEXT) {
154	REQUIRE(rdata->type == dns_rdatatype_ds);
155
156	return (generic_totext_ds(rdata, tctx, target));
157}
158
159static inline isc_result_t
160generic_fromwire_ds(ARGS_FROMWIRE) {
161	isc_region_t sr;
162
163	UNUSED(type);
164	UNUSED(rdclass);
165	UNUSED(dctx);
166	UNUSED(options);
167
168	isc_buffer_activeregion(source, &sr);
169
170	/*
171	 * Check digest lengths if we know them.
172	 */
173	if (sr.length < 5 ||
174	    (sr.base[3] == DNS_DSDIGEST_SHA1 &&
175	     sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
176	    (sr.base[3] == DNS_DSDIGEST_SHA256 &&
177	     sr.length < 4 + ISC_SHA256_DIGESTLENGTH) ||
178	    (sr.base[3] == DNS_DSDIGEST_SHA384 &&
179	     sr.length < 4 + ISC_SHA384_DIGESTLENGTH))
180	{
181		return (ISC_R_UNEXPECTEDEND);
182	}
183
184	/*
185	 * Only copy digest lengths if we know them.
186	 * If there is extra data dns_rdata_fromwire() will
187	 * detect that.
188	 */
189	if (sr.base[3] == DNS_DSDIGEST_SHA1) {
190		sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
191	} else if (sr.base[3] == DNS_DSDIGEST_SHA256) {
192		sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
193	} else if (sr.base[3] == DNS_DSDIGEST_SHA384) {
194		sr.length = 4 + ISC_SHA384_DIGESTLENGTH;
195	}
196
197	isc_buffer_forward(source, sr.length);
198	return (mem_tobuffer(target, sr.base, sr.length));
199}
200
201static inline isc_result_t
202fromwire_ds(ARGS_FROMWIRE) {
203	REQUIRE(type == dns_rdatatype_ds);
204
205	return (generic_fromwire_ds(rdclass, type, source, dctx, options,
206				    target));
207}
208
209static inline isc_result_t
210towire_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
222static inline int
223compare_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
238static inline isc_result_t
239generic_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
268static inline isc_result_t
269fromstruct_ds(ARGS_FROMSTRUCT) {
270	REQUIRE(type == dns_rdatatype_ds);
271
272	return (generic_fromstruct_ds(rdclass, type, source, target));
273}
274
275static inline isc_result_t
276generic_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	if (ds->digest == NULL) {
298		return (ISC_R_NOMEMORY);
299	}
300
301	ds->mctx = mctx;
302	return (ISC_R_SUCCESS);
303}
304
305static inline isc_result_t
306tostruct_ds(ARGS_TOSTRUCT) {
307	dns_rdata_ds_t *ds = target;
308
309	REQUIRE(rdata->type == dns_rdatatype_ds);
310	REQUIRE(ds != NULL);
311
312	ds->common.rdclass = rdata->rdclass;
313	ds->common.rdtype = rdata->type;
314	ISC_LINK_INIT(&ds->common, link);
315
316	return (generic_tostruct_ds(rdata, target, mctx));
317}
318
319static inline void
320freestruct_ds(ARGS_FREESTRUCT) {
321	dns_rdata_ds_t *ds = source;
322
323	REQUIRE(ds != NULL);
324	REQUIRE(ds->common.rdtype == dns_rdatatype_ds);
325
326	if (ds->mctx == NULL) {
327		return;
328	}
329
330	if (ds->digest != NULL) {
331		isc_mem_free(ds->mctx, ds->digest);
332	}
333	ds->mctx = NULL;
334}
335
336static inline isc_result_t
337additionaldata_ds(ARGS_ADDLDATA) {
338	REQUIRE(rdata->type == dns_rdatatype_ds);
339
340	UNUSED(rdata);
341	UNUSED(add);
342	UNUSED(arg);
343
344	return (ISC_R_SUCCESS);
345}
346
347static inline isc_result_t
348digest_ds(ARGS_DIGEST) {
349	isc_region_t r;
350
351	REQUIRE(rdata->type == dns_rdatatype_ds);
352
353	dns_rdata_toregion(rdata, &r);
354
355	return ((digest)(arg, &r));
356}
357
358static inline bool
359checkowner_ds(ARGS_CHECKOWNER) {
360	REQUIRE(type == dns_rdatatype_ds);
361
362	UNUSED(name);
363	UNUSED(type);
364	UNUSED(rdclass);
365	UNUSED(wildcard);
366
367	return (true);
368}
369
370static inline bool
371checknames_ds(ARGS_CHECKNAMES) {
372	REQUIRE(rdata->type == dns_rdatatype_ds);
373
374	UNUSED(rdata);
375	UNUSED(owner);
376	UNUSED(bad);
377
378	return (true);
379}
380
381static inline int
382casecompare_ds(ARGS_COMPARE) {
383	return (compare_ds(rdata1, rdata2));
384}
385
386#endif /* RDATA_GENERIC_DS_43_C */
387