1135446Strhodes/* 2262706Serwin * Copyright (C) 2004, 2005, 2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id: dnssectool.c,v 1.63 2011/10/21 03:55:33 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22170222Sdougb/*% 23170222Sdougb * DNSSEC Support Routines. 24170222Sdougb */ 25170222Sdougb 26135446Strhodes#include <config.h> 27135446Strhodes 28135446Strhodes#include <stdlib.h> 29135446Strhodes 30254897Serwin#include <isc/base32.h> 31135446Strhodes#include <isc/buffer.h> 32224092Sdougb#include <isc/dir.h> 33135446Strhodes#include <isc/entropy.h> 34254897Serwin#include <isc/heap.h> 35135446Strhodes#include <isc/list.h> 36135446Strhodes#include <isc/mem.h> 37135446Strhodes#include <isc/string.h> 38135446Strhodes#include <isc/time.h> 39135446Strhodes#include <isc/util.h> 40135446Strhodes#include <isc/print.h> 41135446Strhodes 42254897Serwin#include <dns/db.h> 43254897Serwin#include <dns/dbiterator.h> 44224092Sdougb#include <dns/dnssec.h> 45254897Serwin#include <dns/fixedname.h> 46224092Sdougb#include <dns/keyvalues.h> 47135446Strhodes#include <dns/log.h> 48135446Strhodes#include <dns/name.h> 49254897Serwin#include <dns/nsec.h> 50254897Serwin#include <dns/nsec3.h> 51135446Strhodes#include <dns/rdatastruct.h> 52135446Strhodes#include <dns/rdataclass.h> 53254897Serwin#include <dns/rdataset.h> 54254897Serwin#include <dns/rdatasetiter.h> 55135446Strhodes#include <dns/rdatatype.h> 56135446Strhodes#include <dns/result.h> 57135446Strhodes#include <dns/secalg.h> 58135446Strhodes#include <dns/time.h> 59135446Strhodes 60135446Strhodes#include "dnssectool.h" 61135446Strhodes 62254897Serwinstatic isc_heap_t *expected_chains, *found_chains; 63254897Serwin 64254897Serwinstruct nsec3_chain_fixed { 65254897Serwin isc_uint8_t hash; 66254897Serwin isc_uint8_t salt_length; 67254897Serwin isc_uint8_t next_length; 68254897Serwin isc_uint16_t iterations; 69254897Serwin /* unsigned char salt[0]; */ 70254897Serwin /* unsigned char owner[0]; */ 71254897Serwin /* unsigned char next[0]; */ 72254897Serwin}; 73254897Serwin 74135446Strhodesextern int verbose; 75135446Strhodesextern const char *program; 76135446Strhodes 77135446Strhodestypedef struct entropysource entropysource_t; 78135446Strhodes 79135446Strhodesstruct entropysource { 80135446Strhodes isc_entropysource_t *source; 81135446Strhodes isc_mem_t *mctx; 82135446Strhodes ISC_LINK(entropysource_t) link; 83135446Strhodes}; 84135446Strhodes 85135446Strhodesstatic ISC_LIST(entropysource_t) sources; 86135446Strhodesstatic fatalcallback_t *fatalcallback = NULL; 87135446Strhodes 88135446Strhodesvoid 89135446Strhodesfatal(const char *format, ...) { 90135446Strhodes va_list args; 91135446Strhodes 92204619Sdougb fprintf(stderr, "%s: fatal: ", program); 93135446Strhodes va_start(args, format); 94135446Strhodes vfprintf(stderr, format, args); 95135446Strhodes va_end(args); 96135446Strhodes fprintf(stderr, "\n"); 97135446Strhodes if (fatalcallback != NULL) 98135446Strhodes (*fatalcallback)(); 99135446Strhodes exit(1); 100135446Strhodes} 101135446Strhodes 102135446Strhodesvoid 103135446Strhodessetfatalcallback(fatalcallback_t *callback) { 104135446Strhodes fatalcallback = callback; 105135446Strhodes} 106135446Strhodes 107135446Strhodesvoid 108135446Strhodescheck_result(isc_result_t result, const char *message) { 109135446Strhodes if (result != ISC_R_SUCCESS) 110135446Strhodes fatal("%s: %s", message, isc_result_totext(result)); 111135446Strhodes} 112135446Strhodes 113135446Strhodesvoid 114135446Strhodesvbprintf(int level, const char *fmt, ...) { 115135446Strhodes va_list ap; 116135446Strhodes if (level > verbose) 117135446Strhodes return; 118135446Strhodes va_start(ap, fmt); 119135446Strhodes fprintf(stderr, "%s: ", program); 120135446Strhodes vfprintf(stderr, fmt, ap); 121135446Strhodes va_end(ap); 122135446Strhodes} 123135446Strhodes 124135446Strhodesvoid 125135446Strhodestype_format(const dns_rdatatype_t type, char *cp, unsigned int size) { 126135446Strhodes isc_buffer_t b; 127135446Strhodes isc_region_t r; 128135446Strhodes isc_result_t result; 129135446Strhodes 130135446Strhodes isc_buffer_init(&b, cp, size - 1); 131135446Strhodes result = dns_rdatatype_totext(type, &b); 132135446Strhodes check_result(result, "dns_rdatatype_totext()"); 133135446Strhodes isc_buffer_usedregion(&b, &r); 134135446Strhodes r.base[r.length] = 0; 135135446Strhodes} 136135446Strhodes 137135446Strhodesvoid 138135446Strhodessig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) { 139135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 140135446Strhodes char algstr[DNS_NAME_FORMATSIZE]; 141135446Strhodes 142135446Strhodes dns_name_format(&sig->signer, namestr, sizeof(namestr)); 143224092Sdougb dns_secalg_format(sig->algorithm, algstr, sizeof(algstr)); 144135446Strhodes snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid); 145135446Strhodes} 146135446Strhodes 147135446Strhodesvoid 148135446Strhodessetup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) { 149135446Strhodes isc_result_t result; 150135446Strhodes isc_logdestination_t destination; 151135446Strhodes isc_logconfig_t *logconfig = NULL; 152135446Strhodes isc_log_t *log = NULL; 153135446Strhodes int level; 154135446Strhodes 155153816Sdougb if (verbose < 0) 156153816Sdougb verbose = 0; 157135446Strhodes switch (verbose) { 158135446Strhodes case 0: 159135446Strhodes /* 160135446Strhodes * We want to see warnings about things like out-of-zone 161135446Strhodes * data in the master file even when not verbose. 162135446Strhodes */ 163135446Strhodes level = ISC_LOG_WARNING; 164135446Strhodes break; 165135446Strhodes case 1: 166135446Strhodes level = ISC_LOG_INFO; 167135446Strhodes break; 168135446Strhodes default: 169135446Strhodes level = ISC_LOG_DEBUG(verbose - 2 + 1); 170135446Strhodes break; 171135446Strhodes } 172135446Strhodes 173135446Strhodes RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS); 174135446Strhodes isc_log_setcontext(log); 175135446Strhodes dns_log_init(log); 176135446Strhodes dns_log_setcontext(log); 177135446Strhodes 178135446Strhodes RUNTIME_CHECK(isc_log_settag(logconfig, program) == ISC_R_SUCCESS); 179135446Strhodes 180135446Strhodes /* 181135446Strhodes * Set up a channel similar to default_stderr except: 182135446Strhodes * - the logging level is passed in 183135446Strhodes * - the program name and logging level are printed 184135446Strhodes * - no time stamp is printed 185135446Strhodes */ 186135446Strhodes destination.file.stream = stderr; 187135446Strhodes destination.file.name = NULL; 188135446Strhodes destination.file.versions = ISC_LOG_ROLLNEVER; 189135446Strhodes destination.file.maximum_size = 0; 190135446Strhodes result = isc_log_createchannel(logconfig, "stderr", 191135446Strhodes ISC_LOG_TOFILEDESC, 192135446Strhodes level, 193135446Strhodes &destination, 194135446Strhodes ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL); 195135446Strhodes check_result(result, "isc_log_createchannel()"); 196135446Strhodes 197135446Strhodes RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", 198135446Strhodes NULL, NULL) == ISC_R_SUCCESS); 199135446Strhodes 200135446Strhodes *logp = log; 201135446Strhodes} 202135446Strhodes 203135446Strhodesvoid 204135446Strhodescleanup_logging(isc_log_t **logp) { 205135446Strhodes isc_log_t *log; 206135446Strhodes 207135446Strhodes REQUIRE(logp != NULL); 208135446Strhodes 209135446Strhodes log = *logp; 210135446Strhodes if (log == NULL) 211135446Strhodes return; 212135446Strhodes isc_log_destroy(&log); 213135446Strhodes isc_log_setcontext(NULL); 214135446Strhodes dns_log_setcontext(NULL); 215135446Strhodes logp = NULL; 216135446Strhodes} 217135446Strhodes 218135446Strhodesvoid 219135446Strhodessetup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) { 220135446Strhodes isc_result_t result; 221135446Strhodes isc_entropysource_t *source = NULL; 222135446Strhodes entropysource_t *elt; 223135446Strhodes int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 224135446Strhodes 225135446Strhodes REQUIRE(ectx != NULL); 226194995Sdougb 227135446Strhodes if (*ectx == NULL) { 228135446Strhodes result = isc_entropy_create(mctx, ectx); 229135446Strhodes if (result != ISC_R_SUCCESS) 230135446Strhodes fatal("could not create entropy object"); 231135446Strhodes ISC_LIST_INIT(sources); 232135446Strhodes } 233135446Strhodes 234135446Strhodes if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 235135446Strhodes usekeyboard = ISC_ENTROPY_KEYBOARDYES; 236135446Strhodes randomfile = NULL; 237135446Strhodes } 238135446Strhodes 239135446Strhodes result = isc_entropy_usebestsource(*ectx, &source, randomfile, 240135446Strhodes usekeyboard); 241135446Strhodes 242135446Strhodes if (result != ISC_R_SUCCESS) 243135446Strhodes fatal("could not initialize entropy source: %s", 244135446Strhodes isc_result_totext(result)); 245135446Strhodes 246135446Strhodes if (source != NULL) { 247135446Strhodes elt = isc_mem_get(mctx, sizeof(*elt)); 248135446Strhodes if (elt == NULL) 249135446Strhodes fatal("out of memory"); 250135446Strhodes elt->source = source; 251135446Strhodes elt->mctx = mctx; 252135446Strhodes ISC_LINK_INIT(elt, link); 253135446Strhodes ISC_LIST_APPEND(sources, elt, link); 254135446Strhodes } 255135446Strhodes} 256135446Strhodes 257135446Strhodesvoid 258135446Strhodescleanup_entropy(isc_entropy_t **ectx) { 259135446Strhodes entropysource_t *source; 260135446Strhodes while (!ISC_LIST_EMPTY(sources)) { 261135446Strhodes source = ISC_LIST_HEAD(sources); 262135446Strhodes ISC_LIST_UNLINK(sources, source, link); 263135446Strhodes isc_entropy_destroysource(&source->source); 264135446Strhodes isc_mem_put(source->mctx, source, sizeof(*source)); 265135446Strhodes } 266135446Strhodes isc_entropy_detach(ectx); 267135446Strhodes} 268135446Strhodes 269224092Sdougbstatic isc_stdtime_t 270224092Sdougbtime_units(isc_stdtime_t offset, char *suffix, const char *str) { 271224092Sdougb switch (suffix[0]) { 272224092Sdougb case 'Y': case 'y': 273224092Sdougb return (offset * (365 * 24 * 3600)); 274224092Sdougb case 'M': case 'm': 275224092Sdougb switch (suffix[1]) { 276224092Sdougb case 'O': case 'o': 277224092Sdougb return (offset * (30 * 24 * 3600)); 278224092Sdougb case 'I': case 'i': 279224092Sdougb return (offset * 60); 280224092Sdougb case '\0': 281224092Sdougb fatal("'%s' ambiguous: use 'mi' for minutes " 282224092Sdougb "or 'mo' for months", str); 283224092Sdougb default: 284224092Sdougb fatal("time value %s is invalid", str); 285224092Sdougb } 286224092Sdougb /* NOTREACHED */ 287224092Sdougb break; 288224092Sdougb case 'W': case 'w': 289224092Sdougb return (offset * (7 * 24 * 3600)); 290224092Sdougb case 'D': case 'd': 291224092Sdougb return (offset * (24 * 3600)); 292224092Sdougb case 'H': case 'h': 293224092Sdougb return (offset * 3600); 294224092Sdougb case 'S': case 's': case '\0': 295224092Sdougb return (offset); 296224092Sdougb default: 297224092Sdougb fatal("time value %s is invalid", str); 298224092Sdougb } 299224092Sdougb /* NOTREACHED */ 300224092Sdougb return(0); /* silence compiler warning */ 301224092Sdougb} 302224092Sdougb 303224092Sdougbdns_ttl_t 304224092Sdougbstrtottl(const char *str) { 305224092Sdougb const char *orig = str; 306224092Sdougb dns_ttl_t ttl; 307224092Sdougb char *endp; 308224092Sdougb 309224092Sdougb ttl = strtol(str, &endp, 0); 310224092Sdougb if (ttl == 0 && endp == str) 311224092Sdougb fatal("TTL must be numeric"); 312224092Sdougb ttl = time_units(ttl, endp, orig); 313224092Sdougb return (ttl); 314224092Sdougb} 315224092Sdougb 316135446Strhodesisc_stdtime_t 317135446Strhodesstrtotime(const char *str, isc_int64_t now, isc_int64_t base) { 318135446Strhodes isc_int64_t val, offset; 319135446Strhodes isc_result_t result; 320224092Sdougb const char *orig = str; 321135446Strhodes char *endp; 322262706Serwin int n; 323135446Strhodes 324224092Sdougb if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') 325224092Sdougb return ((isc_stdtime_t) 0); 326224092Sdougb 327262706Serwin /* 328262706Serwin * We accept times in the following formats: 329262706Serwin * now([+-]offset) 330262706Serwin * YYYYMMDD([+-]offset) 331262706Serwin * YYYYMMDDhhmmss([+-]offset) 332262706Serwin * [+-]offset 333262706Serwin */ 334262706Serwin n = strspn(str, "0123456789"); 335262706Serwin if ((n == 8 || n == 14) && 336262706Serwin (str[n] == '\0' || str[n] == '-' || str[n] == '+')) 337262706Serwin { 338262706Serwin char timestr[15]; 339262706Serwin 340262706Serwin strlcpy(timestr, str, sizeof(timestr)); 341262706Serwin timestr[n] = 0; 342262706Serwin if (n == 8) 343262706Serwin strlcat(timestr, "000000", sizeof(timestr)); 344262706Serwin result = dns_time64_fromtext(timestr, &val); 345262706Serwin if (result != ISC_R_SUCCESS) 346262706Serwin fatal("time value %s is invalid: %s", orig, 347262706Serwin isc_result_totext(result)); 348262706Serwin base = val; 349262706Serwin str += n; 350262706Serwin } else if (strncmp(str, "now", 3) == 0) { 351224092Sdougb base = now; 352224092Sdougb str += 3; 353224092Sdougb } 354224092Sdougb 355224092Sdougb if (str[0] == '\0') 356224092Sdougb return ((isc_stdtime_t) base); 357224092Sdougb else if (str[0] == '+') { 358135446Strhodes offset = strtol(str + 1, &endp, 0); 359224092Sdougb offset = time_units((isc_stdtime_t) offset, endp, orig); 360135446Strhodes val = base + offset; 361224092Sdougb } else if (str[0] == '-') { 362224092Sdougb offset = strtol(str + 1, &endp, 0); 363224092Sdougb offset = time_units((isc_stdtime_t) offset, endp, orig); 364224092Sdougb val = base - offset; 365262706Serwin } else 366224092Sdougb fatal("time value %s is invalid", orig); 367135446Strhodes 368135446Strhodes return ((isc_stdtime_t) val); 369135446Strhodes} 370135446Strhodes 371135446Strhodesdns_rdataclass_t 372135446Strhodesstrtoclass(const char *str) { 373135446Strhodes isc_textregion_t r; 374135446Strhodes dns_rdataclass_t rdclass; 375135446Strhodes isc_result_t ret; 376135446Strhodes 377135446Strhodes if (str == NULL) 378135446Strhodes return dns_rdataclass_in; 379135446Strhodes DE_CONST(str, r.base); 380135446Strhodes r.length = strlen(str); 381135446Strhodes ret = dns_rdataclass_fromtext(&rdclass, &r); 382135446Strhodes if (ret != ISC_R_SUCCESS) 383135446Strhodes fatal("unknown class %s", str); 384135446Strhodes return (rdclass); 385135446Strhodes} 386224092Sdougb 387224092Sdougbisc_result_t 388224092Sdougbtry_dir(const char *dirname) { 389224092Sdougb isc_result_t result; 390224092Sdougb isc_dir_t d; 391224092Sdougb 392224092Sdougb isc_dir_init(&d); 393224092Sdougb result = isc_dir_open(&d, dirname); 394224092Sdougb if (result == ISC_R_SUCCESS) { 395224092Sdougb isc_dir_close(&d); 396224092Sdougb } 397224092Sdougb return (result); 398224092Sdougb} 399224092Sdougb 400224092Sdougb/* 401224092Sdougb * Check private key version compatibility. 402224092Sdougb */ 403224092Sdougbvoid 404224092Sdougbcheck_keyversion(dst_key_t *key, char *keystr) { 405224092Sdougb int major, minor; 406224092Sdougb dst_key_getprivateformat(key, &major, &minor); 407224092Sdougb INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */ 408224092Sdougb 409224092Sdougb if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) 410224092Sdougb fatal("Key %s has incompatible format version %d.%d, " 411224092Sdougb "use -f to force upgrade to new version.", 412224092Sdougb keystr, major, minor); 413224092Sdougb if (minor > DST_MINOR_VERSION) 414224092Sdougb fatal("Key %s has incompatible format version %d.%d, " 415224092Sdougb "use -f to force downgrade to current version.", 416224092Sdougb keystr, major, minor); 417224092Sdougb} 418224092Sdougb 419224092Sdougbvoid 420224092Sdougbset_keyversion(dst_key_t *key) { 421224092Sdougb int major, minor; 422224092Sdougb dst_key_getprivateformat(key, &major, &minor); 423224092Sdougb INSIST(major <= DST_MAJOR_VERSION); 424224092Sdougb 425224092Sdougb if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) 426224092Sdougb dst_key_setprivateformat(key, DST_MAJOR_VERSION, 427224092Sdougb DST_MINOR_VERSION); 428224092Sdougb 429224092Sdougb /* 430224092Sdougb * If the key is from a version older than 1.3, set 431224092Sdougb * set the creation date 432224092Sdougb */ 433224092Sdougb if (major < 1 || (major == 1 && minor <= 2)) { 434224092Sdougb isc_stdtime_t now; 435224092Sdougb isc_stdtime_get(&now); 436224092Sdougb dst_key_settime(key, DST_TIME_CREATED, now); 437224092Sdougb } 438224092Sdougb} 439224092Sdougb 440224092Sdougbisc_boolean_t 441234010Sdougbkey_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir, 442234010Sdougb isc_mem_t *mctx, isc_boolean_t *exact) 443224092Sdougb{ 444224092Sdougb isc_result_t result; 445224092Sdougb isc_boolean_t conflict = ISC_FALSE; 446224092Sdougb dns_dnsseckeylist_t matchkeys; 447224092Sdougb dns_dnsseckey_t *key = NULL; 448234010Sdougb isc_uint16_t id, oldid; 449234010Sdougb isc_uint32_t rid, roldid; 450234010Sdougb dns_secalg_t alg; 451224092Sdougb 452224092Sdougb if (exact != NULL) 453224092Sdougb *exact = ISC_FALSE; 454224092Sdougb 455234010Sdougb id = dst_key_id(dstkey); 456234010Sdougb rid = dst_key_rid(dstkey); 457234010Sdougb alg = dst_key_alg(dstkey); 458234010Sdougb 459224092Sdougb ISC_LIST_INIT(matchkeys); 460224092Sdougb result = dns_dnssec_findmatchingkeys(name, dir, mctx, &matchkeys); 461224092Sdougb if (result == ISC_R_NOTFOUND) 462224092Sdougb return (ISC_FALSE); 463224092Sdougb 464224092Sdougb while (!ISC_LIST_EMPTY(matchkeys) && !conflict) { 465224092Sdougb key = ISC_LIST_HEAD(matchkeys); 466224092Sdougb if (dst_key_alg(key->key) != alg) 467224092Sdougb goto next; 468224092Sdougb 469224092Sdougb oldid = dst_key_id(key->key); 470234010Sdougb roldid = dst_key_rid(key->key); 471234010Sdougb 472234010Sdougb if (oldid == rid || roldid == id || id == oldid) { 473224092Sdougb conflict = ISC_TRUE; 474234010Sdougb if (id != oldid) { 475224092Sdougb if (verbose > 1) 476224092Sdougb fprintf(stderr, "Key ID %d could " 477224092Sdougb "collide with %d\n", 478224092Sdougb id, oldid); 479224092Sdougb } else { 480224092Sdougb if (exact != NULL) 481224092Sdougb *exact = ISC_TRUE; 482224092Sdougb if (verbose > 1) 483224092Sdougb fprintf(stderr, "Key ID %d exists\n", 484224092Sdougb id); 485224092Sdougb } 486224092Sdougb } 487224092Sdougb 488224092Sdougb next: 489224092Sdougb ISC_LIST_UNLINK(matchkeys, key, link); 490224092Sdougb dns_dnsseckey_destroy(mctx, &key); 491224092Sdougb } 492224092Sdougb 493224092Sdougb /* Finish freeing the list */ 494224092Sdougb while (!ISC_LIST_EMPTY(matchkeys)) { 495224092Sdougb key = ISC_LIST_HEAD(matchkeys); 496224092Sdougb ISC_LIST_UNLINK(matchkeys, key, link); 497224092Sdougb dns_dnsseckey_destroy(mctx, &key); 498224092Sdougb } 499224092Sdougb 500224092Sdougb return (conflict); 501224092Sdougb} 502254897Serwin 503254897Serwinisc_boolean_t 504254897Serwinis_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 505254897Serwin dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) 506254897Serwin{ 507254897Serwin dns_rdataset_t nsset; 508254897Serwin isc_result_t result; 509254897Serwin 510254897Serwin if (dns_name_equal(name, origin)) 511254897Serwin return (ISC_FALSE); 512254897Serwin 513254897Serwin dns_rdataset_init(&nsset); 514254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns, 515254897Serwin 0, 0, &nsset, NULL); 516254897Serwin if (dns_rdataset_isassociated(&nsset)) { 517254897Serwin if (ttlp != NULL) 518254897Serwin *ttlp = nsset.ttl; 519254897Serwin dns_rdataset_disassociate(&nsset); 520254897Serwin } 521254897Serwin 522254897Serwin return (ISC_TF(result == ISC_R_SUCCESS)); 523254897Serwin} 524254897Serwin 525254897Serwinstatic isc_boolean_t 526254897Serwingoodsig(dns_name_t *origin, dns_rdata_t *sigrdata, dns_name_t *name, 527254897Serwin dns_rdataset_t *keyrdataset, dns_rdataset_t *rdataset, isc_mem_t *mctx) 528254897Serwin{ 529254897Serwin dns_rdata_dnskey_t key; 530254897Serwin dns_rdata_rrsig_t sig; 531254897Serwin dst_key_t *dstkey = NULL; 532254897Serwin isc_result_t result; 533254897Serwin 534254897Serwin result = dns_rdata_tostruct(sigrdata, &sig, NULL); 535254897Serwin check_result(result, "dns_rdata_tostruct()"); 536254897Serwin 537254897Serwin for (result = dns_rdataset_first(keyrdataset); 538254897Serwin result == ISC_R_SUCCESS; 539254897Serwin result = dns_rdataset_next(keyrdataset)) { 540254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 541254897Serwin dns_rdataset_current(keyrdataset, &rdata); 542254897Serwin result = dns_rdata_tostruct(&rdata, &key, NULL); 543254897Serwin check_result(result, "dns_rdata_tostruct()"); 544254897Serwin result = dns_dnssec_keyfromrdata(origin, &rdata, mctx, 545254897Serwin &dstkey); 546254897Serwin if (result != ISC_R_SUCCESS) 547254897Serwin return (ISC_FALSE); 548254897Serwin if (sig.algorithm != key.algorithm || 549254897Serwin sig.keyid != dst_key_id(dstkey) || 550254897Serwin !dns_name_equal(&sig.signer, origin)) { 551254897Serwin dst_key_free(&dstkey); 552254897Serwin continue; 553254897Serwin } 554254897Serwin result = dns_dnssec_verify(name, rdataset, dstkey, ISC_FALSE, 555254897Serwin mctx, sigrdata); 556254897Serwin dst_key_free(&dstkey); 557254897Serwin if (result == ISC_R_SUCCESS) 558254897Serwin return(ISC_TRUE); 559254897Serwin } 560254897Serwin return (ISC_FALSE); 561254897Serwin} 562254897Serwin 563254897Serwinstatic isc_result_t 564254897Serwinverifynsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 565254897Serwin dns_dbnode_t *node, dns_name_t *nextname) 566254897Serwin{ 567254897Serwin unsigned char buffer[DNS_NSEC_BUFFERSIZE]; 568254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 569254897Serwin char nextbuf[DNS_NAME_FORMATSIZE]; 570254897Serwin char found[DNS_NAME_FORMATSIZE]; 571254897Serwin dns_rdataset_t rdataset; 572254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 573254897Serwin dns_rdata_t tmprdata = DNS_RDATA_INIT; 574254897Serwin dns_rdata_nsec_t nsec; 575254897Serwin isc_result_t result; 576254897Serwin 577254897Serwin dns_rdataset_init(&rdataset); 578254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 579254897Serwin 0, 0, &rdataset, NULL); 580254897Serwin if (result != ISC_R_SUCCESS) { 581254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 582254897Serwin fprintf(stderr, "Missing NSEC record for %s\n", namebuf); 583254897Serwin goto failure; 584254897Serwin } 585254897Serwin 586254897Serwin result = dns_rdataset_first(&rdataset); 587254897Serwin check_result(result, "dns_rdataset_first()"); 588254897Serwin 589254897Serwin dns_rdataset_current(&rdataset, &rdata); 590254897Serwin result = dns_rdata_tostruct(&rdata, &nsec, NULL); 591254897Serwin check_result(result, "dns_rdata_tostruct()"); 592254897Serwin /* Check bit next name is consistent */ 593254897Serwin if (!dns_name_equal(&nsec.next, nextname)) { 594254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 595254897Serwin dns_name_format(nextname, nextbuf, sizeof(nextbuf)); 596254897Serwin dns_name_format(&nsec.next, found, sizeof(found)); 597254897Serwin fprintf(stderr, "Bad NSEC record for %s, next name " 598254897Serwin "mismatch (expected:%s, found:%s)\n", namebuf, 599254897Serwin nextbuf, found); 600254897Serwin goto failure; 601254897Serwin } 602254897Serwin /* Check bit map is consistent */ 603254897Serwin result = dns_nsec_buildrdata(db, ver, node, nextname, buffer, 604254897Serwin &tmprdata); 605254897Serwin check_result(result, "dns_nsec_buildrdata()"); 606254897Serwin if (dns_rdata_compare(&rdata, &tmprdata) != 0) { 607254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 608254897Serwin fprintf(stderr, "Bad NSEC record for %s, bit map " 609254897Serwin "mismatch\n", namebuf); 610254897Serwin goto failure; 611254897Serwin } 612254897Serwin result = dns_rdataset_next(&rdataset); 613254897Serwin if (result != ISC_R_NOMORE) { 614254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 615254897Serwin fprintf(stderr, "Multipe NSEC records for %s\n", namebuf); 616254897Serwin goto failure; 617254897Serwin 618254897Serwin } 619254897Serwin dns_rdataset_disassociate(&rdataset); 620254897Serwin return (ISC_R_SUCCESS); 621254897Serwin failure: 622254897Serwin if (dns_rdataset_isassociated(&rdataset)) 623254897Serwin dns_rdataset_disassociate(&rdataset); 624254897Serwin return (ISC_R_FAILURE); 625254897Serwin} 626254897Serwin 627254897Serwinstatic void 628254897Serwincheck_no_rrsig(dns_db_t *db, dns_dbversion_t *ver, dns_rdataset_t *rdataset, 629254897Serwin dns_name_t *name, dns_dbnode_t *node) 630254897Serwin{ 631254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 632254897Serwin char typebuf[80]; 633254897Serwin dns_rdataset_t sigrdataset; 634254897Serwin dns_rdatasetiter_t *rdsiter = NULL; 635254897Serwin isc_result_t result; 636254897Serwin 637254897Serwin dns_rdataset_init(&sigrdataset); 638254897Serwin result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 639254897Serwin check_result(result, "dns_db_allrdatasets()"); 640254897Serwin for (result = dns_rdatasetiter_first(rdsiter); 641254897Serwin result == ISC_R_SUCCESS; 642254897Serwin result = dns_rdatasetiter_next(rdsiter)) { 643254897Serwin dns_rdatasetiter_current(rdsiter, &sigrdataset); 644254897Serwin if (sigrdataset.type == dns_rdatatype_rrsig && 645254897Serwin sigrdataset.covers == rdataset->type) 646254897Serwin break; 647254897Serwin dns_rdataset_disassociate(&sigrdataset); 648254897Serwin } 649254897Serwin if (result == ISC_R_SUCCESS) { 650254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 651254897Serwin type_format(rdataset->type, typebuf, sizeof(typebuf)); 652254897Serwin fprintf(stderr, "Warning: Found unexpected signatures for " 653254897Serwin "%s/%s\n", namebuf, typebuf); 654254897Serwin } 655254897Serwin if (dns_rdataset_isassociated(&sigrdataset)) 656254897Serwin dns_rdataset_disassociate(&sigrdataset); 657254897Serwin dns_rdatasetiter_destroy(&rdsiter); 658254897Serwin} 659254897Serwin 660254897Serwinstatic isc_boolean_t 661254897Serwinchain_compare(void *arg1, void *arg2) { 662254897Serwin struct nsec3_chain_fixed *e1 = arg1, *e2 = arg2; 663254897Serwin size_t len; 664254897Serwin 665254897Serwin /* 666254897Serwin * Do each element in turn to get a stable sort. 667254897Serwin */ 668254897Serwin if (e1->hash < e2->hash) 669254897Serwin return (ISC_TRUE); 670254897Serwin if (e1->hash > e2->hash) 671254897Serwin return (ISC_FALSE); 672254897Serwin if (e1->iterations < e2->iterations) 673254897Serwin return (ISC_TRUE); 674254897Serwin if (e1->iterations > e2->iterations) 675254897Serwin return (ISC_FALSE); 676254897Serwin if (e1->salt_length < e2->salt_length) 677254897Serwin return (ISC_TRUE); 678254897Serwin if (e1->salt_length > e2->salt_length) 679254897Serwin return (ISC_FALSE); 680254897Serwin if (e1->next_length < e2->next_length) 681254897Serwin return (ISC_TRUE); 682254897Serwin if (e1->next_length > e2->next_length) 683254897Serwin return (ISC_FALSE); 684254897Serwin len = e1->salt_length + 2 * e1->next_length; 685254897Serwin if (memcmp(e1 + 1, e2 + 1, len) < 0) 686254897Serwin return (ISC_TRUE); 687254897Serwin return (ISC_FALSE); 688254897Serwin} 689254897Serwin 690254897Serwinstatic isc_boolean_t 691254897Serwinchain_equal(struct nsec3_chain_fixed *e1, struct nsec3_chain_fixed *e2) { 692254897Serwin size_t len; 693254897Serwin 694254897Serwin if (e1->hash != e2->hash) 695254897Serwin return (ISC_FALSE); 696254897Serwin if (e1->iterations != e2->iterations) 697254897Serwin return (ISC_FALSE); 698254897Serwin if (e1->salt_length != e2->salt_length) 699254897Serwin return (ISC_FALSE); 700254897Serwin if (e1->next_length != e2->next_length) 701254897Serwin return (ISC_FALSE); 702254897Serwin len = e1->salt_length + 2 * e1->next_length; 703254897Serwin if (memcmp(e1 + 1, e2 + 1, len) != 0) 704254897Serwin return (ISC_FALSE); 705254897Serwin return (ISC_TRUE); 706254897Serwin} 707254897Serwin 708254897Serwinstatic isc_result_t 709254897Serwinrecord_nsec3(const unsigned char *rawhash, const dns_rdata_nsec3_t *nsec3, 710254897Serwin isc_mem_t *mctx, isc_heap_t *chains) 711254897Serwin{ 712254897Serwin struct nsec3_chain_fixed *element; 713254897Serwin size_t len; 714254897Serwin unsigned char *cp; 715254897Serwin isc_result_t result; 716254897Serwin 717254897Serwin len = sizeof(*element) + nsec3->next_length * 2 + nsec3->salt_length; 718254897Serwin 719254897Serwin element = isc_mem_get(mctx, len); 720254897Serwin if (element == NULL) 721254897Serwin return (ISC_R_NOMEMORY); 722254897Serwin memset(element, 0, len); 723254897Serwin element->hash = nsec3->hash; 724254897Serwin element->salt_length = nsec3->salt_length; 725254897Serwin element->next_length = nsec3->next_length; 726254897Serwin element->iterations = nsec3->iterations; 727254897Serwin cp = (unsigned char *)(element + 1); 728262706Serwin memmove(cp, nsec3->salt, nsec3->salt_length); 729254897Serwin cp += nsec3->salt_length; 730262706Serwin memmove(cp, rawhash, nsec3->next_length); 731254897Serwin cp += nsec3->next_length; 732262706Serwin memmove(cp, nsec3->next, nsec3->next_length); 733254897Serwin result = isc_heap_insert(chains, element); 734254897Serwin if (result != ISC_R_SUCCESS) { 735254897Serwin fprintf(stderr, "isc_heap_insert failed: %s\n", 736254897Serwin isc_result_totext(result)); 737254897Serwin isc_mem_put(mctx, element, len); 738254897Serwin } 739254897Serwin return (result); 740254897Serwin} 741254897Serwin 742254897Serwinstatic isc_result_t 743254897Serwinmatch_nsec3(dns_name_t *name, isc_mem_t *mctx, 744254897Serwin dns_rdata_nsec3param_t *nsec3param, dns_rdataset_t *rdataset, 745254897Serwin unsigned char types[8192], unsigned int maxtype, 746254897Serwin unsigned char *rawhash, size_t rhsize) 747254897Serwin{ 748254897Serwin unsigned char cbm[8244]; 749254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 750254897Serwin dns_rdata_nsec3_t nsec3; 751254897Serwin isc_result_t result; 752254897Serwin unsigned int len; 753254897Serwin 754254897Serwin /* 755254897Serwin * Find matching NSEC3 record. 756254897Serwin */ 757254897Serwin for (result = dns_rdataset_first(rdataset); 758254897Serwin result == ISC_R_SUCCESS; 759254897Serwin result = dns_rdataset_next(rdataset)) { 760254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 761254897Serwin dns_rdataset_current(rdataset, &rdata); 762254897Serwin result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 763254897Serwin check_result(result, "dns_rdata_tostruct()"); 764254897Serwin if (nsec3.hash == nsec3param->hash && 765254897Serwin nsec3.next_length == rhsize && 766254897Serwin nsec3.iterations == nsec3param->iterations && 767254897Serwin nsec3.salt_length == nsec3param->salt_length && 768254897Serwin memcmp(nsec3.salt, nsec3param->salt, 769254897Serwin nsec3param->salt_length) == 0) 770254897Serwin break; 771254897Serwin } 772254897Serwin if (result != ISC_R_SUCCESS) { 773254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 774254897Serwin fprintf(stderr, "Missing NSEC3 record for %s\n", namebuf); 775254897Serwin return (result); 776254897Serwin } 777254897Serwin 778254897Serwin /* 779254897Serwin * Check the type list. 780254897Serwin */ 781254897Serwin len = dns_nsec_compressbitmap(cbm, types, maxtype); 782254897Serwin if (nsec3.len != len || memcmp(cbm, nsec3.typebits, len) != 0) { 783254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 784254897Serwin fprintf(stderr, "Bad NSEC3 record for %s, bit map " 785254897Serwin "mismatch\n", namebuf); 786254897Serwin return (ISC_R_FAILURE); 787254897Serwin } 788254897Serwin 789254897Serwin /* 790254897Serwin * Record chain. 791254897Serwin */ 792254897Serwin result = record_nsec3(rawhash, &nsec3, mctx, expected_chains); 793254897Serwin check_result(result, "record_nsec3()"); 794254897Serwin 795254897Serwin /* 796254897Serwin * Make sure there is only one NSEC3 record with this set of 797254897Serwin * parameters. 798254897Serwin */ 799254897Serwin for (result = dns_rdataset_next(rdataset); 800254897Serwin result == ISC_R_SUCCESS; 801254897Serwin result = dns_rdataset_next(rdataset)) { 802254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 803254897Serwin dns_rdataset_current(rdataset, &rdata); 804254897Serwin result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 805254897Serwin check_result(result, "dns_rdata_tostruct()"); 806254897Serwin if (nsec3.hash == nsec3param->hash && 807254897Serwin nsec3.iterations == nsec3param->iterations && 808254897Serwin nsec3.salt_length == nsec3param->salt_length && 809254897Serwin memcmp(nsec3.salt, nsec3param->salt, 810254897Serwin nsec3.salt_length) == 0) { 811254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 812254897Serwin fprintf(stderr, "Multiple NSEC3 records with the " 813254897Serwin "same parameter set for %s", namebuf); 814254897Serwin result = DNS_R_DUPLICATE; 815254897Serwin break; 816254897Serwin } 817254897Serwin } 818254897Serwin if (result != ISC_R_NOMORE) 819254897Serwin return (result); 820254897Serwin 821254897Serwin result = ISC_R_SUCCESS; 822254897Serwin return (result); 823254897Serwin} 824254897Serwin 825254897Serwinstatic isc_boolean_t 826254897Serwininnsec3params(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *nsec3paramset) { 827254897Serwin dns_rdata_nsec3param_t nsec3param; 828254897Serwin isc_result_t result; 829254897Serwin 830254897Serwin for (result = dns_rdataset_first(nsec3paramset); 831254897Serwin result == ISC_R_SUCCESS; 832254897Serwin result = dns_rdataset_next(nsec3paramset)) { 833254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 834254897Serwin 835254897Serwin dns_rdataset_current(nsec3paramset, &rdata); 836254897Serwin result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); 837254897Serwin check_result(result, "dns_rdata_tostruct()"); 838254897Serwin if (nsec3param.flags == 0 && 839254897Serwin nsec3param.hash == nsec3->hash && 840254897Serwin nsec3param.iterations == nsec3->iterations && 841254897Serwin nsec3param.salt_length == nsec3->salt_length && 842254897Serwin memcmp(nsec3param.salt, nsec3->salt, 843254897Serwin nsec3->salt_length) == 0) 844254897Serwin return (ISC_TRUE); 845254897Serwin } 846254897Serwin return (ISC_FALSE); 847254897Serwin} 848254897Serwin 849254897Serwinstatic isc_result_t 850254897Serwinrecord_found(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, 851254897Serwin dns_name_t *name, dns_dbnode_t *node, 852254897Serwin dns_rdataset_t *nsec3paramset) 853254897Serwin{ 854254897Serwin unsigned char owner[NSEC3_MAX_HASH_LENGTH]; 855254897Serwin dns_rdata_nsec3_t nsec3; 856254897Serwin dns_rdataset_t rdataset; 857254897Serwin dns_label_t hashlabel; 858254897Serwin isc_buffer_t b; 859254897Serwin isc_result_t result; 860254897Serwin 861254897Serwin if (nsec3paramset == NULL || !dns_rdataset_isassociated(nsec3paramset)) 862254897Serwin return (ISC_R_SUCCESS); 863254897Serwin 864254897Serwin dns_rdataset_init(&rdataset); 865254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 866254897Serwin 0, 0, &rdataset, NULL); 867254897Serwin if (result != ISC_R_SUCCESS) 868254897Serwin return (ISC_R_SUCCESS); 869254897Serwin 870254897Serwin dns_name_getlabel(name, 0, &hashlabel); 871254897Serwin isc_region_consume(&hashlabel, 1); 872254897Serwin isc_buffer_init(&b, owner, sizeof(owner)); 873254897Serwin result = isc_base32hex_decoderegion(&hashlabel, &b); 874254897Serwin if (result != ISC_R_SUCCESS) 875254897Serwin goto cleanup; 876254897Serwin 877254897Serwin for (result = dns_rdataset_first(&rdataset); 878254897Serwin result == ISC_R_SUCCESS; 879254897Serwin result = dns_rdataset_next(&rdataset)) { 880254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 881254897Serwin dns_rdataset_current(&rdataset, &rdata); 882254897Serwin result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 883254897Serwin check_result(result, "dns_rdata_tostruct()"); 884254897Serwin if (nsec3.next_length != isc_buffer_usedlength(&b)) 885254897Serwin continue; 886254897Serwin /* 887254897Serwin * We only care about NSEC3 records that match a NSEC3PARAM 888254897Serwin * record. 889254897Serwin */ 890254897Serwin if (!innsec3params(&nsec3, nsec3paramset)) 891254897Serwin continue; 892254897Serwin 893254897Serwin /* 894254897Serwin * Record chain. 895254897Serwin */ 896254897Serwin result = record_nsec3(owner, &nsec3, mctx, found_chains); 897254897Serwin check_result(result, "record_nsec3()"); 898254897Serwin } 899254897Serwin 900254897Serwin cleanup: 901254897Serwin dns_rdataset_disassociate(&rdataset); 902254897Serwin return (ISC_R_SUCCESS); 903254897Serwin} 904254897Serwin 905254897Serwinstatic isc_boolean_t 906254897Serwinisoptout(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 907254897Serwin dns_rdata_t *nsec3rdata) 908254897Serwin{ 909254897Serwin dns_rdataset_t rdataset; 910254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 911254897Serwin dns_rdata_nsec3_t nsec3; 912254897Serwin dns_rdata_nsec3param_t nsec3param; 913254897Serwin dns_fixedname_t fixed; 914254897Serwin dns_name_t *hashname; 915254897Serwin isc_result_t result; 916254897Serwin dns_dbnode_t *node = NULL; 917254897Serwin unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; 918254897Serwin size_t rhsize = sizeof(rawhash); 919254897Serwin isc_boolean_t ret; 920254897Serwin 921254897Serwin result = dns_rdata_tostruct(nsec3rdata, &nsec3param, NULL); 922254897Serwin check_result(result, "dns_rdata_tostruct()"); 923254897Serwin 924254897Serwin dns_fixedname_init(&fixed); 925254897Serwin result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, origin, origin, 926254897Serwin nsec3param.hash, nsec3param.iterations, 927254897Serwin nsec3param.salt, nsec3param.salt_length); 928254897Serwin check_result(result, "dns_nsec3_hashname()"); 929254897Serwin 930254897Serwin dns_rdataset_init(&rdataset); 931254897Serwin hashname = dns_fixedname_name(&fixed); 932254897Serwin result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node); 933254897Serwin if (result == ISC_R_SUCCESS) 934254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 935254897Serwin 0, 0, &rdataset, NULL); 936254897Serwin if (result != ISC_R_SUCCESS) 937254897Serwin return (ISC_FALSE); 938254897Serwin 939254897Serwin result = dns_rdataset_first(&rdataset); 940254897Serwin check_result(result, "dns_rdataset_first()"); 941254897Serwin 942254897Serwin dns_rdataset_current(&rdataset, &rdata); 943254897Serwin 944254897Serwin result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 945254897Serwin if (result != ISC_R_SUCCESS) 946254897Serwin ret = ISC_FALSE; 947254897Serwin else 948254897Serwin ret = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0); 949254897Serwin 950254897Serwin if (dns_rdataset_isassociated(&rdataset)) 951254897Serwin dns_rdataset_disassociate(&rdataset); 952254897Serwin if (node != NULL) 953254897Serwin dns_db_detachnode(db, &node); 954254897Serwin 955254897Serwin return (ret); 956254897Serwin} 957254897Serwin 958254897Serwinstatic isc_result_t 959254897Serwinverifynsec3(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 960254897Serwin isc_mem_t *mctx, dns_name_t *name, dns_rdata_t *rdata, 961254897Serwin isc_boolean_t delegation, isc_boolean_t empty, 962254897Serwin unsigned char types[8192], unsigned int maxtype) 963254897Serwin{ 964254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 965254897Serwin char hashbuf[DNS_NAME_FORMATSIZE]; 966254897Serwin dns_rdataset_t rdataset; 967254897Serwin dns_rdata_nsec3param_t nsec3param; 968254897Serwin dns_fixedname_t fixed; 969254897Serwin dns_name_t *hashname; 970254897Serwin isc_result_t result; 971254897Serwin dns_dbnode_t *node = NULL; 972254897Serwin unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; 973254897Serwin size_t rhsize = sizeof(rawhash); 974254897Serwin isc_boolean_t optout; 975254897Serwin 976254897Serwin result = dns_rdata_tostruct(rdata, &nsec3param, NULL); 977254897Serwin check_result(result, "dns_rdata_tostruct()"); 978254897Serwin 979254897Serwin if (nsec3param.flags != 0) 980254897Serwin return (ISC_R_SUCCESS); 981254897Serwin 982254897Serwin if (!dns_nsec3_supportedhash(nsec3param.hash)) 983254897Serwin return (ISC_R_SUCCESS); 984254897Serwin 985254897Serwin optout = isoptout(db, ver, origin, rdata); 986254897Serwin 987254897Serwin dns_fixedname_init(&fixed); 988254897Serwin result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, name, origin, 989254897Serwin nsec3param.hash, nsec3param.iterations, 990254897Serwin nsec3param.salt, nsec3param.salt_length); 991254897Serwin check_result(result, "dns_nsec3_hashname()"); 992254897Serwin 993254897Serwin /* 994254897Serwin * We don't use dns_db_find() here as it works with the choosen 995254897Serwin * nsec3 chain and we may also be called with uncommitted data 996254897Serwin * from dnssec-signzone so the secure status of the zone may not 997254897Serwin * be up to date. 998254897Serwin */ 999254897Serwin dns_rdataset_init(&rdataset); 1000254897Serwin hashname = dns_fixedname_name(&fixed); 1001254897Serwin result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node); 1002254897Serwin if (result == ISC_R_SUCCESS) 1003254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 1004254897Serwin 0, 0, &rdataset, NULL); 1005254897Serwin if (result != ISC_R_SUCCESS && 1006254897Serwin (!delegation || (empty && !optout) || 1007254897Serwin (!empty && dns_nsec_isset(types, dns_rdatatype_ds)))) 1008254897Serwin { 1009254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 1010254897Serwin dns_name_format(hashname, hashbuf, sizeof(hashbuf)); 1011254897Serwin fprintf(stderr, "Missing NSEC3 record for %s (%s)\n", 1012254897Serwin namebuf, hashbuf); 1013254897Serwin } else if (result == ISC_R_NOTFOUND && 1014254897Serwin delegation && (!empty || optout)) 1015254897Serwin { 1016254897Serwin result = ISC_R_SUCCESS; 1017254897Serwin } else if (result == ISC_R_SUCCESS) { 1018254897Serwin result = match_nsec3(name, mctx, &nsec3param, &rdataset, 1019254897Serwin types, maxtype, rawhash, rhsize); 1020254897Serwin } 1021254897Serwin 1022254897Serwin if (dns_rdataset_isassociated(&rdataset)) 1023254897Serwin dns_rdataset_disassociate(&rdataset); 1024254897Serwin if (node != NULL) 1025254897Serwin dns_db_detachnode(db, &node); 1026254897Serwin 1027254897Serwin return (result); 1028254897Serwin} 1029254897Serwin 1030254897Serwinstatic isc_result_t 1031254897Serwinverifynsec3s(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1032254897Serwin isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *nsec3paramset, 1033254897Serwin isc_boolean_t delegation, isc_boolean_t empty, 1034254897Serwin unsigned char types[8192], unsigned int maxtype) 1035254897Serwin{ 1036254897Serwin isc_result_t result; 1037254897Serwin 1038254897Serwin for (result = dns_rdataset_first(nsec3paramset); 1039254897Serwin result == ISC_R_SUCCESS; 1040254897Serwin result = dns_rdataset_next(nsec3paramset)) { 1041254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 1042254897Serwin 1043254897Serwin dns_rdataset_current(nsec3paramset, &rdata); 1044254897Serwin result = verifynsec3(db, ver, origin, mctx, name, &rdata, 1045254897Serwin delegation, empty, types, maxtype); 1046254897Serwin if (result != ISC_R_SUCCESS) 1047254897Serwin break; 1048254897Serwin } 1049254897Serwin if (result == ISC_R_NOMORE) 1050254897Serwin result = ISC_R_SUCCESS; 1051254897Serwin return (result); 1052254897Serwin} 1053254897Serwin 1054254897Serwinstatic void 1055254897Serwinverifyset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1056254897Serwin isc_mem_t *mctx, dns_rdataset_t *rdataset, dns_name_t *name, 1057254897Serwin dns_dbnode_t *node, dns_rdataset_t *keyrdataset, 1058254897Serwin unsigned char *act_algorithms, unsigned char *bad_algorithms) 1059254897Serwin{ 1060254897Serwin unsigned char set_algorithms[256]; 1061254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 1062254897Serwin char algbuf[80]; 1063254897Serwin char typebuf[80]; 1064254897Serwin dns_rdataset_t sigrdataset; 1065254897Serwin dns_rdatasetiter_t *rdsiter = NULL; 1066254897Serwin isc_result_t result; 1067254897Serwin int i; 1068254897Serwin 1069254897Serwin dns_rdataset_init(&sigrdataset); 1070254897Serwin result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1071254897Serwin check_result(result, "dns_db_allrdatasets()"); 1072254897Serwin for (result = dns_rdatasetiter_first(rdsiter); 1073254897Serwin result == ISC_R_SUCCESS; 1074254897Serwin result = dns_rdatasetiter_next(rdsiter)) { 1075254897Serwin dns_rdatasetiter_current(rdsiter, &sigrdataset); 1076254897Serwin if (sigrdataset.type == dns_rdatatype_rrsig && 1077254897Serwin sigrdataset.covers == rdataset->type) 1078254897Serwin break; 1079254897Serwin dns_rdataset_disassociate(&sigrdataset); 1080254897Serwin } 1081254897Serwin if (result != ISC_R_SUCCESS) { 1082254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 1083254897Serwin type_format(rdataset->type, typebuf, sizeof(typebuf)); 1084254897Serwin fprintf(stderr, "No signatures for %s/%s\n", namebuf, typebuf); 1085254897Serwin for (i = 0; i < 256; i++) 1086254897Serwin if (act_algorithms[i] != 0) 1087254897Serwin bad_algorithms[i] = 1; 1088254897Serwin dns_rdatasetiter_destroy(&rdsiter); 1089254897Serwin return; 1090254897Serwin } 1091254897Serwin 1092254897Serwin memset(set_algorithms, 0, sizeof(set_algorithms)); 1093254897Serwin for (result = dns_rdataset_first(&sigrdataset); 1094254897Serwin result == ISC_R_SUCCESS; 1095254897Serwin result = dns_rdataset_next(&sigrdataset)) { 1096254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 1097254897Serwin dns_rdata_rrsig_t sig; 1098254897Serwin 1099254897Serwin dns_rdataset_current(&sigrdataset, &rdata); 1100254897Serwin result = dns_rdata_tostruct(&rdata, &sig, NULL); 1101254897Serwin check_result(result, "dns_rdata_tostruct()"); 1102254897Serwin if (rdataset->ttl != sig.originalttl) { 1103254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 1104254897Serwin type_format(rdataset->type, typebuf, sizeof(typebuf)); 1105254897Serwin fprintf(stderr, "TTL mismatch for %s %s keytag %u\n", 1106254897Serwin namebuf, typebuf, sig.keyid); 1107254897Serwin continue; 1108254897Serwin } 1109254897Serwin if ((set_algorithms[sig.algorithm] != 0) || 1110254897Serwin (act_algorithms[sig.algorithm] == 0)) 1111254897Serwin continue; 1112254897Serwin if (goodsig(origin, &rdata, name, keyrdataset, rdataset, mctx)) 1113254897Serwin set_algorithms[sig.algorithm] = 1; 1114254897Serwin } 1115254897Serwin dns_rdatasetiter_destroy(&rdsiter); 1116254897Serwin if (memcmp(set_algorithms, act_algorithms, sizeof(set_algorithms))) { 1117254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 1118254897Serwin type_format(rdataset->type, typebuf, sizeof(typebuf)); 1119254897Serwin for (i = 0; i < 256; i++) 1120254897Serwin if ((act_algorithms[i] != 0) && 1121254897Serwin (set_algorithms[i] == 0)) { 1122254897Serwin dns_secalg_format(i, algbuf, sizeof(algbuf)); 1123254897Serwin fprintf(stderr, "No correct %s signature for " 1124254897Serwin "%s %s\n", algbuf, namebuf, typebuf); 1125254897Serwin bad_algorithms[i] = 1; 1126254897Serwin } 1127254897Serwin } 1128254897Serwin dns_rdataset_disassociate(&sigrdataset); 1129254897Serwin} 1130254897Serwin 1131254897Serwinstatic isc_result_t 1132254897Serwinverifynode(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1133254897Serwin isc_mem_t *mctx, dns_name_t *name, dns_dbnode_t *node, 1134254897Serwin isc_boolean_t delegation, dns_rdataset_t *keyrdataset, 1135254897Serwin unsigned char *act_algorithms, unsigned char *bad_algorithms, 1136254897Serwin dns_rdataset_t *nsecset, dns_rdataset_t *nsec3paramset, 1137254897Serwin dns_name_t *nextname) 1138254897Serwin{ 1139254897Serwin unsigned char types[8192]; 1140254897Serwin unsigned int maxtype = 0; 1141254897Serwin dns_rdataset_t rdataset; dns_rdatasetiter_t *rdsiter = NULL; 1142254897Serwin isc_result_t result, tresult; 1143254897Serwin 1144254897Serwin memset(types, 0, sizeof(types)); 1145254897Serwin result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1146254897Serwin check_result(result, "dns_db_allrdatasets()"); 1147254897Serwin result = dns_rdatasetiter_first(rdsiter); 1148254897Serwin dns_rdataset_init(&rdataset); 1149254897Serwin while (result == ISC_R_SUCCESS) { 1150254897Serwin dns_rdatasetiter_current(rdsiter, &rdataset); 1151254897Serwin /* 1152254897Serwin * If we are not at a delegation then everything should be 1153254897Serwin * signed. If we are at a delegation then only the DS set 1154254897Serwin * is signed. The NS set is not signed at a delegation but 1155254897Serwin * its existance is recorded in the bit map. Anything else 1156254897Serwin * other than NSEC and DS is not signed at a delegation. 1157254897Serwin */ 1158254897Serwin if (rdataset.type != dns_rdatatype_rrsig && 1159254897Serwin rdataset.type != dns_rdatatype_dnskey && 1160254897Serwin (!delegation || rdataset.type == dns_rdatatype_ds || 1161254897Serwin rdataset.type == dns_rdatatype_nsec)) { 1162254897Serwin verifyset(db, ver, origin, mctx, &rdataset, 1163254897Serwin name, node, keyrdataset, 1164254897Serwin act_algorithms, bad_algorithms); 1165254897Serwin dns_nsec_setbit(types, rdataset.type, 1); 1166254897Serwin if (rdataset.type > maxtype) 1167254897Serwin maxtype = rdataset.type; 1168254897Serwin } else if (rdataset.type != dns_rdatatype_rrsig && 1169254897Serwin rdataset.type != dns_rdatatype_dnskey) { 1170254897Serwin if (rdataset.type == dns_rdatatype_ns) 1171254897Serwin dns_nsec_setbit(types, rdataset.type, 1); 1172254897Serwin check_no_rrsig(db, ver, &rdataset, name, node); 1173254897Serwin } else 1174254897Serwin dns_nsec_setbit(types, rdataset.type, 1); 1175254897Serwin dns_rdataset_disassociate(&rdataset); 1176254897Serwin result = dns_rdatasetiter_next(rdsiter); 1177254897Serwin } 1178254897Serwin if (result != ISC_R_NOMORE) 1179254897Serwin fatal("rdataset iteration failed: %s", 1180254897Serwin isc_result_totext(result)); 1181254897Serwin dns_rdatasetiter_destroy(&rdsiter); 1182254897Serwin 1183254897Serwin result = ISC_R_SUCCESS; 1184254897Serwin 1185254897Serwin if (nsecset != NULL && dns_rdataset_isassociated(nsecset)) 1186254897Serwin result = verifynsec(db, ver, name, node, nextname); 1187254897Serwin 1188254897Serwin if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) { 1189254897Serwin tresult = verifynsec3s(db, ver, origin, mctx, name, 1190254897Serwin nsec3paramset, delegation, ISC_FALSE, 1191254897Serwin types, maxtype); 1192254897Serwin if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) 1193254897Serwin result = tresult; 1194254897Serwin } 1195254897Serwin return (result); 1196254897Serwin} 1197254897Serwin 1198254897Serwinstatic isc_boolean_t 1199254897Serwinis_empty(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) { 1200254897Serwin dns_rdatasetiter_t *rdsiter = NULL; 1201254897Serwin isc_result_t result; 1202254897Serwin 1203254897Serwin result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1204254897Serwin check_result(result, "dns_db_allrdatasets()"); 1205254897Serwin result = dns_rdatasetiter_first(rdsiter); 1206254897Serwin dns_rdatasetiter_destroy(&rdsiter); 1207254897Serwin if (result == ISC_R_NOMORE) 1208254897Serwin return (ISC_TRUE); 1209254897Serwin return (ISC_FALSE); 1210254897Serwin} 1211254897Serwin 1212254897Serwinstatic void 1213254897Serwincheck_no_nsec(dns_name_t *name, dns_dbnode_t *node, dns_db_t *db, 1214254897Serwin dns_dbversion_t *ver) 1215254897Serwin{ 1216254897Serwin dns_rdataset_t rdataset; 1217254897Serwin isc_result_t result; 1218254897Serwin 1219254897Serwin dns_rdataset_init(&rdataset); 1220254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 1221254897Serwin 0, 0, &rdataset, NULL); 1222254897Serwin if (result != ISC_R_NOTFOUND) { 1223254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 1224254897Serwin dns_name_format(name, namebuf, sizeof(namebuf)); 1225254897Serwin fatal("unexpected NSEC RRset at %s\n", namebuf); 1226254897Serwin } 1227254897Serwin 1228254897Serwin if (dns_rdataset_isassociated(&rdataset)) 1229254897Serwin dns_rdataset_disassociate(&rdataset); 1230254897Serwin} 1231254897Serwin 1232254897Serwinstatic isc_boolean_t 1233254897Serwinnewchain(const struct nsec3_chain_fixed *first, 1234254897Serwin const struct nsec3_chain_fixed *e) 1235254897Serwin{ 1236254897Serwin if (first->hash != e->hash || 1237254897Serwin first->iterations != e->iterations || 1238254897Serwin first->salt_length != e->salt_length || 1239254897Serwin first->next_length != e->next_length || 1240254897Serwin memcmp(first + 1, e + 1, first->salt_length) != 0) 1241254897Serwin return (ISC_TRUE); 1242254897Serwin return (ISC_FALSE); 1243254897Serwin} 1244254897Serwin 1245254897Serwinstatic void 1246254897Serwinfree_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) { 1247254897Serwin size_t len; 1248254897Serwin 1249254897Serwin len = sizeof(*e) + e->salt_length + 2 * e->next_length; 1250254897Serwin isc_mem_put(mctx, e, len); 1251254897Serwin} 1252254897Serwin 1253254897Serwinstatic isc_boolean_t 1254254897Serwinchecknext(const struct nsec3_chain_fixed *first, 1255254897Serwin const struct nsec3_chain_fixed *e) 1256254897Serwin{ 1257254897Serwin char buf[512]; 1258254897Serwin const unsigned char *d1 = (const unsigned char *)(first + 1); 1259254897Serwin const unsigned char *d2 = (const unsigned char *)(e + 1); 1260254897Serwin isc_buffer_t b; 1261254897Serwin isc_region_t sr; 1262254897Serwin 1263254897Serwin d1 += first->salt_length + first->next_length; 1264254897Serwin d2 += e->salt_length; 1265254897Serwin 1266254897Serwin if (memcmp(d1, d2, first->next_length) == 0) 1267254897Serwin return (ISC_TRUE); 1268254897Serwin 1269254897Serwin DE_CONST(d1 - first->next_length, sr.base); 1270254897Serwin sr.length = first->next_length; 1271254897Serwin isc_buffer_init(&b, buf, sizeof(buf)); 1272254897Serwin isc_base32hex_totext(&sr, 1, "", &b); 1273254897Serwin fprintf(stderr, "Break in NSEC3 chain at: %.*s\n", 1274254897Serwin (int) isc_buffer_usedlength(&b), buf); 1275254897Serwin 1276254897Serwin DE_CONST(d1, sr.base); 1277254897Serwin sr.length = first->next_length; 1278254897Serwin isc_buffer_init(&b, buf, sizeof(buf)); 1279254897Serwin isc_base32hex_totext(&sr, 1, "", &b); 1280254897Serwin fprintf(stderr, "Expected: %.*s\n", (int) isc_buffer_usedlength(&b), 1281254897Serwin buf); 1282254897Serwin 1283254897Serwin DE_CONST(d2, sr.base); 1284254897Serwin sr.length = first->next_length; 1285254897Serwin isc_buffer_init(&b, buf, sizeof(buf)); 1286254897Serwin isc_base32hex_totext(&sr, 1, "", &b); 1287254897Serwin fprintf(stderr, "Found: %.*s\n", (int) isc_buffer_usedlength(&b), buf); 1288254897Serwin 1289254897Serwin return (ISC_FALSE); 1290254897Serwin} 1291254897Serwin 1292254897Serwin#define EXPECTEDANDFOUND "Expected and found NSEC3 chains not equal\n" 1293254897Serwin 1294254897Serwinstatic isc_result_t 1295254897Serwinverify_nsec3_chains(isc_mem_t *mctx) { 1296254897Serwin isc_result_t result = ISC_R_SUCCESS; 1297254897Serwin struct nsec3_chain_fixed *e, *f = NULL; 1298254897Serwin struct nsec3_chain_fixed *first = NULL, *prev = NULL; 1299254897Serwin 1300254897Serwin while ((e = isc_heap_element(expected_chains, 1)) != NULL) { 1301254897Serwin isc_heap_delete(expected_chains, 1); 1302254897Serwin if (f == NULL) 1303254897Serwin f = isc_heap_element(found_chains, 1); 1304254897Serwin if (f != NULL) { 1305254897Serwin isc_heap_delete(found_chains, 1); 1306254897Serwin 1307254897Serwin /* 1308254897Serwin * Check that they match. 1309254897Serwin */ 1310254897Serwin if (chain_equal(e, f)) { 1311254897Serwin free_element(mctx, f); 1312254897Serwin f = NULL; 1313254897Serwin } else { 1314254897Serwin if (result == ISC_R_SUCCESS) 1315254897Serwin fprintf(stderr, EXPECTEDANDFOUND); 1316254897Serwin result = ISC_R_FAILURE; 1317254897Serwin /* 1318254897Serwin * Attempt to resync found_chain. 1319254897Serwin */ 1320254897Serwin while (f != NULL && !chain_compare(e, f)) { 1321254897Serwin free_element(mctx, f); 1322254897Serwin f = isc_heap_element(found_chains, 1); 1323254897Serwin if (f != NULL) 1324254897Serwin isc_heap_delete(found_chains, 1); 1325254897Serwin if (f != NULL && chain_equal(e, f)) { 1326254897Serwin free_element(mctx, f); 1327254897Serwin f = NULL; 1328254897Serwin break; 1329254897Serwin } 1330254897Serwin } 1331254897Serwin } 1332254897Serwin } else if (result == ISC_R_SUCCESS) { 1333254897Serwin fprintf(stderr, EXPECTEDANDFOUND); 1334254897Serwin result = ISC_R_FAILURE; 1335254897Serwin } 1336254897Serwin if (first == NULL || newchain(first, e)) { 1337254897Serwin if (prev != NULL) { 1338254897Serwin if (!checknext(prev, first)) 1339254897Serwin result = ISC_R_FAILURE; 1340254897Serwin if (prev != first) 1341254897Serwin free_element(mctx, prev); 1342254897Serwin } 1343254897Serwin if (first != NULL) 1344254897Serwin free_element(mctx, first); 1345254897Serwin prev = first = e; 1346254897Serwin continue; 1347254897Serwin } 1348254897Serwin if (!checknext(prev, e)) 1349254897Serwin result = ISC_R_FAILURE; 1350254897Serwin if (prev != first) 1351254897Serwin free_element(mctx, prev); 1352254897Serwin prev = e; 1353254897Serwin } 1354254897Serwin if (prev != NULL) { 1355254897Serwin if (!checknext(prev, first)) 1356254897Serwin result = ISC_R_FAILURE; 1357254897Serwin if (prev != first) 1358254897Serwin free_element(mctx, prev); 1359254897Serwin } 1360254897Serwin if (first != NULL) 1361254897Serwin free_element(mctx, first); 1362254897Serwin do { 1363254897Serwin if (f != NULL) { 1364254897Serwin if (result == ISC_R_SUCCESS) { 1365254897Serwin fprintf(stderr, EXPECTEDANDFOUND); 1366254897Serwin result = ISC_R_FAILURE; 1367254897Serwin } 1368254897Serwin free_element(mctx, f); 1369254897Serwin } 1370254897Serwin f = isc_heap_element(found_chains, 1); 1371254897Serwin if (f != NULL) 1372254897Serwin isc_heap_delete(found_chains, 1); 1373254897Serwin } while (f != NULL); 1374254897Serwin 1375254897Serwin return (result); 1376254897Serwin} 1377254897Serwin 1378254897Serwinstatic isc_result_t 1379254897Serwinverifyemptynodes(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1380254897Serwin isc_mem_t *mctx, dns_name_t *name, dns_name_t *prevname, 1381254897Serwin isc_boolean_t isdelegation, dns_rdataset_t *nsec3paramset) 1382254897Serwin{ 1383254897Serwin dns_namereln_t reln; 1384254897Serwin int order; 1385254897Serwin unsigned int labels, nlabels, i; 1386254897Serwin dns_name_t suffix; 1387254897Serwin isc_result_t result = ISC_R_SUCCESS, tresult; 1388254897Serwin 1389254897Serwin reln = dns_name_fullcompare(prevname, name, &order, &labels); 1390254897Serwin if (order >= 0) 1391254897Serwin return (result); 1392254897Serwin 1393254897Serwin nlabels = dns_name_countlabels(name); 1394254897Serwin 1395254897Serwin if (reln == dns_namereln_commonancestor || 1396254897Serwin reln == dns_namereln_contains) { 1397254897Serwin dns_name_init(&suffix, NULL); 1398254897Serwin for (i = labels + 1; i < nlabels; i++) { 1399254897Serwin dns_name_getlabelsequence(name, nlabels - i, i, 1400254897Serwin &suffix); 1401254897Serwin if (nsec3paramset != NULL && 1402254897Serwin dns_rdataset_isassociated(nsec3paramset)) { 1403254897Serwin tresult = verifynsec3s(db, ver, origin, mctx, 1404254897Serwin &suffix, nsec3paramset, 1405254897Serwin isdelegation, ISC_TRUE, 1406254897Serwin NULL, 0); 1407254897Serwin if (result == ISC_R_SUCCESS && 1408254897Serwin tresult != ISC_R_SUCCESS) 1409254897Serwin result = tresult; 1410254897Serwin } 1411254897Serwin } 1412254897Serwin } 1413254897Serwin return (result); 1414254897Serwin} 1415254897Serwin 1416254897Serwin/*% 1417254897Serwin * Verify that certain things are sane: 1418254897Serwin * 1419254897Serwin * The apex has a DNSKEY record with at least one KSK, and at least 1420254897Serwin * one ZSK if the -x flag was not used. 1421254897Serwin * 1422254897Serwin * The DNSKEY record was signed with at least one of the KSKs in this 1423254897Serwin * set. 1424254897Serwin * 1425254897Serwin * The rest of the zone was signed with at least one of the ZSKs 1426254897Serwin * present in the DNSKEY RRSET. 1427254897Serwin */ 1428254897Serwinvoid 1429254897Serwinverifyzone(dns_db_t *db, dns_dbversion_t *ver, 1430254897Serwin dns_name_t *origin, isc_mem_t *mctx, 1431254897Serwin isc_boolean_t ignore_kskflag, isc_boolean_t keyset_kskonly) 1432254897Serwin{ 1433254897Serwin char algbuf[80]; 1434254897Serwin dns_dbiterator_t *dbiter = NULL; 1435254897Serwin dns_dbnode_t *node = NULL, *nextnode = NULL; 1436254897Serwin dns_fixedname_t fname, fnextname, fprevname, fzonecut; 1437254897Serwin dns_name_t *name, *nextname, *prevname, *zonecut; 1438254897Serwin dns_rdata_dnskey_t dnskey; 1439254897Serwin dns_rdata_t rdata = DNS_RDATA_INIT; 1440254897Serwin dns_rdataset_t keyset, soaset; 1441254897Serwin dns_rdataset_t keysigs, soasigs; 1442254897Serwin dns_rdataset_t nsecset, nsecsigs; 1443254897Serwin dns_rdataset_t nsec3paramset, nsec3paramsigs; 1444254897Serwin int i; 1445254897Serwin isc_boolean_t done = ISC_FALSE; 1446254897Serwin isc_boolean_t first = ISC_TRUE; 1447254897Serwin isc_boolean_t goodksk = ISC_FALSE; 1448254897Serwin isc_boolean_t goodzsk = ISC_FALSE; 1449254897Serwin isc_result_t result, vresult = ISC_R_UNSET; 1450254897Serwin unsigned char revoked_ksk[256]; 1451254897Serwin unsigned char revoked_zsk[256]; 1452254897Serwin unsigned char standby_ksk[256]; 1453254897Serwin unsigned char standby_zsk[256]; 1454254897Serwin unsigned char ksk_algorithms[256]; 1455254897Serwin unsigned char zsk_algorithms[256]; 1456254897Serwin unsigned char bad_algorithms[256]; 1457254897Serwin unsigned char act_algorithms[256]; 1458254897Serwin 1459254897Serwin result = isc_heap_create(mctx, chain_compare, NULL, 1024, 1460254897Serwin &expected_chains); 1461254897Serwin check_result(result, "isc_heap_create()"); 1462254897Serwin result = isc_heap_create(mctx, chain_compare, NULL, 1024, 1463254897Serwin &found_chains); 1464254897Serwin check_result(result, "isc_heap_create()"); 1465254897Serwin 1466254897Serwin result = dns_db_findnode(db, origin, ISC_FALSE, &node); 1467254897Serwin if (result != ISC_R_SUCCESS) 1468254897Serwin fatal("failed to find the zone's origin: %s", 1469254897Serwin isc_result_totext(result)); 1470254897Serwin 1471254897Serwin dns_rdataset_init(&keyset); 1472254897Serwin dns_rdataset_init(&keysigs); 1473254897Serwin dns_rdataset_init(&soaset); 1474254897Serwin dns_rdataset_init(&soasigs); 1475254897Serwin dns_rdataset_init(&nsecset); 1476254897Serwin dns_rdataset_init(&nsecsigs); 1477254897Serwin dns_rdataset_init(&nsec3paramset); 1478254897Serwin dns_rdataset_init(&nsec3paramsigs); 1479254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 1480254897Serwin 0, 0, &keyset, &keysigs); 1481254897Serwin if (result != ISC_R_SUCCESS) 1482254897Serwin fatal("Zone contains no DNSSEC keys\n"); 1483254897Serwin 1484254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 1485254897Serwin 0, 0, &soaset, &soasigs); 1486254897Serwin if (result != ISC_R_SUCCESS) 1487254897Serwin fatal("Zone contains no SOA record\n"); 1488254897Serwin 1489254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 1490254897Serwin 0, 0, &nsecset, &nsecsigs); 1491254897Serwin if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 1492254897Serwin fatal("NSEC lookup failed\n"); 1493254897Serwin 1494254897Serwin result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 1495254897Serwin 0, 0, &nsec3paramset, &nsec3paramsigs); 1496254897Serwin if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 1497254897Serwin fatal("NSEC3PARAM lookup failed\n"); 1498254897Serwin 1499254897Serwin if (!dns_rdataset_isassociated(&keysigs)) 1500254897Serwin fatal("DNSKEY is not signed (keys offline or inactive?)\n"); 1501254897Serwin 1502254897Serwin if (!dns_rdataset_isassociated(&soasigs)) 1503254897Serwin fatal("SOA is not signed (keys offline or inactive?)\n"); 1504254897Serwin 1505254897Serwin if (dns_rdataset_isassociated(&nsecset) && 1506254897Serwin !dns_rdataset_isassociated(&nsecsigs)) 1507254897Serwin fatal("NSEC is not signed (keys offline or inactive?)\n"); 1508254897Serwin 1509254897Serwin if (dns_rdataset_isassociated(&nsec3paramset) && 1510254897Serwin !dns_rdataset_isassociated(&nsec3paramsigs)) 1511254897Serwin fatal("NSEC3PARAM is not signed (keys offline or inactive?)\n"); 1512254897Serwin 1513254897Serwin if (!dns_rdataset_isassociated(&nsecset) && 1514254897Serwin !dns_rdataset_isassociated(&nsec3paramset)) 1515254897Serwin fatal("No valid NSEC/NSEC3 chain for testing\n"); 1516254897Serwin 1517254897Serwin dns_db_detachnode(db, &node); 1518254897Serwin 1519254897Serwin memset(revoked_ksk, 0, sizeof(revoked_ksk)); 1520254897Serwin memset(revoked_zsk, 0, sizeof(revoked_zsk)); 1521254897Serwin memset(standby_ksk, 0, sizeof(standby_ksk)); 1522254897Serwin memset(standby_zsk, 0, sizeof(standby_zsk)); 1523254897Serwin memset(ksk_algorithms, 0, sizeof(ksk_algorithms)); 1524254897Serwin memset(zsk_algorithms, 0, sizeof(zsk_algorithms)); 1525254897Serwin memset(bad_algorithms, 0, sizeof(bad_algorithms)); 1526254897Serwin memset(act_algorithms, 0, sizeof(act_algorithms)); 1527254897Serwin 1528254897Serwin /* 1529254897Serwin * Check that the DNSKEY RR has at least one self signing KSK 1530254897Serwin * and one ZSK per algorithm in it (or, if -x was used, one 1531254897Serwin * self-signing KSK). 1532254897Serwin */ 1533254897Serwin for (result = dns_rdataset_first(&keyset); 1534254897Serwin result == ISC_R_SUCCESS; 1535254897Serwin result = dns_rdataset_next(&keyset)) { 1536254897Serwin dns_rdataset_current(&keyset, &rdata); 1537254897Serwin result = dns_rdata_tostruct(&rdata, &dnskey, NULL); 1538254897Serwin check_result(result, "dns_rdata_tostruct"); 1539254897Serwin 1540254897Serwin if ((dnskey.flags & DNS_KEYOWNER_ZONE) == 0) 1541254897Serwin ; 1542254897Serwin else if ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0) { 1543254897Serwin if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && 1544254897Serwin !dns_dnssec_selfsigns(&rdata, origin, &keyset, 1545254897Serwin &keysigs, ISC_FALSE, 1546254897Serwin mctx)) { 1547254897Serwin char namebuf[DNS_NAME_FORMATSIZE]; 1548254897Serwin char buffer[1024]; 1549254897Serwin isc_buffer_t buf; 1550254897Serwin 1551254897Serwin dns_name_format(origin, namebuf, 1552254897Serwin sizeof(namebuf)); 1553254897Serwin isc_buffer_init(&buf, buffer, sizeof(buffer)); 1554254897Serwin result = dns_rdata_totext(&rdata, NULL, &buf); 1555254897Serwin check_result(result, "dns_rdata_totext"); 1556254897Serwin fatal("revoked KSK is not self signed:\n" 1557254897Serwin "%s DNSKEY %.*s", namebuf, 1558254897Serwin (int)isc_buffer_usedlength(&buf), buffer); 1559254897Serwin } 1560254897Serwin if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && 1561254897Serwin revoked_ksk[dnskey.algorithm] != 255) 1562254897Serwin revoked_ksk[dnskey.algorithm]++; 1563254897Serwin else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && 1564254897Serwin revoked_zsk[dnskey.algorithm] != 255) 1565254897Serwin revoked_zsk[dnskey.algorithm]++; 1566254897Serwin } else if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) { 1567254897Serwin if (dns_dnssec_selfsigns(&rdata, origin, &keyset, 1568254897Serwin &keysigs, ISC_FALSE, mctx)) { 1569254897Serwin if (ksk_algorithms[dnskey.algorithm] != 255) 1570254897Serwin ksk_algorithms[dnskey.algorithm]++; 1571254897Serwin goodksk = ISC_TRUE; 1572254897Serwin } else { 1573254897Serwin if (standby_ksk[dnskey.algorithm] != 255) 1574254897Serwin standby_ksk[dnskey.algorithm]++; 1575254897Serwin } 1576254897Serwin } else if (dns_dnssec_selfsigns(&rdata, origin, &keyset, 1577254897Serwin &keysigs, ISC_FALSE, mctx)) { 1578254897Serwin if (zsk_algorithms[dnskey.algorithm] != 255) 1579254897Serwin zsk_algorithms[dnskey.algorithm]++; 1580254897Serwin goodzsk = ISC_TRUE; 1581254897Serwin } else if (dns_dnssec_signs(&rdata, origin, &soaset, 1582254897Serwin &soasigs, ISC_FALSE, mctx)) { 1583254897Serwin if (zsk_algorithms[dnskey.algorithm] != 255) 1584254897Serwin zsk_algorithms[dnskey.algorithm]++; 1585254897Serwin } else { 1586254897Serwin if (standby_zsk[dnskey.algorithm] != 255) 1587254897Serwin standby_zsk[dnskey.algorithm]++; 1588254897Serwin } 1589254897Serwin dns_rdata_freestruct(&dnskey); 1590254897Serwin dns_rdata_reset(&rdata); 1591254897Serwin } 1592254897Serwin dns_rdataset_disassociate(&keysigs); 1593254897Serwin dns_rdataset_disassociate(&soaset); 1594254897Serwin dns_rdataset_disassociate(&soasigs); 1595254897Serwin if (dns_rdataset_isassociated(&nsecsigs)) 1596254897Serwin dns_rdataset_disassociate(&nsecsigs); 1597254897Serwin if (dns_rdataset_isassociated(&nsec3paramsigs)) 1598254897Serwin dns_rdataset_disassociate(&nsec3paramsigs); 1599254897Serwin 1600254897Serwin if (ignore_kskflag ) { 1601254897Serwin if (!goodksk && !goodzsk) 1602254897Serwin fatal("No self-signed DNSKEY found."); 1603254897Serwin } else if (!goodksk) 1604254897Serwin fatal("No self-signed KSK DNSKEY found. Supply an active\n" 1605254897Serwin "key with the KSK flag set, or use '-P'."); 1606254897Serwin 1607254897Serwin fprintf(stderr, "Verifying the zone using the following algorithms:"); 1608254897Serwin for (i = 0; i < 256; i++) { 1609254897Serwin if (ignore_kskflag) 1610254897Serwin act_algorithms[i] = (ksk_algorithms[i] != 0 || 1611254897Serwin zsk_algorithms[i] != 0) ? 1 : 0; 1612254897Serwin else 1613254897Serwin act_algorithms[i] = ksk_algorithms[i] != 0 ? 1 : 0; 1614254897Serwin if (act_algorithms[i] != 0) { 1615254897Serwin dns_secalg_format(i, algbuf, sizeof(algbuf)); 1616254897Serwin fprintf(stderr, " %s", algbuf); 1617254897Serwin } 1618254897Serwin } 1619254897Serwin fprintf(stderr, ".\n"); 1620254897Serwin 1621254897Serwin if (!ignore_kskflag && !keyset_kskonly) { 1622254897Serwin for (i = 0; i < 256; i++) { 1623254897Serwin /* 1624254897Serwin * The counts should both be zero or both be non-zero. 1625254897Serwin * Mark the algorithm as bad if this is not met. 1626254897Serwin */ 1627254897Serwin if ((ksk_algorithms[i] != 0) == 1628254897Serwin (zsk_algorithms[i] != 0)) 1629254897Serwin continue; 1630254897Serwin dns_secalg_format(i, algbuf, sizeof(algbuf)); 1631254897Serwin fprintf(stderr, "Missing %s for algorithm %s\n", 1632254897Serwin (ksk_algorithms[i] != 0) 1633254897Serwin ? "ZSK" 1634254897Serwin : "self-signed KSK", 1635254897Serwin algbuf); 1636254897Serwin bad_algorithms[i] = 1; 1637254897Serwin } 1638254897Serwin } 1639254897Serwin 1640254897Serwin /* 1641254897Serwin * Check that all the other records were signed by keys that are 1642254897Serwin * present in the DNSKEY RRSET. 1643254897Serwin */ 1644254897Serwin 1645254897Serwin dns_fixedname_init(&fname); 1646254897Serwin name = dns_fixedname_name(&fname); 1647254897Serwin dns_fixedname_init(&fnextname); 1648254897Serwin nextname = dns_fixedname_name(&fnextname); 1649254897Serwin dns_fixedname_init(&fprevname); 1650254897Serwin prevname = NULL; 1651254897Serwin dns_fixedname_init(&fzonecut); 1652254897Serwin zonecut = NULL; 1653254897Serwin 1654254897Serwin result = dns_db_createiterator(db, DNS_DB_NONSEC3, &dbiter); 1655254897Serwin check_result(result, "dns_db_createiterator()"); 1656254897Serwin 1657254897Serwin result = dns_dbiterator_first(dbiter); 1658254897Serwin check_result(result, "dns_dbiterator_first()"); 1659254897Serwin 1660254897Serwin while (!done) { 1661254897Serwin isc_boolean_t isdelegation = ISC_FALSE; 1662254897Serwin 1663254897Serwin result = dns_dbiterator_current(dbiter, &node, name); 1664254897Serwin check_dns_dbiterator_current(result); 1665254897Serwin if (!dns_name_issubdomain(name, origin)) { 1666254897Serwin check_no_nsec(name, node, db, ver); 1667254897Serwin dns_db_detachnode(db, &node); 1668254897Serwin result = dns_dbiterator_next(dbiter); 1669254897Serwin if (result == ISC_R_NOMORE) 1670254897Serwin done = ISC_TRUE; 1671254897Serwin else 1672254897Serwin check_result(result, "dns_dbiterator_next()"); 1673254897Serwin continue; 1674254897Serwin } 1675254897Serwin if (is_delegation(db, ver, origin, name, node, NULL)) { 1676254897Serwin zonecut = dns_fixedname_name(&fzonecut); 1677254897Serwin dns_name_copy(name, zonecut, NULL); 1678254897Serwin isdelegation = ISC_TRUE; 1679254897Serwin } 1680254897Serwin nextnode = NULL; 1681254897Serwin result = dns_dbiterator_next(dbiter); 1682254897Serwin while (result == ISC_R_SUCCESS) { 1683254897Serwin result = dns_dbiterator_current(dbiter, &nextnode, 1684254897Serwin nextname); 1685254897Serwin check_dns_dbiterator_current(result); 1686254897Serwin if (!dns_name_issubdomain(nextname, origin) || 1687254897Serwin (zonecut != NULL && 1688254897Serwin dns_name_issubdomain(nextname, zonecut))) 1689254897Serwin { 1690254897Serwin check_no_nsec(nextname, nextnode, db, ver); 1691254897Serwin dns_db_detachnode(db, &nextnode); 1692254897Serwin result = dns_dbiterator_next(dbiter); 1693254897Serwin continue; 1694254897Serwin } 1695254897Serwin if (is_empty(db, ver, nextnode)) { 1696254897Serwin dns_db_detachnode(db, &nextnode); 1697254897Serwin result = dns_dbiterator_next(dbiter); 1698254897Serwin continue; 1699254897Serwin } 1700254897Serwin dns_db_detachnode(db, &nextnode); 1701254897Serwin break; 1702254897Serwin } 1703254897Serwin if (result == ISC_R_NOMORE) { 1704254897Serwin done = ISC_TRUE; 1705254897Serwin nextname = origin; 1706254897Serwin } else if (result != ISC_R_SUCCESS) 1707254897Serwin fatal("iterating through the database failed: %s", 1708254897Serwin isc_result_totext(result)); 1709254897Serwin result = verifynode(db, ver, origin, mctx, name, node, 1710254897Serwin isdelegation, &keyset, act_algorithms, 1711254897Serwin bad_algorithms, &nsecset, &nsec3paramset, 1712254897Serwin nextname); 1713254897Serwin if (vresult == ISC_R_UNSET) 1714254897Serwin vresult = ISC_R_SUCCESS; 1715254897Serwin if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS) 1716254897Serwin vresult = result; 1717254897Serwin if (prevname != NULL) { 1718254897Serwin result = verifyemptynodes(db, ver, origin, mctx, name, 1719254897Serwin prevname, isdelegation, 1720254897Serwin &nsec3paramset); 1721254897Serwin } else 1722254897Serwin prevname = dns_fixedname_name(&fprevname); 1723254897Serwin dns_name_copy(name, prevname, NULL); 1724254897Serwin if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS) 1725254897Serwin vresult = result; 1726254897Serwin dns_db_detachnode(db, &node); 1727254897Serwin } 1728254897Serwin 1729254897Serwin dns_dbiterator_destroy(&dbiter); 1730254897Serwin 1731254897Serwin result = dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbiter); 1732254897Serwin check_result(result, "dns_db_createiterator()"); 1733254897Serwin 1734254897Serwin for (result = dns_dbiterator_first(dbiter); 1735254897Serwin result == ISC_R_SUCCESS; 1736254897Serwin result = dns_dbiterator_next(dbiter) ) { 1737254897Serwin result = dns_dbiterator_current(dbiter, &node, name); 1738254897Serwin check_dns_dbiterator_current(result); 1739254897Serwin result = verifynode(db, ver, origin, mctx, name, node, 1740254897Serwin ISC_FALSE, &keyset, act_algorithms, 1741254897Serwin bad_algorithms, NULL, NULL, NULL); 1742254897Serwin check_result(result, "verifynode"); 1743254897Serwin record_found(db, ver, mctx, name, node, &nsec3paramset); 1744254897Serwin dns_db_detachnode(db, &node); 1745254897Serwin } 1746254897Serwin dns_dbiterator_destroy(&dbiter); 1747254897Serwin 1748254897Serwin dns_rdataset_disassociate(&keyset); 1749254897Serwin if (dns_rdataset_isassociated(&nsecset)) 1750254897Serwin dns_rdataset_disassociate(&nsecset); 1751254897Serwin if (dns_rdataset_isassociated(&nsec3paramset)) 1752254897Serwin dns_rdataset_disassociate(&nsec3paramset); 1753254897Serwin 1754254897Serwin result = verify_nsec3_chains(mctx); 1755254897Serwin if (vresult == ISC_R_UNSET) 1756254897Serwin vresult = ISC_R_SUCCESS; 1757254897Serwin if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) 1758254897Serwin vresult = result; 1759254897Serwin isc_heap_destroy(&expected_chains); 1760254897Serwin isc_heap_destroy(&found_chains); 1761254897Serwin 1762254897Serwin /* 1763254897Serwin * If we made it this far, we have what we consider a properly signed 1764254897Serwin * zone. Set the good flag. 1765254897Serwin */ 1766254897Serwin for (i = 0; i < 256; i++) { 1767254897Serwin if (bad_algorithms[i] != 0) { 1768254897Serwin if (first) 1769254897Serwin fprintf(stderr, "The zone is not fully signed " 1770254897Serwin "for the following algorithms:"); 1771254897Serwin dns_secalg_format(i, algbuf, sizeof(algbuf)); 1772254897Serwin fprintf(stderr, " %s", algbuf); 1773254897Serwin first = ISC_FALSE; 1774254897Serwin } 1775254897Serwin } 1776254897Serwin if (!first) { 1777254897Serwin fprintf(stderr, ".\n"); 1778254897Serwin fatal("DNSSEC completeness test failed."); 1779254897Serwin } 1780254897Serwin 1781254897Serwin if (vresult != ISC_R_SUCCESS) 1782254897Serwin fatal("DNSSEC completeness test failed (%s).", 1783254897Serwin dns_result_totext(vresult)); 1784254897Serwin 1785254897Serwin if (goodksk || ignore_kskflag) { 1786254897Serwin /* 1787254897Serwin * Print the success summary. 1788254897Serwin */ 1789254897Serwin fprintf(stderr, "Zone fully signed:\n"); 1790254897Serwin for (i = 0; i < 256; i++) { 1791254897Serwin if ((ksk_algorithms[i] != 0) || 1792254897Serwin (standby_ksk[i] != 0) || 1793254897Serwin (revoked_zsk[i] != 0) || 1794254897Serwin (zsk_algorithms[i] != 0) || 1795254897Serwin (standby_zsk[i] != 0) || 1796254897Serwin (revoked_zsk[i] != 0)) { 1797254897Serwin dns_secalg_format(i, algbuf, sizeof(algbuf)); 1798254897Serwin fprintf(stderr, "Algorithm: %s: KSKs: " 1799254897Serwin "%u active, %u stand-by, %u revoked\n", 1800254897Serwin algbuf, ksk_algorithms[i], 1801254897Serwin standby_ksk[i], revoked_ksk[i]); 1802254897Serwin fprintf(stderr, "%*sZSKs: " 1803254897Serwin "%u active, %u %s, %u revoked\n", 1804254897Serwin (int) strlen(algbuf) + 13, "", 1805254897Serwin zsk_algorithms[i], 1806254897Serwin standby_zsk[i], 1807254897Serwin keyset_kskonly ? "present" : "stand-by", 1808254897Serwin revoked_zsk[i]); 1809254897Serwin } 1810254897Serwin } 1811254897Serwin } 1812254897Serwin} 1813