1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: nsec3_50.c,v 1.12 2020/02/26 18:49:02 florian Exp $ */
18 
19 /*
20  * Copyright (C) 2004  Nominet, Ltd.
21  *
22  * Permission to use, copy, modify, and distribute this software for any
23  * purpose with or without fee is hereby granted, provided that the above
24  * copyright notice and this permission notice appear in all copies.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
27  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
28  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
29  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
30  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
31  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
32  * PERFORMANCE OF THIS SOFTWARE.
33  */
34 
35 /* RFC 5155 */
36 
37 #ifndef RDATA_GENERIC_NSEC3_50_C
38 #define RDATA_GENERIC_NSEC3_50_C
39 
40 #include <isc/base32.h>
41 
42 static inline isc_result_t
43 totext_nsec3(ARGS_TOTEXT) {
44 	isc_region_t sr;
45 	unsigned int i, j;
46 	unsigned char hash;
47 	unsigned char flags;
48 	char buf[sizeof("TYPE65535")];
49 	uint32_t iterations;
50 
51 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
52 	REQUIRE(rdata->length != 0);
53 
54 	dns_rdata_toregion(rdata, &sr);
55 
56 	/* Hash */
57 	hash = uint8_fromregion(&sr);
58 	isc_region_consume(&sr, 1);
59 	snprintf(buf, sizeof(buf), "%u ", hash);
60 	RETERR(isc_str_tobuffer(buf, target));
61 
62 	/* Flags */
63 	flags = uint8_fromregion(&sr);
64 	isc_region_consume(&sr, 1);
65 	snprintf(buf, sizeof(buf), "%u ", flags);
66 	RETERR(isc_str_tobuffer(buf, target));
67 
68 	/* Iterations */
69 	iterations = uint16_fromregion(&sr);
70 	isc_region_consume(&sr, 2);
71 	snprintf(buf, sizeof(buf), "%u ", iterations);
72 	RETERR(isc_str_tobuffer(buf, target));
73 
74 	/* Salt */
75 	j = uint8_fromregion(&sr);
76 	isc_region_consume(&sr, 1);
77 	INSIST(j <= sr.length);
78 
79 	if (j != 0) {
80 		i = sr.length;
81 		sr.length = j;
82 		RETERR(isc_hex_totext(&sr, 1, "", target));
83 		sr.length = i - j;
84 	} else
85 		RETERR(isc_str_tobuffer("-", target));
86 
87 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
88 		RETERR(isc_str_tobuffer(" (", target));
89 	RETERR(isc_str_tobuffer(tctx->linebreak, target));
90 
91 	/* Next hash */
92 	j = uint8_fromregion(&sr);
93 	isc_region_consume(&sr, 1);
94 	INSIST(j <= sr.length);
95 
96 	i = sr.length;
97 	sr.length = j;
98 	RETERR(isc_base32hexnp_totext(&sr, 1, "", target));
99 	sr.length = i - j;
100 
101 	/*
102 	 * Don't leave a trailing space when there's no typemap present.
103 	 */
104 	if (((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0) && (sr.length > 0)) {
105 		RETERR(isc_str_tobuffer(" ", target));
106 	}
107 	RETERR(typemap_totext(&sr, tctx, target));
108 
109 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
110 		RETERR(isc_str_tobuffer(" )", target));
111 
112 	return (ISC_R_SUCCESS);
113 }
114 
115 static inline isc_result_t
116 fromwire_nsec3(ARGS_FROMWIRE) {
117 	isc_region_t sr, rr;
118 	unsigned int saltlen, hashlen;
119 
120 	REQUIRE(type == dns_rdatatype_nsec3);
121 
122 	UNUSED(type);
123 	UNUSED(rdclass);
124 	UNUSED(options);
125 	UNUSED(dctx);
126 
127 	isc_buffer_activeregion(source, &sr);
128 	rr = sr;
129 
130 	/* hash(1), flags(1), iteration(2), saltlen(1) */
131 	if (sr.length < 5U)
132 		return (DNS_R_FORMERR);
133 	saltlen = sr.base[4];
134 	isc_region_consume(&sr, 5);
135 
136 	if (sr.length < saltlen)
137 		return (DNS_R_FORMERR);
138 	isc_region_consume(&sr, saltlen);
139 
140 	if (sr.length < 1U)
141 		return (DNS_R_FORMERR);
142 	hashlen = sr.base[0];
143 	isc_region_consume(&sr, 1);
144 
145 	if (sr.length < hashlen)
146 		return (DNS_R_FORMERR);
147 	isc_region_consume(&sr, hashlen);
148 
149 	RETERR(typemap_test(&sr, ISC_TRUE));
150 
151 	RETERR(isc_mem_tobuffer(target, rr.base, rr.length));
152 	isc_buffer_forward(source, rr.length);
153 	return (ISC_R_SUCCESS);
154 }
155 
156 static inline isc_result_t
157 towire_nsec3(ARGS_TOWIRE) {
158 	isc_region_t sr;
159 
160 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
161 	REQUIRE(rdata->length != 0);
162 
163 	UNUSED(cctx);
164 
165 	dns_rdata_toregion(rdata, &sr);
166 	return (isc_mem_tobuffer(target, sr.base, sr.length));
167 }
168 
169 #define NSEC3_MAX_HASH_LENGTH 155
170 static inline isc_boolean_t
171 checkowner_nsec3(ARGS_CHECKOWNER) {
172 	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
173 	isc_buffer_t buffer;
174 	dns_label_t label;
175 
176 	REQUIRE(type == dns_rdatatype_nsec3);
177 
178 	UNUSED(type);
179 	UNUSED(rdclass);
180 	UNUSED(wildcard);
181 
182 	/*
183 	 * First label is a base32hex string without padding.
184 	 */
185 	dns_name_getlabel(name, 0, &label);
186 	isc_region_consume(&label, 1);
187 	isc_buffer_init(&buffer, owner, sizeof(owner));
188 	if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS)
189 		return (ISC_TRUE);
190 
191 	return (ISC_FALSE);
192 }
193 
194 #endif	/* RDATA_GENERIC_NSEC3_50_C */
195