1/* 2 * Copyright (C) 2009, 2012 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id$ */ 18 19#include "config.h" 20 21#include <isc/result.h> 22#include <isc/string.h> 23#include <isc/types.h> 24#include <isc/base64.h> 25 26#include <dns/nsec3.h> 27#include <dns/private.h> 28 29/* 30 * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM 31 * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist. 32 * 33 * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain 34 * if all the NSEC3PARAM records (and associated chains) are slated for 35 * destruction and we have not been told to NOT build the NSEC chain. 36 * 37 * If the NSEC set exist then check to see if there is a request to create 38 * a NSEC3 chain. 39 * 40 * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private 41 * type exists then we need to examine it to determine if NSEC3 chain has 42 * been requested to be built otherwise a NSEC chain needs to be built. 43 */ 44 45#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0) 46#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0) 47#define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0) 48 49#define CHECK(x) 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 63static isc_boolean_t 64ignore(dns_rdata_t *param, dns_rdataset_t *privateset) { 65 isc_result_t result; 66 67 for (result = dns_rdataset_first(privateset); 68 result == ISC_R_SUCCESS; 69 result = dns_rdataset_next(privateset)) { 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, 76 buf, sizeof(buf))) 77 continue; 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 (ISC_FALSE); 84 if (rdata.data[0] != param->data[0] || 85 rdata.data[2] != param->data[2] || 86 rdata.data[3] != param->data[3] || 87 rdata.data[4] != param->data[4] || 88 memcmp(&rdata.data[5], ¶m->data[5], param->data[4])) 89 continue; 90 /* 91 * The removal of this NSEC3 chain does NOT cause a 92 * NSEC chain to be created so we don't need to tell 93 * the caller that it will be removed. 94 */ 95 if (NONSEC(rdata.data[1])) 96 return (ISC_FALSE); 97 return (ISC_TRUE); 98 } 99 return (ISC_FALSE); 100} 101 102isc_result_t 103dns_private_chains(dns_db_t *db, dns_dbversion_t *ver, 104 dns_rdatatype_t privatetype, 105 isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3) 106{ 107 dns_dbnode_t *node; 108 dns_rdataset_t nsecset, nsec3paramset, privateset; 109 isc_boolean_t nsec3chain; 110 isc_boolean_t signing; 111 isc_result_t result; 112 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 113 unsigned int count; 114 115 node = NULL; 116 dns_rdataset_init(&nsecset); 117 dns_rdataset_init(&nsec3paramset); 118 dns_rdataset_init(&privateset); 119 120 CHECK(dns_db_getoriginnode(db, &node)); 121 122 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 123 0, (isc_stdtime_t) 0, &nsecset, NULL); 124 125 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 126 goto failure; 127 128 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 129 0, (isc_stdtime_t) 0, &nsec3paramset, 130 NULL); 131 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 132 goto failure; 133 134 if (dns_rdataset_isassociated(&nsecset) && 135 dns_rdataset_isassociated(&nsec3paramset)) { 136 if (build_nsec != NULL) 137 *build_nsec = ISC_TRUE; 138 if (build_nsec3 != NULL) 139 *build_nsec3 = ISC_TRUE; 140 goto success; 141 } 142 143 if (privatetype != (dns_rdatatype_t)0) { 144 result = dns_db_findrdataset(db, node, ver, privatetype, 145 0, (isc_stdtime_t) 0, 146 &privateset, NULL); 147 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 148 goto failure; 149 } 150 151 /* 152 * Look to see if we also need to be creating a NSEC3 chains. 153 */ 154 if (dns_rdataset_isassociated(&nsecset)) { 155 if (build_nsec != NULL) 156 *build_nsec = ISC_TRUE; 157 if (build_nsec3 != NULL) 158 *build_nsec3 = ISC_FALSE; 159 if (!dns_rdataset_isassociated(&privateset)) 160 goto success; 161 for (result = dns_rdataset_first(&privateset); 162 result == ISC_R_SUCCESS; 163 result = dns_rdataset_next(&privateset)) { 164 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 165 dns_rdata_t private = DNS_RDATA_INIT; 166 dns_rdata_t rdata = DNS_RDATA_INIT; 167 168 dns_rdataset_current(&privateset, &private); 169 if (!dns_nsec3param_fromprivate(&private, &rdata, 170 buf, sizeof(buf))) 171 continue; 172 if (REMOVE(rdata.data[1])) 173 continue; 174 if (build_nsec3 != NULL) 175 *build_nsec3 = ISC_TRUE; 176 break; 177 } 178 goto success; 179 } 180 181 if (dns_rdataset_isassociated(&nsec3paramset)) { 182 if (build_nsec3 != NULL) 183 *build_nsec3 = ISC_TRUE; 184 if (build_nsec != NULL) 185 *build_nsec = ISC_FALSE; 186 if (!dns_rdataset_isassociated(&privateset)) 187 goto success; 188 /* 189 * If we are in the process of building a new NSEC3 chain 190 * then we don't need to build a NSEC chain. 191 */ 192 for (result = dns_rdataset_first(&privateset); 193 result == ISC_R_SUCCESS; 194 result = dns_rdataset_next(&privateset)) { 195 dns_rdata_t private = DNS_RDATA_INIT; 196 dns_rdata_t rdata = DNS_RDATA_INIT; 197 198 dns_rdataset_current(&privateset, &private); 199 if (!dns_nsec3param_fromprivate(&private, &rdata, 200 buf, sizeof(buf))) 201 continue; 202 if (CREATE(rdata.data[1])) 203 goto success; 204 } 205 206 /* 207 * Check to see if there will be a active NSEC3CHAIN once 208 * the changes queued complete. 209 */ 210 count = 0; 211 for (result = dns_rdataset_first(&nsec3paramset); 212 result == ISC_R_SUCCESS; 213 result = dns_rdataset_next(&nsec3paramset)) { 214 dns_rdata_t rdata = DNS_RDATA_INIT; 215 216 /* 217 * If there is more that one NSEC3 chain present then 218 * we don't need to construct a NSEC chain. 219 */ 220 if (++count > 1) 221 goto success; 222 dns_rdataset_current(&nsec3paramset, &rdata); 223 if (ignore(&rdata, &privateset)) 224 continue; 225 /* 226 * We still have a good NSEC3 chain or we are 227 * not creating a NSEC chain as NONSEC is set. 228 */ 229 goto success; 230 } 231 232 /* 233 * The last NSEC3 chain is being removed and does not have 234 * have NONSEC set. 235 */ 236 if (build_nsec != NULL) 237 *build_nsec = ISC_TRUE; 238 goto success; 239 } 240 241 if (build_nsec != NULL) 242 *build_nsec = ISC_FALSE; 243 if (build_nsec3 != NULL) 244 *build_nsec3 = ISC_FALSE; 245 if (!dns_rdataset_isassociated(&privateset)) 246 goto success; 247 248 signing = ISC_FALSE; 249 nsec3chain = ISC_FALSE; 250 251 for (result = dns_rdataset_first(&privateset); 252 result == ISC_R_SUCCESS; 253 result = dns_rdataset_next(&privateset)) { 254 dns_rdata_t rdata = DNS_RDATA_INIT; 255 dns_rdata_t private = DNS_RDATA_INIT; 256 257 dns_rdataset_current(&privateset, &private); 258 if (!dns_nsec3param_fromprivate(&private, &rdata, 259 buf, sizeof(buf))) { 260 /* 261 * Look for record that says we are signing the 262 * zone with a key. 263 */ 264 if (private.length == 5 && private.data[0] != 0 && 265 private.data[3] == 0 && private.data[4] == 0) 266 signing = ISC_TRUE; 267 } else { 268 if (CREATE(rdata.data[1])) 269 nsec3chain = ISC_TRUE; 270 } 271 } 272 273 if (signing) { 274 if (nsec3chain) { 275 if (build_nsec3 != NULL) 276 *build_nsec3 = ISC_TRUE; 277 } else { 278 if (build_nsec != NULL) 279 *build_nsec = ISC_TRUE; 280 } 281 } 282 283 success: 284 result = ISC_R_SUCCESS; 285 failure: 286 if (dns_rdataset_isassociated(&nsecset)) 287 dns_rdataset_disassociate(&nsecset); 288 if (dns_rdataset_isassociated(&nsec3paramset)) 289 dns_rdataset_disassociate(&nsec3paramset); 290 if (dns_rdataset_isassociated(&privateset)) 291 dns_rdataset_disassociate(&privateset); 292 if (node != NULL) 293 dns_db_detachnode(db, &node); 294 return (result); 295} 296