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