Home | History | Annotate | Line # | Download | only in dns
private.c revision 1.8
      1 /*	$NetBSD: private.c,v 1.8 2023/01/25 21:43: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 		{
     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
    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
    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