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