1224090Sdougb/* 2254897Serwin * Copyright (C) 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id$ */ 18224090Sdougb 19224090Sdougb#include "config.h" 20224090Sdougb 21224090Sdougb#include <isc/result.h> 22224090Sdougb#include <isc/string.h> 23224090Sdougb#include <isc/types.h> 24224090Sdougb#include <isc/base64.h> 25224090Sdougb 26224090Sdougb#include <dns/nsec3.h> 27224090Sdougb#include <dns/private.h> 28224090Sdougb 29224090Sdougb/* 30224090Sdougb * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM 31224090Sdougb * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist. 32224090Sdougb * 33224090Sdougb * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain 34224090Sdougb * if all the NSEC3PARAM records (and associated chains) are slated for 35224090Sdougb * destruction and we have not been told to NOT build the NSEC chain. 36224090Sdougb * 37224090Sdougb * If the NSEC set exist then check to see if there is a request to create 38224090Sdougb * a NSEC3 chain. 39224090Sdougb * 40224090Sdougb * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private 41224090Sdougb * type exists then we need to examine it to determine if NSEC3 chain has 42224090Sdougb * been requested to be built otherwise a NSEC chain needs to be built. 43224090Sdougb */ 44224090Sdougb 45224090Sdougb#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) 46224090Sdougb#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) 47254897Serwin#define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0) 48224090Sdougb#define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0) 49224090Sdougb 50224090Sdougb#define CHECK(x) do { \ 51224090Sdougb result = (x); \ 52224090Sdougb if (result != ISC_R_SUCCESS) \ 53224090Sdougb goto failure; \ 54224090Sdougb } while (0) 55224090Sdougb 56224090Sdougb/* 57224090Sdougb * Work out if 'param' should be ignored or not (i.e. it is in the process 58224090Sdougb * of being removed). 59224090Sdougb * 60224090Sdougb * Note: we 'belt-and-braces' here by also checking for a CREATE private 61224090Sdougb * record and keep the param record in this case. 62224090Sdougb */ 63224090Sdougb 64224090Sdougbstatic isc_boolean_t 65224090Sdougbignore(dns_rdata_t *param, dns_rdataset_t *privateset) { 66224090Sdougb isc_result_t result; 67224090Sdougb 68224090Sdougb for (result = dns_rdataset_first(privateset); 69224090Sdougb result == ISC_R_SUCCESS; 70224090Sdougb result = dns_rdataset_next(privateset)) { 71224090Sdougb unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 72224090Sdougb dns_rdata_t private = DNS_RDATA_INIT; 73224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 74224090Sdougb 75224090Sdougb dns_rdataset_current(privateset, &private); 76224090Sdougb if (!dns_nsec3param_fromprivate(&private, &rdata, 77224090Sdougb buf, sizeof(buf))) 78224090Sdougb continue; 79224090Sdougb /* 80224090Sdougb * We are going to create a new NSEC3 chain so it 81224090Sdougb * doesn't matter if we are removing this one. 82224090Sdougb */ 83224090Sdougb if (CREATE(rdata.data[1])) 84224090Sdougb return (ISC_FALSE); 85224090Sdougb if (rdata.data[0] != param->data[0] || 86224090Sdougb rdata.data[2] != param->data[2] || 87224090Sdougb rdata.data[3] != param->data[3] || 88224090Sdougb rdata.data[4] != param->data[4] || 89224090Sdougb memcmp(&rdata.data[5], ¶m->data[5], param->data[4])) 90224090Sdougb continue; 91224090Sdougb /* 92224090Sdougb * The removal of this NSEC3 chain does NOT cause a 93224090Sdougb * NSEC chain to be created so we don't need to tell 94224090Sdougb * the caller that it will be removed. 95224090Sdougb */ 96224090Sdougb if (NONSEC(rdata.data[1])) 97224090Sdougb return (ISC_FALSE); 98224090Sdougb return (ISC_TRUE); 99224090Sdougb } 100224090Sdougb return (ISC_FALSE); 101224090Sdougb} 102224090Sdougb 103224090Sdougbisc_result_t 104224090Sdougbdns_private_chains(dns_db_t *db, dns_dbversion_t *ver, 105224090Sdougb dns_rdatatype_t privatetype, 106224090Sdougb isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3) 107224090Sdougb{ 108224090Sdougb dns_dbnode_t *node; 109224090Sdougb dns_rdataset_t nsecset, nsec3paramset, privateset; 110224090Sdougb isc_boolean_t nsec3chain; 111224090Sdougb isc_boolean_t signing; 112224090Sdougb isc_result_t result; 113224090Sdougb unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 114224090Sdougb unsigned int count; 115224090Sdougb 116224090Sdougb node = NULL; 117224090Sdougb dns_rdataset_init(&nsecset); 118224090Sdougb dns_rdataset_init(&nsec3paramset); 119224090Sdougb dns_rdataset_init(&privateset); 120224090Sdougb 121224090Sdougb CHECK(dns_db_getoriginnode(db, &node)); 122224090Sdougb 123224090Sdougb result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 124224090Sdougb 0, (isc_stdtime_t) 0, &nsecset, NULL); 125224090Sdougb 126224090Sdougb if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 127224090Sdougb goto failure; 128224090Sdougb 129224090Sdougb result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 130224090Sdougb 0, (isc_stdtime_t) 0, &nsec3paramset, 131224090Sdougb NULL); 132224090Sdougb if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 133224090Sdougb goto failure; 134224090Sdougb 135224090Sdougb if (dns_rdataset_isassociated(&nsecset) && 136224090Sdougb dns_rdataset_isassociated(&nsec3paramset)) { 137224090Sdougb if (build_nsec != NULL) 138224090Sdougb *build_nsec = ISC_TRUE; 139224090Sdougb if (build_nsec3 != NULL) 140224090Sdougb *build_nsec3 = ISC_TRUE; 141224090Sdougb goto success; 142224090Sdougb } 143224090Sdougb 144224090Sdougb if (privatetype != (dns_rdatatype_t)0) { 145224090Sdougb result = dns_db_findrdataset(db, node, ver, privatetype, 146224090Sdougb 0, (isc_stdtime_t) 0, 147224090Sdougb &privateset, NULL); 148224090Sdougb if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 149224090Sdougb goto failure; 150224090Sdougb } 151224090Sdougb 152224090Sdougb /* 153254897Serwin * Look to see if we also need to be creating a NSEC3 chain. 154224090Sdougb */ 155224090Sdougb if (dns_rdataset_isassociated(&nsecset)) { 156224090Sdougb if (build_nsec != NULL) 157224090Sdougb *build_nsec = ISC_TRUE; 158224090Sdougb if (build_nsec3 != NULL) 159224090Sdougb *build_nsec3 = ISC_FALSE; 160224090Sdougb if (!dns_rdataset_isassociated(&privateset)) 161224090Sdougb goto success; 162224090Sdougb for (result = dns_rdataset_first(&privateset); 163224090Sdougb result == ISC_R_SUCCESS; 164224090Sdougb result = dns_rdataset_next(&privateset)) { 165224090Sdougb unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 166224090Sdougb dns_rdata_t private = DNS_RDATA_INIT; 167224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 168224090Sdougb 169224090Sdougb dns_rdataset_current(&privateset, &private); 170224090Sdougb if (!dns_nsec3param_fromprivate(&private, &rdata, 171224090Sdougb buf, sizeof(buf))) 172224090Sdougb continue; 173224090Sdougb if (REMOVE(rdata.data[1])) 174224090Sdougb continue; 175224090Sdougb if (build_nsec3 != NULL) 176224090Sdougb *build_nsec3 = ISC_TRUE; 177224090Sdougb break; 178224090Sdougb } 179224090Sdougb goto success; 180224090Sdougb } 181224090Sdougb 182224090Sdougb if (dns_rdataset_isassociated(&nsec3paramset)) { 183224090Sdougb if (build_nsec3 != NULL) 184224090Sdougb *build_nsec3 = ISC_TRUE; 185224090Sdougb if (build_nsec != NULL) 186224090Sdougb *build_nsec = ISC_FALSE; 187224090Sdougb if (!dns_rdataset_isassociated(&privateset)) 188224090Sdougb goto success; 189224090Sdougb /* 190224090Sdougb * If we are in the process of building a new NSEC3 chain 191224090Sdougb * then we don't need to build a NSEC chain. 192224090Sdougb */ 193224090Sdougb for (result = dns_rdataset_first(&privateset); 194224090Sdougb result == ISC_R_SUCCESS; 195224090Sdougb result = dns_rdataset_next(&privateset)) { 196224090Sdougb dns_rdata_t private = DNS_RDATA_INIT; 197224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 198224090Sdougb 199224090Sdougb dns_rdataset_current(&privateset, &private); 200224090Sdougb if (!dns_nsec3param_fromprivate(&private, &rdata, 201224090Sdougb buf, sizeof(buf))) 202224090Sdougb continue; 203224090Sdougb if (CREATE(rdata.data[1])) 204224090Sdougb goto success; 205224090Sdougb } 206224090Sdougb 207224090Sdougb /* 208224090Sdougb * Check to see if there will be a active NSEC3CHAIN once 209224090Sdougb * the changes queued complete. 210224090Sdougb */ 211224090Sdougb count = 0; 212224090Sdougb for (result = dns_rdataset_first(&nsec3paramset); 213224090Sdougb result == ISC_R_SUCCESS; 214224090Sdougb result = dns_rdataset_next(&nsec3paramset)) { 215224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 216224090Sdougb 217224090Sdougb /* 218224090Sdougb * If there is more that one NSEC3 chain present then 219224090Sdougb * we don't need to construct a NSEC chain. 220224090Sdougb */ 221224090Sdougb if (++count > 1) 222224090Sdougb goto success; 223224090Sdougb dns_rdataset_current(&nsec3paramset, &rdata); 224224090Sdougb if (ignore(&rdata, &privateset)) 225224090Sdougb continue; 226224090Sdougb /* 227224090Sdougb * We still have a good NSEC3 chain or we are 228224090Sdougb * not creating a NSEC chain as NONSEC is set. 229224090Sdougb */ 230224090Sdougb goto success; 231224090Sdougb } 232224090Sdougb 233224090Sdougb /* 234224090Sdougb * The last NSEC3 chain is being removed and does not have 235224090Sdougb * have NONSEC set. 236224090Sdougb */ 237224090Sdougb if (build_nsec != NULL) 238224090Sdougb *build_nsec = ISC_TRUE; 239224090Sdougb goto success; 240224090Sdougb } 241224090Sdougb 242224090Sdougb if (build_nsec != NULL) 243224090Sdougb *build_nsec = ISC_FALSE; 244224090Sdougb if (build_nsec3 != NULL) 245224090Sdougb *build_nsec3 = ISC_FALSE; 246224090Sdougb if (!dns_rdataset_isassociated(&privateset)) 247224090Sdougb goto success; 248224090Sdougb 249224090Sdougb signing = ISC_FALSE; 250224090Sdougb nsec3chain = ISC_FALSE; 251224090Sdougb 252224090Sdougb for (result = dns_rdataset_first(&privateset); 253224090Sdougb result == ISC_R_SUCCESS; 254224090Sdougb result = dns_rdataset_next(&privateset)) { 255224090Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 256224090Sdougb dns_rdata_t private = DNS_RDATA_INIT; 257224090Sdougb 258224090Sdougb dns_rdataset_current(&privateset, &private); 259224090Sdougb if (!dns_nsec3param_fromprivate(&private, &rdata, 260224090Sdougb buf, sizeof(buf))) { 261224090Sdougb /* 262224090Sdougb * Look for record that says we are signing the 263224090Sdougb * zone with a key. 264224090Sdougb */ 265224090Sdougb if (private.length == 5 && private.data[0] != 0 && 266224090Sdougb private.data[3] == 0 && private.data[4] == 0) 267224090Sdougb signing = ISC_TRUE; 268224090Sdougb } else { 269224090Sdougb if (CREATE(rdata.data[1])) 270224090Sdougb nsec3chain = ISC_TRUE; 271224090Sdougb } 272224090Sdougb } 273224090Sdougb 274224090Sdougb if (signing) { 275224090Sdougb if (nsec3chain) { 276224090Sdougb if (build_nsec3 != NULL) 277224090Sdougb *build_nsec3 = ISC_TRUE; 278224090Sdougb } else { 279224090Sdougb if (build_nsec != NULL) 280224090Sdougb *build_nsec = ISC_TRUE; 281224090Sdougb } 282224090Sdougb } 283224090Sdougb 284224090Sdougb success: 285224090Sdougb result = ISC_R_SUCCESS; 286224090Sdougb failure: 287224090Sdougb if (dns_rdataset_isassociated(&nsecset)) 288224090Sdougb dns_rdataset_disassociate(&nsecset); 289224090Sdougb if (dns_rdataset_isassociated(&nsec3paramset)) 290224090Sdougb dns_rdataset_disassociate(&nsec3paramset); 291224090Sdougb if (dns_rdataset_isassociated(&privateset)) 292224090Sdougb dns_rdataset_disassociate(&privateset); 293224090Sdougb if (node != NULL) 294224090Sdougb dns_db_detachnode(db, &node); 295224090Sdougb return (result); 296224090Sdougb} 297254897Serwin 298254897Serwinisc_result_t 299254897Serwindns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) { 300254897Serwin isc_result_t result; 301254897Serwin 302254897Serwin if (private->length < 5) 303254897Serwin return (ISC_R_NOTFOUND); 304254897Serwin 305254897Serwin if (private->data[0] == 0) { 306254897Serwin unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE]; 307254897Serwin unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE]; 308254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 309254897Serwin dns_rdata_nsec3param_t nsec3param; 310254897Serwin isc_boolean_t remove, init, nonsec; 311254897Serwin isc_buffer_t b; 312254897Serwin 313254897Serwin if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf, 314254897Serwin sizeof(nsec3buf))) 315254897Serwin CHECK(ISC_R_FAILURE); 316254897Serwin 317254897Serwin CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 318254897Serwin 319254897Serwin remove = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0); 320254897Serwin init = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0); 321254897Serwin nonsec = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0); 322254897Serwin 323254897Serwin nsec3param.flags &= ~(DNS_NSEC3FLAG_CREATE| 324254897Serwin DNS_NSEC3FLAG_REMOVE| 325254897Serwin DNS_NSEC3FLAG_INITIAL| 326254897Serwin DNS_NSEC3FLAG_NONSEC); 327254897Serwin 328254897Serwin if (init) 329254897Serwin isc_buffer_putstr(buf, "Pending NSEC3 chain "); 330254897Serwin else if (remove) 331254897Serwin isc_buffer_putstr(buf, "Removing NSEC3 chain "); 332254897Serwin else 333254897Serwin isc_buffer_putstr(buf, "Creating NSEC3 chain "); 334254897Serwin 335254897Serwin dns_rdata_reset(&rdata); 336254897Serwin isc_buffer_init(&b, newbuf, sizeof(newbuf)); 337254897Serwin CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in, 338254897Serwin dns_rdatatype_nsec3param, 339254897Serwin &nsec3param, &b)); 340254897Serwin 341254897Serwin CHECK(dns_rdata_totext(&rdata, NULL, buf)); 342254897Serwin 343254897Serwin if (remove && !nonsec) 344254897Serwin isc_buffer_putstr(buf, " / creating NSEC chain"); 345254897Serwin } else if (private->length == 5) { 346254897Serwin unsigned char alg = private->data[0]; 347254897Serwin dns_keytag_t keyid = (private->data[2] | private->data[1] << 8); 348254897Serwin char keybuf[BUFSIZ], algbuf[DNS_SECALG_FORMATSIZE]; 349254897Serwin isc_boolean_t remove = ISC_TF(private->data[3] != 0); 350254897Serwin isc_boolean_t complete = ISC_TF(private->data[4] != 0); 351254897Serwin 352254897Serwin if (remove && complete) 353254897Serwin isc_buffer_putstr(buf, "Done removing signatures for "); 354254897Serwin else if (remove) 355254897Serwin isc_buffer_putstr(buf, "Removing signatures for "); 356254897Serwin else if (complete) 357254897Serwin isc_buffer_putstr(buf, "Done signing with "); 358254897Serwin else 359254897Serwin isc_buffer_putstr(buf, "Signing with "); 360254897Serwin 361254897Serwin dns_secalg_format(alg, algbuf, sizeof(algbuf)); 362254897Serwin sprintf(keybuf, "key %d/%s", keyid, algbuf); 363254897Serwin isc_buffer_putstr(buf, keybuf); 364254897Serwin } else 365254897Serwin return (ISC_R_NOTFOUND); 366254897Serwin 367254897Serwin isc_buffer_putuint8(buf, 0); 368254897Serwin result = ISC_R_SUCCESS; 369254897Serwin failure: 370254897Serwin return (result); 371254897Serwin} 372