1 /*	$NetBSD: ds_43.c,v 1.7 2014/12/10 04:37:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007, 2009-2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 2002  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id */
21 
22 /* RFC3658 */
23 
24 #ifndef RDATA_GENERIC_DS_43_C
25 #define RDATA_GENERIC_DS_43_C
26 
27 #define RRTYPE_DS_ATTRIBUTES \
28 	(DNS_RDATATYPEATTR_DNSSEC|DNS_RDATATYPEATTR_ATPARENT)
29 
30 #include <isc/sha1.h>
31 #include <isc/sha2.h>
32 
33 #include <dns/ds.h>
34 
35 #include "dst_gost.h"
36 
37 static inline isc_result_t
fromtext_ds(ARGS_FROMTEXT)38 fromtext_ds(ARGS_FROMTEXT) {
39 	isc_token_t token;
40 	unsigned char c;
41 	int length;
42 
43 	REQUIRE(type == 43);
44 
45 	UNUSED(type);
46 	UNUSED(rdclass);
47 	UNUSED(origin);
48 	UNUSED(options);
49 	UNUSED(callbacks);
50 
51 	/*
52 	 * Key tag.
53 	 */
54 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
55 				      ISC_FALSE));
56 	if (token.value.as_ulong > 0xffffU)
57 		RETTOK(ISC_R_RANGE);
58 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
59 
60 	/*
61 	 * Algorithm.
62 	 */
63 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
64 				      ISC_FALSE));
65 	RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
66 	RETERR(mem_tobuffer(target, &c, 1));
67 
68 	/*
69 	 * Digest type.
70 	 */
71 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
72 				      ISC_FALSE));
73 	RETTOK(dns_dsdigest_fromtext(&c, &token.value.as_textregion));
74 	RETERR(mem_tobuffer(target, &c, 1));
75 
76 	/*
77 	 * Digest.
78 	 */
79 	switch (c) {
80 	case DNS_DSDIGEST_SHA1:
81 		length = ISC_SHA1_DIGESTLENGTH;
82 		break;
83 	case DNS_DSDIGEST_SHA256:
84 		length = ISC_SHA256_DIGESTLENGTH;
85 		break;
86 #ifdef ISC_GOST_DIGESTLENGTH
87 	case DNS_DSDIGEST_GOST:
88 		length = ISC_GOST_DIGESTLENGTH;
89 		break;
90 #endif
91 	case DNS_DSDIGEST_SHA384:
92 		length = ISC_SHA384_DIGESTLENGTH;
93 		break;
94 	default:
95 		length = -1;
96 		break;
97 	}
98 	return (isc_hex_tobuffer(lexer, target, length));
99 }
100 
101 static inline isc_result_t
totext_ds(ARGS_TOTEXT)102 totext_ds(ARGS_TOTEXT) {
103 	isc_region_t sr;
104 	char buf[sizeof("64000 ")];
105 	unsigned int n;
106 
107 	REQUIRE(rdata->type == 43);
108 	REQUIRE(rdata->length != 0);
109 
110 	UNUSED(tctx);
111 
112 	dns_rdata_toregion(rdata, &sr);
113 
114 	/*
115 	 * Key tag.
116 	 */
117 	n = uint16_fromregion(&sr);
118 	isc_region_consume(&sr, 2);
119 	sprintf(buf, "%u ", n);
120 	RETERR(str_totext(buf, target));
121 
122 	/*
123 	 * Algorithm.
124 	 */
125 	n = uint8_fromregion(&sr);
126 	isc_region_consume(&sr, 1);
127 	sprintf(buf, "%u ", n);
128 	RETERR(str_totext(buf, target));
129 
130 	/*
131 	 * Digest type.
132 	 */
133 	n = uint8_fromregion(&sr);
134 	isc_region_consume(&sr, 1);
135 	sprintf(buf, "%u", n);
136 	RETERR(str_totext(buf, target));
137 
138 	/*
139 	 * Digest.
140 	 */
141 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
142 		RETERR(str_totext(" (", target));
143 	RETERR(str_totext(tctx->linebreak, target));
144 	if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
145 		if (tctx->width == 0) /* No splitting */
146 			RETERR(isc_hex_totext(&sr, 0, "", target));
147 		else
148 			RETERR(isc_hex_totext(&sr, tctx->width - 2,
149 					      tctx->linebreak, target));
150 	} else
151 		RETERR(str_totext("[omitted]", target));
152 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
153 		RETERR(str_totext(" )", target));
154 	return (ISC_R_SUCCESS);
155 }
156 
157 static inline isc_result_t
fromwire_ds(ARGS_FROMWIRE)158 fromwire_ds(ARGS_FROMWIRE) {
159 	isc_region_t sr;
160 
161 	REQUIRE(type == 43);
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 < 4 ||
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 #ifdef ISC_GOST_DIGESTLENGTH
179 	    (sr.base[3] == DNS_DSDIGEST_GOST &&
180 	     sr.length < 4 + ISC_GOST_DIGESTLENGTH) ||
181 #endif
182 	    (sr.base[3] == DNS_DSDIGEST_SHA384 &&
183 	     sr.length < 4 + ISC_SHA384_DIGESTLENGTH))
184 		return (ISC_R_UNEXPECTEDEND);
185 
186 	/*
187 	 * Only copy digest lengths if we know them.
188 	 * If there is extra data dns_rdata_fromwire() will
189 	 * detect that.
190 	 */
191 	if (sr.base[3] == DNS_DSDIGEST_SHA1)
192 		sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
193 	else if (sr.base[3] == DNS_DSDIGEST_SHA256)
194 		sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
195 #ifdef ISC_GOST_DIGESTLENGTH
196 	else if (sr.base[3] == DNS_DSDIGEST_GOST)
197 		sr.length = 4 + ISC_GOST_DIGESTLENGTH;
198 #endif
199 	else if (sr.base[3] == DNS_DSDIGEST_SHA384)
200 		sr.length = 4 + ISC_SHA384_DIGESTLENGTH;
201 
202 	isc_buffer_forward(source, sr.length);
203 	return (mem_tobuffer(target, sr.base, sr.length));
204 }
205 
206 static inline isc_result_t
towire_ds(ARGS_TOWIRE)207 towire_ds(ARGS_TOWIRE) {
208 	isc_region_t sr;
209 
210 	REQUIRE(rdata->type == 43);
211 	REQUIRE(rdata->length != 0);
212 
213 	UNUSED(cctx);
214 
215 	dns_rdata_toregion(rdata, &sr);
216 	return (mem_tobuffer(target, sr.base, sr.length));
217 }
218 
219 static inline int
compare_ds(ARGS_COMPARE)220 compare_ds(ARGS_COMPARE) {
221 	isc_region_t r1;
222 	isc_region_t r2;
223 
224 	REQUIRE(rdata1->type == rdata2->type);
225 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
226 	REQUIRE(rdata1->type == 43);
227 	REQUIRE(rdata1->length != 0);
228 	REQUIRE(rdata2->length != 0);
229 
230 	dns_rdata_toregion(rdata1, &r1);
231 	dns_rdata_toregion(rdata2, &r2);
232 	return (isc_region_compare(&r1, &r2));
233 }
234 
235 static inline isc_result_t
fromstruct_ds(ARGS_FROMSTRUCT)236 fromstruct_ds(ARGS_FROMSTRUCT) {
237 	dns_rdata_ds_t *ds = source;
238 
239 	REQUIRE(type == 43);
240 	REQUIRE(source != NULL);
241 	REQUIRE(ds->common.rdtype == type);
242 	REQUIRE(ds->common.rdclass == rdclass);
243 	switch (ds->digest_type) {
244 	case DNS_DSDIGEST_SHA1:
245 		REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH);
246 		break;
247 	case DNS_DSDIGEST_SHA256:
248 		REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH);
249 		break;
250 #ifdef ISC_GOST_DIGESTLENGTH
251 	case DNS_DSDIGEST_GOST:
252 		REQUIRE(ds->length == ISC_GOST_DIGESTLENGTH);
253 		break;
254 #endif
255 	case DNS_DSDIGEST_SHA384:
256 		REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH);
257 		break;
258 	}
259 
260 	UNUSED(type);
261 	UNUSED(rdclass);
262 
263 	RETERR(uint16_tobuffer(ds->key_tag, target));
264 	RETERR(uint8_tobuffer(ds->algorithm, target));
265 	RETERR(uint8_tobuffer(ds->digest_type, target));
266 
267 	return (mem_tobuffer(target, ds->digest, ds->length));
268 }
269 
270 static inline isc_result_t
tostruct_ds(ARGS_TOSTRUCT)271 tostruct_ds(ARGS_TOSTRUCT) {
272 	dns_rdata_ds_t *ds = target;
273 	isc_region_t region;
274 
275 	REQUIRE(rdata->type == 43);
276 	REQUIRE(target != NULL);
277 	REQUIRE(rdata->length != 0);
278 
279 	ds->common.rdclass = rdata->rdclass;
280 	ds->common.rdtype = rdata->type;
281 	ISC_LINK_INIT(&ds->common, link);
282 
283 	dns_rdata_toregion(rdata, &region);
284 
285 	ds->key_tag = uint16_fromregion(&region);
286 	isc_region_consume(&region, 2);
287 	ds->algorithm = uint8_fromregion(&region);
288 	isc_region_consume(&region, 1);
289 	ds->digest_type = uint8_fromregion(&region);
290 	isc_region_consume(&region, 1);
291 	ds->length = region.length;
292 
293 	ds->digest = mem_maybedup(mctx, region.base, region.length);
294 	if (ds->digest == NULL)
295 		return (ISC_R_NOMEMORY);
296 
297 	ds->mctx = mctx;
298 	return (ISC_R_SUCCESS);
299 }
300 
301 static inline void
freestruct_ds(ARGS_FREESTRUCT)302 freestruct_ds(ARGS_FREESTRUCT) {
303 	dns_rdata_ds_t *ds = source;
304 
305 	REQUIRE(ds != NULL);
306 	REQUIRE(ds->common.rdtype == 43);
307 
308 	if (ds->mctx == NULL)
309 		return;
310 
311 	if (ds->digest != NULL)
312 		isc_mem_free(ds->mctx, ds->digest);
313 	ds->mctx = NULL;
314 }
315 
316 static inline isc_result_t
additionaldata_ds(ARGS_ADDLDATA)317 additionaldata_ds(ARGS_ADDLDATA) {
318 	REQUIRE(rdata->type == 43);
319 
320 	UNUSED(rdata);
321 	UNUSED(add);
322 	UNUSED(arg);
323 
324 	return (ISC_R_SUCCESS);
325 }
326 
327 static inline isc_result_t
digest_ds(ARGS_DIGEST)328 digest_ds(ARGS_DIGEST) {
329 	isc_region_t r;
330 
331 	REQUIRE(rdata->type == 43);
332 
333 	dns_rdata_toregion(rdata, &r);
334 
335 	return ((digest)(arg, &r));
336 }
337 
338 static inline isc_boolean_t
checkowner_ds(ARGS_CHECKOWNER)339 checkowner_ds(ARGS_CHECKOWNER) {
340 
341 	REQUIRE(type == 43);
342 
343 	UNUSED(name);
344 	UNUSED(type);
345 	UNUSED(rdclass);
346 	UNUSED(wildcard);
347 
348 	return (ISC_TRUE);
349 }
350 
351 static inline isc_boolean_t
checknames_ds(ARGS_CHECKNAMES)352 checknames_ds(ARGS_CHECKNAMES) {
353 
354 	REQUIRE(rdata->type == 43);
355 
356 	UNUSED(rdata);
357 	UNUSED(owner);
358 	UNUSED(bad);
359 
360 	return (ISC_TRUE);
361 }
362 
363 static inline int
casecompare_ds(ARGS_COMPARE)364 casecompare_ds(ARGS_COMPARE) {
365 	return (compare_ds(rdata1, rdata2));
366 }
367 
368 #endif	/* RDATA_GENERIC_DS_43_C */
369