xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/private.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: private.c,v 1.1 2024/02/18 20:57:33 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
ignore(dns_rdata_t * param,dns_rdataset_t * privateset)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 		{
79 			continue;
80 		}
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 (false);
87 		}
88 		if (rdata.data[0] != param->data[0] ||
89 		    rdata.data[2] != param->data[2] ||
90 		    rdata.data[3] != param->data[3] ||
91 		    rdata.data[4] != param->data[4] ||
92 		    memcmp(&rdata.data[5], &param->data[5], param->data[4]))
93 		{
94 			continue;
95 		}
96 		/*
97 		 * The removal of this NSEC3 chain does NOT cause a
98 		 * NSEC chain to be created so we don't need to tell
99 		 * the caller that it will be removed.
100 		 */
101 		if (NONSEC(rdata.data[1])) {
102 			return (false);
103 		}
104 		return (true);
105 	}
106 	return (false);
107 }
108 
109 isc_result_t
dns_private_chains(dns_db_t * db,dns_dbversion_t * ver,dns_rdatatype_t privatetype,bool * build_nsec,bool * build_nsec3)110 dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
111 		   dns_rdatatype_t privatetype, bool *build_nsec,
112 		   bool *build_nsec3) {
113 	dns_dbnode_t *node;
114 	dns_rdataset_t nsecset, nsec3paramset, privateset;
115 	bool nsec3chain;
116 	bool signing;
117 	isc_result_t result;
118 	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
119 	unsigned int count;
120 
121 	node = NULL;
122 	dns_rdataset_init(&nsecset);
123 	dns_rdataset_init(&nsec3paramset);
124 	dns_rdataset_init(&privateset);
125 
126 	CHECK(dns_db_getoriginnode(db, &node));
127 
128 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 0,
129 				     (isc_stdtime_t)0, &nsecset, NULL);
130 
131 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
132 		goto failure;
133 	}
134 
135 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0,
136 				     (isc_stdtime_t)0, &nsec3paramset, NULL);
137 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
138 		goto failure;
139 	}
140 
141 	if (dns_rdataset_isassociated(&nsecset) &&
142 	    dns_rdataset_isassociated(&nsec3paramset))
143 	{
144 		if (build_nsec != NULL) {
145 			*build_nsec = true;
146 		}
147 		if (build_nsec3 != NULL) {
148 			*build_nsec3 = true;
149 		}
150 		goto success;
151 	}
152 
153 	if (privatetype != (dns_rdatatype_t)0) {
154 		result = dns_db_findrdataset(db, node, ver, privatetype, 0,
155 					     (isc_stdtime_t)0, &privateset,
156 					     NULL);
157 		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
158 			goto failure;
159 		}
160 	}
161 
162 	/*
163 	 * Look to see if we also need to be creating a NSEC3 chain.
164 	 */
165 	if (dns_rdataset_isassociated(&nsecset)) {
166 		if (build_nsec != NULL) {
167 			*build_nsec = true;
168 		}
169 		if (build_nsec3 != NULL) {
170 			*build_nsec3 = false;
171 		}
172 		if (!dns_rdataset_isassociated(&privateset)) {
173 			goto success;
174 		}
175 		for (result = dns_rdataset_first(&privateset);
176 		     result == ISC_R_SUCCESS;
177 		     result = dns_rdataset_next(&privateset))
178 		{
179 			dns_rdata_t private = DNS_RDATA_INIT;
180 			dns_rdata_t rdata = DNS_RDATA_INIT;
181 
182 			dns_rdataset_current(&privateset, &private);
183 			if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
184 							sizeof(buf)))
185 			{
186 				continue;
187 			}
188 			if (REMOVE(rdata.data[1])) {
189 				continue;
190 			}
191 			if (build_nsec3 != NULL) {
192 				*build_nsec3 = true;
193 			}
194 			break;
195 		}
196 		goto success;
197 	}
198 
199 	if (dns_rdataset_isassociated(&nsec3paramset)) {
200 		if (build_nsec3 != NULL) {
201 			*build_nsec3 = true;
202 		}
203 		if (build_nsec != NULL) {
204 			*build_nsec = false;
205 		}
206 		if (!dns_rdataset_isassociated(&privateset)) {
207 			goto success;
208 		}
209 		/*
210 		 * If we are in the process of building a new NSEC3 chain
211 		 * then we don't need to build a NSEC chain.
212 		 */
213 		for (result = dns_rdataset_first(&privateset);
214 		     result == ISC_R_SUCCESS;
215 		     result = dns_rdataset_next(&privateset))
216 		{
217 			dns_rdata_t private = DNS_RDATA_INIT;
218 			dns_rdata_t rdata = DNS_RDATA_INIT;
219 
220 			dns_rdataset_current(&privateset, &private);
221 			if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
222 							sizeof(buf)))
223 			{
224 				continue;
225 			}
226 			if (CREATE(rdata.data[1])) {
227 				goto success;
228 			}
229 		}
230 
231 		/*
232 		 * Check to see if there will be a active NSEC3CHAIN once
233 		 * the changes queued complete.
234 		 */
235 		count = 0;
236 		for (result = dns_rdataset_first(&nsec3paramset);
237 		     result == ISC_R_SUCCESS;
238 		     result = dns_rdataset_next(&nsec3paramset))
239 		{
240 			dns_rdata_t rdata = DNS_RDATA_INIT;
241 
242 			/*
243 			 * If there is more that one NSEC3 chain present then
244 			 * we don't need to construct a NSEC chain.
245 			 */
246 			if (++count > 1) {
247 				goto success;
248 			}
249 			dns_rdataset_current(&nsec3paramset, &rdata);
250 			if (ignore(&rdata, &privateset)) {
251 				continue;
252 			}
253 			/*
254 			 * We still have a good NSEC3 chain or we are
255 			 * not creating a NSEC chain as NONSEC is set.
256 			 */
257 			goto success;
258 		}
259 
260 		/*
261 		 * The last NSEC3 chain is being removed and does not have
262 		 * have NONSEC set.
263 		 */
264 		if (build_nsec != NULL) {
265 			*build_nsec = true;
266 		}
267 		goto success;
268 	}
269 
270 	if (build_nsec != NULL) {
271 		*build_nsec = false;
272 	}
273 	if (build_nsec3 != NULL) {
274 		*build_nsec3 = false;
275 	}
276 	if (!dns_rdataset_isassociated(&privateset)) {
277 		goto success;
278 	}
279 
280 	signing = false;
281 	nsec3chain = false;
282 
283 	for (result = dns_rdataset_first(&privateset); result == ISC_R_SUCCESS;
284 	     result = dns_rdataset_next(&privateset))
285 	{
286 		dns_rdata_t rdata = DNS_RDATA_INIT;
287 		dns_rdata_t private = DNS_RDATA_INIT;
288 
289 		dns_rdataset_current(&privateset, &private);
290 		if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
291 						sizeof(buf)))
292 		{
293 			/*
294 			 * Look for record that says we are signing the
295 			 * zone with a key.
296 			 */
297 			if (private.length == 5 && private.data[0] != 0 &&
298 			    private.data[3] == 0 && private.data[4] == 0)
299 			{
300 				signing = true;
301 			}
302 		} else {
303 			if (CREATE(rdata.data[1])) {
304 				nsec3chain = true;
305 			}
306 		}
307 	}
308 
309 	if (signing) {
310 		if (nsec3chain) {
311 			if (build_nsec3 != NULL) {
312 				*build_nsec3 = true;
313 			}
314 		} else {
315 			if (build_nsec != NULL) {
316 				*build_nsec = true;
317 			}
318 		}
319 	}
320 
321 success:
322 	result = ISC_R_SUCCESS;
323 failure:
324 	if (dns_rdataset_isassociated(&nsecset)) {
325 		dns_rdataset_disassociate(&nsecset);
326 	}
327 	if (dns_rdataset_isassociated(&nsec3paramset)) {
328 		dns_rdataset_disassociate(&nsec3paramset);
329 	}
330 	if (dns_rdataset_isassociated(&privateset)) {
331 		dns_rdataset_disassociate(&privateset);
332 	}
333 	if (node != NULL) {
334 		dns_db_detachnode(db, &node);
335 	}
336 	return (result);
337 }
338 
339 isc_result_t
dns_private_totext(dns_rdata_t * private,isc_buffer_t * buf)340 dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
341 	isc_result_t result;
342 
343 	if (private->length < 5) {
344 		return (ISC_R_NOTFOUND);
345 	}
346 
347 	if (private->data[0] == 0) {
348 		unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE];
349 		unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE];
350 		dns_rdata_t rdata = DNS_RDATA_INIT;
351 		dns_rdata_nsec3param_t nsec3param;
352 		bool del, init, nonsec;
353 		isc_buffer_t b;
354 
355 		if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf,
356 						sizeof(nsec3buf)))
357 		{
358 			CHECK(ISC_R_FAILURE);
359 		}
360 
361 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
362 
363 		del = ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0);
364 		init = ((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0);
365 		nonsec = ((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0);
366 
367 		nsec3param.flags &=
368 			~(DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_REMOVE |
369 			  DNS_NSEC3FLAG_INITIAL | DNS_NSEC3FLAG_NONSEC);
370 
371 		if (init) {
372 			isc_buffer_putstr(buf, "Pending NSEC3 chain ");
373 		} else if (del) {
374 			isc_buffer_putstr(buf, "Removing NSEC3 chain ");
375 		} else {
376 			isc_buffer_putstr(buf, "Creating NSEC3 chain ");
377 		}
378 
379 		dns_rdata_reset(&rdata);
380 		isc_buffer_init(&b, newbuf, sizeof(newbuf));
381 		CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
382 					   dns_rdatatype_nsec3param,
383 					   &nsec3param, &b));
384 
385 		CHECK(dns_rdata_totext(&rdata, NULL, buf));
386 
387 		if (del && !nonsec) {
388 			isc_buffer_putstr(buf, " / creating NSEC chain");
389 		}
390 	} else if (private->length == 5) {
391 		unsigned char alg = private->data[0];
392 		dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
393 		char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
394 			algbuf[DNS_SECALG_FORMATSIZE];
395 		bool del = private->data[3];
396 		bool complete = private->data[4];
397 
398 		if (del && complete) {
399 			isc_buffer_putstr(buf, "Done removing signatures for ");
400 		} else if (del) {
401 			isc_buffer_putstr(buf, "Removing signatures for ");
402 		} else if (complete) {
403 			isc_buffer_putstr(buf, "Done signing with ");
404 		} else {
405 			isc_buffer_putstr(buf, "Signing with ");
406 		}
407 
408 		dns_secalg_format(alg, algbuf, sizeof(algbuf));
409 		snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
410 		isc_buffer_putstr(buf, keybuf);
411 	} else {
412 		return (ISC_R_NOTFOUND);
413 	}
414 
415 	isc_buffer_putuint8(buf, 0);
416 	result = ISC_R_SUCCESS;
417 failure:
418 	return (result);
419 }
420