1 /* $NetBSD: private.c,v 1.10 2025/01/26 16:25:24 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/result.h> 20 #include <isc/string.h> 21 #include <isc/types.h> 22 #include <isc/util.h> 23 24 #include <dns/nsec3.h> 25 #include <dns/private.h> 26 27 /* 28 * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM 29 * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist. 30 * 31 * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain 32 * if all the NSEC3PARAM records (and associated chains) are slated for 33 * destruction and we have not been told to NOT build the NSEC chain. 34 * 35 * If the NSEC set exist then check to see if there is a request to create 36 * a NSEC3 chain. 37 * 38 * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private 39 * type exists then we need to examine it to determine if NSEC3 chain has 40 * been requested to be built otherwise a NSEC chain needs to be built. 41 */ 42 43 #define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) 44 #define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) 45 #define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0) 46 #define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0) 47 48 #define CHECK(x) \ 49 do { \ 50 result = (x); \ 51 if (result != ISC_R_SUCCESS) \ 52 goto failure; \ 53 } while (0) 54 55 /* 56 * Work out if 'param' should be ignored or not (i.e. it is in the process 57 * of being removed). 58 * 59 * Note: we 'belt-and-braces' here by also checking for a CREATE private 60 * record and keep the param record in this case. 61 */ 62 63 static bool 64 ignore(dns_rdata_t *param, dns_rdataset_t *privateset) { 65 isc_result_t result; 66 67 for (result = dns_rdataset_first(privateset); result == ISC_R_SUCCESS; 68 result = dns_rdataset_next(privateset)) 69 { 70 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 71 dns_rdata_t private = DNS_RDATA_INIT; 72 dns_rdata_t rdata = DNS_RDATA_INIT; 73 74 dns_rdataset_current(privateset, &private); 75 if (!dns_nsec3param_fromprivate(&private, &rdata, buf, 76 sizeof(buf))) 77 { 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 { 185 continue; 186 } 187 if (REMOVE(rdata.data[1])) { 188 continue; 189 } 190 if (build_nsec3 != NULL) { 191 *build_nsec3 = true; 192 } 193 break; 194 } 195 goto success; 196 } 197 198 if (dns_rdataset_isassociated(&nsec3paramset)) { 199 if (build_nsec3 != NULL) { 200 *build_nsec3 = true; 201 } 202 if (build_nsec != NULL) { 203 *build_nsec = false; 204 } 205 if (!dns_rdataset_isassociated(&privateset)) { 206 goto success; 207 } 208 /* 209 * If we are in the process of building a new NSEC3 chain 210 * then we don't need to build a NSEC chain. 211 */ 212 for (result = dns_rdataset_first(&privateset); 213 result == ISC_R_SUCCESS; 214 result = dns_rdataset_next(&privateset)) 215 { 216 dns_rdata_t private = DNS_RDATA_INIT; 217 dns_rdata_t rdata = DNS_RDATA_INIT; 218 219 dns_rdataset_current(&privateset, &private); 220 if (!dns_nsec3param_fromprivate(&private, &rdata, buf, 221 sizeof(buf))) 222 { 223 continue; 224 } 225 if (CREATE(rdata.data[1])) { 226 goto success; 227 } 228 } 229 230 /* 231 * Check to see if there will be a active NSEC3CHAIN once 232 * the changes queued complete. 233 */ 234 count = 0; 235 for (result = dns_rdataset_first(&nsec3paramset); 236 result == ISC_R_SUCCESS; 237 result = dns_rdataset_next(&nsec3paramset)) 238 { 239 dns_rdata_t rdata = DNS_RDATA_INIT; 240 241 /* 242 * If there is more that one NSEC3 chain present then 243 * we don't need to construct a NSEC chain. 244 */ 245 if (++count > 1) { 246 goto success; 247 } 248 dns_rdataset_current(&nsec3paramset, &rdata); 249 if (ignore(&rdata, &privateset)) { 250 continue; 251 } 252 /* 253 * We still have a good NSEC3 chain or we are 254 * not creating a NSEC chain as NONSEC is set. 255 */ 256 goto success; 257 } 258 259 /* 260 * The last NSEC3 chain is being removed and does not have 261 * have NONSEC set. 262 */ 263 if (build_nsec != NULL) { 264 *build_nsec = true; 265 } 266 goto success; 267 } 268 269 if (build_nsec != NULL) { 270 *build_nsec = false; 271 } 272 if (build_nsec3 != NULL) { 273 *build_nsec3 = false; 274 } 275 if (!dns_rdataset_isassociated(&privateset)) { 276 goto success; 277 } 278 279 signing = false; 280 nsec3chain = false; 281 282 for (result = dns_rdataset_first(&privateset); result == ISC_R_SUCCESS; 283 result = dns_rdataset_next(&privateset)) 284 { 285 dns_rdata_t rdata = DNS_RDATA_INIT; 286 dns_rdata_t private = DNS_RDATA_INIT; 287 288 dns_rdataset_current(&privateset, &private); 289 if (!dns_nsec3param_fromprivate(&private, &rdata, buf, 290 sizeof(buf))) 291 { 292 /* 293 * Look for record that says we are signing the 294 * zone with a key. 295 */ 296 if (private.length == 5 && private.data[0] != 0 && 297 private.data[3] == 0 && private.data[4] == 0) 298 { 299 signing = true; 300 } 301 } else { 302 if (CREATE(rdata.data[1])) { 303 nsec3chain = true; 304 } 305 } 306 } 307 308 if (signing) { 309 if (nsec3chain) { 310 if (build_nsec3 != NULL) { 311 *build_nsec3 = true; 312 } 313 } else { 314 if (build_nsec != NULL) { 315 *build_nsec = true; 316 } 317 } 318 } 319 320 success: 321 result = ISC_R_SUCCESS; 322 failure: 323 if (dns_rdataset_isassociated(&nsecset)) { 324 dns_rdataset_disassociate(&nsecset); 325 } 326 if (dns_rdataset_isassociated(&nsec3paramset)) { 327 dns_rdataset_disassociate(&nsec3paramset); 328 } 329 if (dns_rdataset_isassociated(&privateset)) { 330 dns_rdataset_disassociate(&privateset); 331 } 332 if (node != NULL) { 333 dns_db_detachnode(db, &node); 334 } 335 return result; 336 } 337 338 isc_result_t 339 dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) { 340 isc_result_t result; 341 342 if (private->length < 5) { 343 return ISC_R_NOTFOUND; 344 } 345 346 if (private->data[0] == 0) { 347 unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE]; 348 unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE]; 349 dns_rdata_t rdata = DNS_RDATA_INIT; 350 dns_rdata_nsec3param_t nsec3param; 351 bool del, init, nonsec; 352 isc_buffer_t b; 353 354 if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf, 355 sizeof(nsec3buf))) 356 { 357 CHECK(ISC_R_FAILURE); 358 } 359 360 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 361 362 del = ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0); 363 init = ((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0); 364 nonsec = ((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0); 365 366 nsec3param.flags &= 367 ~(DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_REMOVE | 368 DNS_NSEC3FLAG_INITIAL | DNS_NSEC3FLAG_NONSEC); 369 370 if (init) { 371 isc_buffer_putstr(buf, "Pending NSEC3 chain "); 372 } else if (del) { 373 isc_buffer_putstr(buf, "Removing NSEC3 chain "); 374 } else { 375 isc_buffer_putstr(buf, "Creating NSEC3 chain "); 376 } 377 378 dns_rdata_reset(&rdata); 379 isc_buffer_init(&b, newbuf, sizeof(newbuf)); 380 CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in, 381 dns_rdatatype_nsec3param, 382 &nsec3param, &b)); 383 384 CHECK(dns_rdata_totext(&rdata, NULL, buf)); 385 386 if (del && !nonsec) { 387 isc_buffer_putstr(buf, " / creating NSEC chain"); 388 } 389 } else if (private->length == 5) { 390 unsigned char alg = private->data[0]; 391 dns_keytag_t keyid = (private->data[2] | private->data[1] << 8); 392 char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ], 393 algbuf[DNS_SECALG_FORMATSIZE]; 394 bool del = private->data[3]; 395 bool complete = private->data[4]; 396 397 if (del && complete) { 398 isc_buffer_putstr(buf, "Done removing signatures for "); 399 } else if (del) { 400 isc_buffer_putstr(buf, "Removing signatures for "); 401 } else if (complete) { 402 isc_buffer_putstr(buf, "Done signing with "); 403 } else { 404 isc_buffer_putstr(buf, "Signing with "); 405 } 406 407 dns_secalg_format(alg, algbuf, sizeof(algbuf)); 408 snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf); 409 isc_buffer_putstr(buf, keybuf); 410 } else { 411 return ISC_R_NOTFOUND; 412 } 413 414 isc_buffer_putuint8(buf, 0); 415 result = ISC_R_SUCCESS; 416 failure: 417 return result; 418 } 419