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], ¶m->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