Home | History | Annotate | Line # | Download | only in dns
private.c revision 1.7
      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