xref: /minix/external/bsd/bind/dist/lib/dns/private.c (revision bb9622b5)
1 /*	$NetBSD: private.c,v 1.7 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2009, 2011, 2012, 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 #include "config.h"
22 
23 #include <isc/result.h>
24 #include <isc/string.h>
25 #include <isc/types.h>
26 #include <isc/base64.h>
27 
28 #include <dns/nsec3.h>
29 #include <dns/private.h>
30 
31 /*
32  * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM
33  * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist.
34  *
35  * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain
36  * if all the NSEC3PARAM records (and associated chains) are slated for
37  * destruction and we have not been told to NOT build the NSEC chain.
38  *
39  * If the NSEC set exist then check to see if there is a request to create
40  * a NSEC3 chain.
41  *
42  * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private
43  * type exists then we need to examine it to determine if NSEC3 chain has
44  * been requested to be built otherwise a NSEC chain needs to be built.
45  */
46 
47 #define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
48 #define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0)
49 #define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0)
50 #define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0)
51 
52 #define CHECK(x) do {					\
53 			 result = (x);			\
54 			 if (result != ISC_R_SUCCESS)	\
55 				goto failure;		\
56 		 } while (/*CONSTCOND*/0)
57 
58 /*
59  * Work out if 'param' should be ignored or not (i.e. it is in the process
60  * of being removed).
61  *
62  * Note: we 'belt-and-braces' here by also checking for a CREATE private
63  * record and keep the param record in this case.
64  */
65 
66 static isc_boolean_t
67 ignore(dns_rdata_t *param, dns_rdataset_t *privateset) {
68 	isc_result_t result;
69 
70 	for (result = dns_rdataset_first(privateset);
71 	     result == ISC_R_SUCCESS;
72 	     result = dns_rdataset_next(privateset)) {
73 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
74 		dns_rdata_t private = DNS_RDATA_INIT;
75 		dns_rdata_t rdata = DNS_RDATA_INIT;
76 
77 		dns_rdataset_current(privateset, &private);
78 		if (!dns_nsec3param_fromprivate(&private, &rdata,
79 						buf, sizeof(buf)))
80 			continue;
81 		/*
82 		 * We are going to create a new NSEC3 chain so it
83 		 * doesn't matter if we are removing this one.
84 		 */
85 		if (CREATE(rdata.data[1]))
86 			return (ISC_FALSE);
87 		if (rdata.data[0] != param->data[0] ||
88 		    rdata.data[2] != param->data[2] ||
89 		    rdata.data[3] != param->data[3] ||
90 		    rdata.data[4] != param->data[4] ||
91 		    memcmp(&rdata.data[5], &param->data[5], param->data[4]))
92 			continue;
93 		/*
94 		 * The removal of this NSEC3 chain does NOT cause a
95 		 * NSEC chain to be created so we don't need to tell
96 		 * the caller that it will be removed.
97 		 */
98 		if (NONSEC(rdata.data[1]))
99 			return (ISC_FALSE);
100 		return (ISC_TRUE);
101 	}
102 	return (ISC_FALSE);
103 }
104 
105 isc_result_t
106 dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
107 		   dns_rdatatype_t privatetype,
108 		   isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3)
109 {
110 	dns_dbnode_t *node;
111 	dns_rdataset_t nsecset, nsec3paramset, privateset;
112 	isc_boolean_t nsec3chain;
113 	isc_boolean_t signing;
114 	isc_result_t result;
115 	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
116 	unsigned int count;
117 
118 	node = NULL;
119 	dns_rdataset_init(&nsecset);
120 	dns_rdataset_init(&nsec3paramset);
121 	dns_rdataset_init(&privateset);
122 
123 	CHECK(dns_db_getoriginnode(db, &node));
124 
125 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
126 				     0, (isc_stdtime_t) 0, &nsecset, NULL);
127 
128 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
129 		goto failure;
130 
131 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
132 				     0, (isc_stdtime_t) 0, &nsec3paramset,
133 				     NULL);
134 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
135 		goto failure;
136 
137 	if (dns_rdataset_isassociated(&nsecset) &&
138 	    dns_rdataset_isassociated(&nsec3paramset)) {
139 		if (build_nsec != NULL)
140 			*build_nsec = ISC_TRUE;
141 		if (build_nsec3 != NULL)
142 			*build_nsec3 = ISC_TRUE;
143 		goto success;
144 	}
145 
146 	if (privatetype != (dns_rdatatype_t)0) {
147 		result = dns_db_findrdataset(db, node, ver, privatetype,
148 					     0, (isc_stdtime_t) 0,
149 					     &privateset, NULL);
150 		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
151 			goto failure;
152 	}
153 
154 	/*
155 	 * Look to see if we also need to be creating a NSEC3 chain.
156 	 */
157 	if (dns_rdataset_isassociated(&nsecset)) {
158 		if (build_nsec != NULL)
159 			*build_nsec = ISC_TRUE;
160 		if (build_nsec3 != NULL)
161 			*build_nsec3 = ISC_FALSE;
162 		if (!dns_rdataset_isassociated(&privateset))
163 			goto success;
164 		for (result = dns_rdataset_first(&privateset);
165 		     result == ISC_R_SUCCESS;
166 		     result = dns_rdataset_next(&privateset)) {
167 			dns_rdata_t private = DNS_RDATA_INIT;
168 			dns_rdata_t rdata = DNS_RDATA_INIT;
169 
170 			dns_rdataset_current(&privateset, &private);
171 			if (!dns_nsec3param_fromprivate(&private, &rdata,
172 							buf, sizeof(buf)))
173 				continue;
174 			if (REMOVE(rdata.data[1]))
175 				continue;
176 			if (build_nsec3 != NULL)
177 				*build_nsec3 = ISC_TRUE;
178 			break;
179 		}
180 		goto success;
181 	}
182 
183 	if (dns_rdataset_isassociated(&nsec3paramset)) {
184 		if (build_nsec3 != NULL)
185 			*build_nsec3 = ISC_TRUE;
186 		if (build_nsec != NULL)
187 			*build_nsec = ISC_FALSE;
188 		if (!dns_rdataset_isassociated(&privateset))
189 			goto success;
190 		/*
191 		 * If we are in the process of building a new NSEC3 chain
192 		 * then we don't need to build a NSEC chain.
193 		 */
194 		for (result = dns_rdataset_first(&privateset);
195 		     result == ISC_R_SUCCESS;
196 		     result = dns_rdataset_next(&privateset)) {
197 			dns_rdata_t private = DNS_RDATA_INIT;
198 			dns_rdata_t rdata = DNS_RDATA_INIT;
199 
200 			dns_rdataset_current(&privateset, &private);
201 			if (!dns_nsec3param_fromprivate(&private, &rdata,
202 							buf, sizeof(buf)))
203 				continue;
204 			if (CREATE(rdata.data[1]))
205 				goto success;
206 		}
207 
208 		/*
209 		 * Check to see if there will be a active NSEC3CHAIN once
210 		 * the changes queued complete.
211 		 */
212 		count = 0;
213 		for (result = dns_rdataset_first(&nsec3paramset);
214 		     result == ISC_R_SUCCESS;
215 		     result = dns_rdataset_next(&nsec3paramset)) {
216 			dns_rdata_t rdata = DNS_RDATA_INIT;
217 
218 			/*
219 			 * If there is more that one NSEC3 chain present then
220 			 * we don't need to construct a NSEC chain.
221 			 */
222 			if (++count > 1)
223 				goto success;
224 			dns_rdataset_current(&nsec3paramset, &rdata);
225 			if (ignore(&rdata, &privateset))
226 				continue;
227 			/*
228 			 * We still have a good NSEC3 chain or we are
229 			 * not creating a NSEC chain as NONSEC is set.
230 			 */
231 			goto success;
232 		}
233 
234 		/*
235 		 * The last NSEC3 chain is being removed and does not have
236 		 * have NONSEC set.
237 		 */
238 		if (build_nsec != NULL)
239 			*build_nsec = ISC_TRUE;
240 		goto success;
241 	}
242 
243 	if (build_nsec != NULL)
244 		*build_nsec = ISC_FALSE;
245 	if (build_nsec3 != NULL)
246 		*build_nsec3 = ISC_FALSE;
247 	if (!dns_rdataset_isassociated(&privateset))
248 		goto success;
249 
250 	signing = ISC_FALSE;
251 	nsec3chain = ISC_FALSE;
252 
253 	for (result = dns_rdataset_first(&privateset);
254 	     result == ISC_R_SUCCESS;
255 	     result = dns_rdataset_next(&privateset)) {
256 		dns_rdata_t rdata = DNS_RDATA_INIT;
257 		dns_rdata_t private = DNS_RDATA_INIT;
258 
259 		dns_rdataset_current(&privateset, &private);
260 		if (!dns_nsec3param_fromprivate(&private, &rdata,
261 						buf, sizeof(buf))) {
262 			/*
263 			 * Look for record that says we are signing the
264 			 * zone with a key.
265 			 */
266 			if (private.length == 5 && private.data[0] != 0 &&
267 			    private.data[3] == 0 && private.data[4] == 0)
268 				signing = ISC_TRUE;
269 		} else {
270 			if (CREATE(rdata.data[1]))
271 				nsec3chain = ISC_TRUE;
272 		}
273 	}
274 
275 	if (signing) {
276 		if (nsec3chain) {
277 			if (build_nsec3 != NULL)
278 				*build_nsec3 = ISC_TRUE;
279 		} else {
280 			if (build_nsec != NULL)
281 				*build_nsec = ISC_TRUE;
282 		}
283 	}
284 
285  success:
286 	result = ISC_R_SUCCESS;
287  failure:
288 	if (dns_rdataset_isassociated(&nsecset))
289 		dns_rdataset_disassociate(&nsecset);
290 	if (dns_rdataset_isassociated(&nsec3paramset))
291 		dns_rdataset_disassociate(&nsec3paramset);
292 	if (dns_rdataset_isassociated(&privateset))
293 		dns_rdataset_disassociate(&privateset);
294 	if (node != NULL)
295 		dns_db_detachnode(db, &node);
296 	return (result);
297 }
298 
299 isc_result_t
300 dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
301 	isc_result_t result;
302 
303 	if (private->length < 5)
304 		return (ISC_R_NOTFOUND);
305 
306 	if (private->data[0] == 0) {
307 		unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE];
308 		unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE];
309 		dns_rdata_t rdata = DNS_RDATA_INIT;
310 		dns_rdata_nsec3param_t nsec3param;
311 		isc_boolean_t remove, init, nonsec;
312 		isc_buffer_t b;
313 
314 		if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf,
315 						sizeof(nsec3buf)))
316 			CHECK(ISC_R_FAILURE);
317 
318 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
319 
320 		remove = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0);
321 		init = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0);
322 		nonsec = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0);
323 
324 		nsec3param.flags &= ~(DNS_NSEC3FLAG_CREATE|
325 				      DNS_NSEC3FLAG_REMOVE|
326 				      DNS_NSEC3FLAG_INITIAL|
327 				      DNS_NSEC3FLAG_NONSEC);
328 
329 		if (init)
330 			isc_buffer_putstr(buf, "Pending NSEC3 chain ");
331 		else if (remove)
332 			isc_buffer_putstr(buf, "Removing NSEC3 chain ");
333 		else
334 			isc_buffer_putstr(buf, "Creating NSEC3 chain ");
335 
336 		dns_rdata_reset(&rdata);
337 		isc_buffer_init(&b, newbuf, sizeof(newbuf));
338 		CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
339 					   dns_rdatatype_nsec3param,
340 					   &nsec3param, &b));
341 
342 		CHECK(dns_rdata_totext(&rdata, NULL, buf));
343 
344 		if (remove && !nonsec)
345 			isc_buffer_putstr(buf, " / creating NSEC chain");
346 	} else if (private->length == 5) {
347 		unsigned char alg = private->data[0];
348 		dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
349 		char keybuf[BUFSIZ], algbuf[DNS_SECALG_FORMATSIZE];
350 		isc_boolean_t remove = ISC_TF(private->data[3] != 0);
351 		isc_boolean_t complete = ISC_TF(private->data[4] != 0);
352 
353 		if (remove && complete)
354 			isc_buffer_putstr(buf, "Done removing signatures for ");
355 		else if (remove)
356 			isc_buffer_putstr(buf, "Removing signatures for ");
357 		else if (complete)
358 			isc_buffer_putstr(buf, "Done signing with ");
359 		else
360 			isc_buffer_putstr(buf, "Signing with ");
361 
362 		dns_secalg_format(alg, algbuf, sizeof(algbuf));
363 		sprintf(keybuf, "key %d/%s", keyid, algbuf);
364 		isc_buffer_putstr(buf, keybuf);
365 	} else
366 		return (ISC_R_NOTFOUND);
367 
368 	isc_buffer_putuint8(buf, 0);
369 	result = ISC_R_SUCCESS;
370  failure:
371 	return (result);
372 }
373