1/* $NetBSD: private.c,v 1.1 2024/02/18 20:57:33 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 64static bool 65ignore(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], ¶m->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 109isc_result_t 110dns_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 321success: 322 result = ISC_R_SUCCESS; 323failure: 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 339isc_result_t 340dns_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; 417failure: 418 return (result); 419} 420