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