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