1 /*	$NetBSD: nsec3_50.c,v 1.8 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2008, 2009, 2011, 2012, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id */
20 
21 /*
22  * Copyright (C) 2004  Nominet, Ltd.
23  *
24  * Permission to use, copy, modify, and distribute this software for any
25  * purpose with or without fee is hereby granted, provided that the above
26  * copyright notice and this permission notice appear in all copies.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
29  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
30  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
31  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
32  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
33  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
34  * PERFORMANCE OF THIS SOFTWARE.
35  */
36 
37 /* RFC 5155 */
38 
39 #ifndef RDATA_GENERIC_NSEC3_50_C
40 #define RDATA_GENERIC_NSEC3_50_C
41 
42 #include <isc/iterated_hash.h>
43 #include <isc/base32.h>
44 
45 #define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC
46 
47 static inline isc_result_t
fromtext_nsec3(ARGS_FROMTEXT)48 fromtext_nsec3(ARGS_FROMTEXT) {
49 	isc_token_t token;
50 	unsigned char bm[8*1024]; /* 64k bits */
51 	dns_rdatatype_t covered;
52 	int octet;
53 	int window;
54 	unsigned int flags;
55 	unsigned char hashalg;
56 	isc_buffer_t b;
57 
58 	REQUIRE(type == 50);
59 
60 	UNUSED(type);
61 	UNUSED(rdclass);
62 	UNUSED(callbacks);
63 	UNUSED(origin);
64 	UNUSED(options);
65 
66 	/* Hash. */
67 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
68 				      ISC_FALSE));
69 	RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion));
70 	RETERR(uint8_tobuffer(hashalg, target));
71 
72 	/* Flags. */
73 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
74 				      ISC_FALSE));
75 	flags = token.value.as_ulong;
76 	if (flags > 255U)
77 		RETTOK(ISC_R_RANGE);
78 	RETERR(uint8_tobuffer(flags, target));
79 
80 	/* Iterations. */
81 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
82 				      ISC_FALSE));
83 	if (token.value.as_ulong > 0xffffU)
84 		RETTOK(ISC_R_RANGE);
85 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
86 
87 	/* salt */
88 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
89 				      ISC_FALSE));
90 	if (token.value.as_textregion.length > (255*2))
91 		RETTOK(DNS_R_TEXTTOOLONG);
92 	if (strcmp(DNS_AS_STR(token), "-") == 0) {
93 		RETERR(uint8_tobuffer(0, target));
94 	} else {
95 		RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target));
96 		RETERR(isc_hex_decodestring(DNS_AS_STR(token), target));
97 	}
98 
99 	/*
100 	 * Next hash a single base32hex word.
101 	 */
102 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
103 				      ISC_FALSE));
104 	isc_buffer_init(&b, bm, sizeof(bm));
105 	RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b));
106 	if (isc_buffer_usedlength(&b) > 0xffU)
107 		RETTOK(ISC_R_RANGE);
108 	RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target));
109 	RETERR(mem_tobuffer(target, &bm, isc_buffer_usedlength(&b)));
110 
111 	memset(bm, 0, sizeof(bm));
112 	do {
113 		RETERR(isc_lex_getmastertoken(lexer, &token,
114 					      isc_tokentype_string, ISC_TRUE));
115 		if (token.type != isc_tokentype_string)
116 			break;
117 		RETTOK(dns_rdatatype_fromtext(&covered,
118 					      &token.value.as_textregion));
119 		bm[covered/8] |= (0x80>>(covered%8));
120 	} while (1);
121 	isc_lex_ungettoken(lexer, &token);
122 	for (window = 0; window < 256 ; window++) {
123 		/*
124 		 * Find if we have a type in this window.
125 		 */
126 		for (octet = 31; octet >= 0; octet--)
127 			if (bm[window * 32 + octet] != 0)
128 				break;
129 		if (octet < 0)
130 			continue;
131 		RETERR(uint8_tobuffer(window, target));
132 		RETERR(uint8_tobuffer(octet + 1, target));
133 		RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
134 	}
135 	return (ISC_R_SUCCESS);
136 }
137 
138 static inline isc_result_t
totext_nsec3(ARGS_TOTEXT)139 totext_nsec3(ARGS_TOTEXT) {
140 	isc_region_t sr;
141 	unsigned int i, j, k;
142 	unsigned int window, len;
143 	unsigned char hash;
144 	unsigned char flags;
145 	char buf[sizeof("TYPE65535")];
146 	isc_uint32_t iterations;
147 	isc_boolean_t first;
148 
149 	REQUIRE(rdata->type == 50);
150 	REQUIRE(rdata->length != 0);
151 
152 	dns_rdata_toregion(rdata, &sr);
153 
154 	/* Hash */
155 	hash = uint8_fromregion(&sr);
156 	isc_region_consume(&sr, 1);
157 	sprintf(buf, "%u ", hash);
158 	RETERR(str_totext(buf, target));
159 
160 	/* Flags */
161 	flags = uint8_fromregion(&sr);
162 	isc_region_consume(&sr, 1);
163 	sprintf(buf, "%u ", flags);
164 	RETERR(str_totext(buf, target));
165 
166 	/* Iterations */
167 	iterations = uint16_fromregion(&sr);
168 	isc_region_consume(&sr, 2);
169 	sprintf(buf, "%u ", iterations);
170 	RETERR(str_totext(buf, target));
171 
172 	/* Salt */
173 	j = uint8_fromregion(&sr);
174 	isc_region_consume(&sr, 1);
175 	INSIST(j <= sr.length);
176 
177 	if (j != 0) {
178 		i = sr.length;
179 		sr.length = j;
180 		RETERR(isc_hex_totext(&sr, 1, "", target));
181 		sr.length = i - j;
182 	} else
183 		RETERR(str_totext("-", target));
184 
185 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
186 		RETERR(str_totext(" (", target));
187 	RETERR(str_totext(tctx->linebreak, target));
188 
189 	/* Next hash */
190 	j = uint8_fromregion(&sr);
191 	isc_region_consume(&sr, 1);
192 	INSIST(j <= sr.length);
193 
194 	i = sr.length;
195 	sr.length = j;
196 	RETERR(isc_base32hexnp_totext(&sr, 1, "", target));
197 	sr.length = i - j;
198 
199 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0)
200 		RETERR(str_totext(" ", target));
201 
202 	/* Types covered */
203 	first = ISC_TRUE;
204 	for (i = 0; i < sr.length; i += len) {
205 		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
206 			RETERR(str_totext(tctx->linebreak, target));
207 			first = ISC_TRUE;
208 		}
209 		INSIST(i + 2 <= sr.length);
210 		window = sr.base[i];
211 		len = sr.base[i + 1];
212 		INSIST(len > 0 && len <= 32);
213 		i += 2;
214 		INSIST(i + len <= sr.length);
215 		for (j = 0; j < len; j++) {
216 			dns_rdatatype_t t;
217 			if (sr.base[i + j] == 0)
218 				continue;
219 			for (k = 0; k < 8; k++) {
220 				if ((sr.base[i + j] & (0x80 >> k)) == 0)
221 					continue;
222 				t = window * 256 + j * 8 + k;
223 				if (!first)
224 					RETERR(str_totext(" ", target));
225 				first = ISC_FALSE;
226 				if (dns_rdatatype_isknown(t)) {
227 					RETERR(dns_rdatatype_totext(t, target));
228 				} else {
229 					sprintf(buf, "TYPE%u", t);
230 					RETERR(str_totext(buf, target));
231 				}
232 			}
233 		}
234 	}
235 
236 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
237 		RETERR(str_totext(" )", target));
238 
239 	return (ISC_R_SUCCESS);
240 }
241 
242 static inline isc_result_t
fromwire_nsec3(ARGS_FROMWIRE)243 fromwire_nsec3(ARGS_FROMWIRE) {
244 	isc_region_t sr, rr;
245 	unsigned int window, lastwindow = 0;
246 	unsigned int len;
247 	unsigned int saltlen, hashlen;
248 	isc_boolean_t first = ISC_TRUE;
249 	unsigned int i;
250 
251 	REQUIRE(type == 50);
252 
253 	UNUSED(type);
254 	UNUSED(rdclass);
255 	UNUSED(options);
256 	UNUSED(dctx);
257 
258 	isc_buffer_activeregion(source, &sr);
259 	rr = sr;
260 
261 	/* hash(1), flags(1), iteration(2), saltlen(1) */
262 	if (sr.length < 5U)
263 		RETERR(DNS_R_FORMERR);
264 	saltlen = sr.base[4];
265 	isc_region_consume(&sr, 5);
266 
267 	if (sr.length < saltlen)
268 		RETERR(DNS_R_FORMERR);
269 	isc_region_consume(&sr, saltlen);
270 
271 	if (sr.length < 1U)
272 		RETERR(DNS_R_FORMERR);
273 	hashlen = sr.base[0];
274 	isc_region_consume(&sr, 1);
275 
276 	if (sr.length < hashlen)
277 		RETERR(DNS_R_FORMERR);
278 	isc_region_consume(&sr, hashlen);
279 
280 	for (i = 0; i < sr.length; i += len) {
281 		/*
282 		 * Check for overflow.
283 		 */
284 		if (i + 2 > sr.length)
285 			RETERR(DNS_R_FORMERR);
286 		window = sr.base[i];
287 		len = sr.base[i + 1];
288 		i += 2;
289 		/*
290 		 * Check that bitmap windows are in the correct order.
291 		 */
292 		if (!first && window <= lastwindow)
293 			RETERR(DNS_R_FORMERR);
294 		/*
295 		 * Check for legal lengths.
296 		 */
297 		if (len < 1 || len > 32)
298 			RETERR(DNS_R_FORMERR);
299 		/*
300 		 * Check for overflow.
301 		 */
302 		if (i + len > sr.length)
303 			RETERR(DNS_R_FORMERR);
304 		/*
305 		 * The last octet of the bitmap must be non zero.
306 		 */
307 		if (sr.base[i + len - 1] == 0)
308 			RETERR(DNS_R_FORMERR);
309 		lastwindow = window;
310 		first = ISC_FALSE;
311 	}
312 	if (i != sr.length)
313 		return (DNS_R_EXTRADATA);
314 	RETERR(mem_tobuffer(target, rr.base, rr.length));
315 	isc_buffer_forward(source, rr.length);
316 	return (ISC_R_SUCCESS);
317 }
318 
319 static inline isc_result_t
towire_nsec3(ARGS_TOWIRE)320 towire_nsec3(ARGS_TOWIRE) {
321 	isc_region_t sr;
322 
323 	REQUIRE(rdata->type == 50);
324 	REQUIRE(rdata->length != 0);
325 
326 	UNUSED(cctx);
327 
328 	dns_rdata_toregion(rdata, &sr);
329 	return (mem_tobuffer(target, sr.base, sr.length));
330 }
331 
332 static inline int
compare_nsec3(ARGS_COMPARE)333 compare_nsec3(ARGS_COMPARE) {
334 	isc_region_t r1;
335 	isc_region_t r2;
336 
337 	REQUIRE(rdata1->type == rdata2->type);
338 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
339 	REQUIRE(rdata1->type == 50);
340 	REQUIRE(rdata1->length != 0);
341 	REQUIRE(rdata2->length != 0);
342 
343 	dns_rdata_toregion(rdata1, &r1);
344 	dns_rdata_toregion(rdata2, &r2);
345 	return (isc_region_compare(&r1, &r2));
346 }
347 
348 static inline isc_result_t
fromstruct_nsec3(ARGS_FROMSTRUCT)349 fromstruct_nsec3(ARGS_FROMSTRUCT) {
350 	dns_rdata_nsec3_t *nsec3 = source;
351 	unsigned int i, len, window, lastwindow = 0;
352 	isc_boolean_t first = ISC_TRUE;
353 
354 	REQUIRE(type == 50);
355 	REQUIRE(source != NULL);
356 	REQUIRE(nsec3->common.rdtype == type);
357 	REQUIRE(nsec3->common.rdclass == rdclass);
358 	REQUIRE(nsec3->typebits != NULL || nsec3->len == 0);
359 	REQUIRE(nsec3->hash == dns_hash_sha1);
360 
361 	UNUSED(type);
362 	UNUSED(rdclass);
363 
364 	RETERR(uint8_tobuffer(nsec3->hash, target));
365 	RETERR(uint8_tobuffer(nsec3->flags, target));
366 	RETERR(uint16_tobuffer(nsec3->iterations, target));
367 	RETERR(uint8_tobuffer(nsec3->salt_length, target));
368 	RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length));
369 	RETERR(uint8_tobuffer(nsec3->next_length, target));
370 	RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length));
371 
372 	/*
373 	 * Perform sanity check.
374 	 */
375 	for (i = 0; i < nsec3->len ; i += len) {
376 		INSIST(i + 2 <= nsec3->len);
377 		window = nsec3->typebits[i];
378 		len = nsec3->typebits[i+1];
379 		i += 2;
380 		INSIST(first || window > lastwindow);
381 		INSIST(len > 0 && len <= 32);
382 		INSIST(i + len <= nsec3->len);
383 		INSIST(nsec3->typebits[i + len - 1] != 0);
384 		lastwindow = window;
385 		first = ISC_FALSE;
386 	}
387 	return (mem_tobuffer(target, nsec3->typebits, nsec3->len));
388 }
389 
390 static inline isc_result_t
tostruct_nsec3(ARGS_TOSTRUCT)391 tostruct_nsec3(ARGS_TOSTRUCT) {
392 	isc_region_t region;
393 	dns_rdata_nsec3_t *nsec3 = target;
394 
395 	REQUIRE(rdata->type == 50);
396 	REQUIRE(target != NULL);
397 	REQUIRE(rdata->length != 0);
398 
399 	nsec3->common.rdclass = rdata->rdclass;
400 	nsec3->common.rdtype = rdata->type;
401 	ISC_LINK_INIT(&nsec3->common, link);
402 
403 	region.base = rdata->data;
404 	region.length = rdata->length;
405 	nsec3->hash = uint8_consume_fromregion(&region);
406 	nsec3->flags = uint8_consume_fromregion(&region);
407 	nsec3->iterations = uint16_consume_fromregion(&region);
408 
409 	nsec3->salt_length = uint8_consume_fromregion(&region);
410 	nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length);
411 	if (nsec3->salt == NULL)
412 		return (ISC_R_NOMEMORY);
413 	isc_region_consume(&region, nsec3->salt_length);
414 
415 	nsec3->next_length = uint8_consume_fromregion(&region);
416 	nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length);
417 	if (nsec3->next == NULL)
418 		goto cleanup;
419 	isc_region_consume(&region, nsec3->next_length);
420 
421 	nsec3->len = region.length;
422 	nsec3->typebits = mem_maybedup(mctx, region.base, region.length);
423 	if (nsec3->typebits == NULL)
424 		goto cleanup;
425 
426 	nsec3->mctx = mctx;
427 	return (ISC_R_SUCCESS);
428 
429   cleanup:
430 	if (nsec3->next != NULL)
431 		isc_mem_free(mctx, nsec3->next);
432 	isc_mem_free(mctx, nsec3->salt);
433 	return (ISC_R_NOMEMORY);
434 }
435 
436 static inline void
freestruct_nsec3(ARGS_FREESTRUCT)437 freestruct_nsec3(ARGS_FREESTRUCT) {
438 	dns_rdata_nsec3_t *nsec3 = source;
439 
440 	REQUIRE(source != NULL);
441 	REQUIRE(nsec3->common.rdtype == 50);
442 
443 	if (nsec3->mctx == NULL)
444 		return;
445 
446 	if (nsec3->salt != NULL)
447 		isc_mem_free(nsec3->mctx, nsec3->salt);
448 	if (nsec3->next != NULL)
449 		isc_mem_free(nsec3->mctx, nsec3->next);
450 	if (nsec3->typebits != NULL)
451 		isc_mem_free(nsec3->mctx, nsec3->typebits);
452 	nsec3->mctx = NULL;
453 }
454 
455 static inline isc_result_t
additionaldata_nsec3(ARGS_ADDLDATA)456 additionaldata_nsec3(ARGS_ADDLDATA) {
457 	REQUIRE(rdata->type == 50);
458 
459 	UNUSED(rdata);
460 	UNUSED(add);
461 	UNUSED(arg);
462 
463 	return (ISC_R_SUCCESS);
464 }
465 
466 static inline isc_result_t
digest_nsec3(ARGS_DIGEST)467 digest_nsec3(ARGS_DIGEST) {
468 	isc_region_t r;
469 
470 	REQUIRE(rdata->type == 50);
471 
472 	dns_rdata_toregion(rdata, &r);
473 	return ((digest)(arg, &r));
474 }
475 
476 static inline isc_boolean_t
checkowner_nsec3(ARGS_CHECKOWNER)477 checkowner_nsec3(ARGS_CHECKOWNER) {
478 	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
479 	isc_buffer_t buffer;
480 	dns_label_t label;
481 
482 	REQUIRE(type == 50);
483 
484 	UNUSED(type);
485 	UNUSED(rdclass);
486 	UNUSED(wildcard);
487 
488 	/*
489 	 * First label is a base32hex string without padding.
490 	 */
491 	dns_name_getlabel(name, 0, &label);
492 	isc_region_consume(&label, 1);
493 	isc_buffer_init(&buffer, owner, sizeof(owner));
494 	if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS)
495 		return (ISC_TRUE);
496 
497 	return (ISC_FALSE);
498 }
499 
500 static inline isc_boolean_t
checknames_nsec3(ARGS_CHECKNAMES)501 checknames_nsec3(ARGS_CHECKNAMES) {
502 
503 	REQUIRE(rdata->type == 50);
504 
505 	UNUSED(rdata);
506 	UNUSED(owner);
507 	UNUSED(bad);
508 
509 	return (ISC_TRUE);
510 }
511 
512 static inline int
casecompare_nsec3(ARGS_COMPARE)513 casecompare_nsec3(ARGS_COMPARE) {
514 	return (compare_nsec3(rdata1, rdata2));
515 }
516 
517 #endif	/* RDATA_GENERIC_NSEC3_50_C */
518