diff options
Diffstat (limited to 'contrib/bind9/bin/dnssec/dnssec-signzone.c')
-rw-r--r-- | contrib/bind9/bin/dnssec/dnssec-signzone.c | 892 |
1 files changed, 286 insertions, 606 deletions
diff --git a/contrib/bind9/bin/dnssec/dnssec-signzone.c b/contrib/bind9/bin/dnssec/dnssec-signzone.c index 86c3aee..83456a7 100644 --- a/contrib/bind9/bin/dnssec/dnssec-signzone.c +++ b/contrib/bind9/bin/dnssec/dnssec-signzone.c @@ -1,5 +1,5 @@ /* - * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2004-2013 Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-signzone.c,v 1.262.110.9 2011/07/19 23:47:12 tbox Exp $ */ +/* $Id: dnssec-signzone.c,v 1.285 2011/12/22 07:32:39 each Exp $ */ /*! \file */ @@ -37,6 +37,7 @@ #include <stdlib.h> #include <time.h> +#include <unistd.h> #include <isc/app.h> #include <isc/base32.h> @@ -124,7 +125,7 @@ struct signer_event { static dns_dnsseckeylist_t keylist; static unsigned int keycount = 0; isc_rwlock_t keylist_lock; -static isc_stdtime_t starttime = 0, endtime = 0, now; +static isc_stdtime_t starttime = 0, endtime = 0, dnskey_endtime = 0, now; static int cycle = -1; static int jitter = 0; static isc_boolean_t tryverify = ISC_FALSE; @@ -133,11 +134,13 @@ static isc_mem_t *mctx = NULL; static isc_entropy_t *ectx = NULL; static dns_ttl_t zone_soa_min_ttl; static dns_ttl_t soa_ttl; -static FILE *fp; +static FILE *fp = NULL; static char *tempfile = NULL; static const dns_master_style_t *masterstyle; static dns_masterformat_t inputformat = dns_masterformat_text; static dns_masterformat_t outputformat = dns_masterformat_text; +static isc_uint32_t rawversion = 1, serialnum = 0; +static isc_boolean_t snset = ISC_FALSE; static unsigned int nsigned = 0, nretained = 0, ndropped = 0; static unsigned int nverified = 0, nverifyfailed = 0; static const char *directory = NULL, *dsdir = NULL; @@ -171,6 +174,10 @@ static isc_boolean_t disable_zone_check = ISC_FALSE; static isc_boolean_t update_chain = ISC_FALSE; static isc_boolean_t set_keyttl = ISC_FALSE; static dns_ttl_t keyttl; +static isc_boolean_t smartsign = ISC_FALSE; +static isc_boolean_t remove_orphans = ISC_FALSE; +static isc_boolean_t output_dnssec_only = ISC_FALSE; +static isc_boolean_t output_stdout = ISC_FALSE; #define INCSTAT(counter) \ if (printstats) { \ @@ -182,19 +189,71 @@ static dns_ttl_t keyttl; static void sign(isc_task_t *task, isc_event_t *event); -#define check_dns_dbiterator_current(result) \ - check_result((result == DNS_R_NEWORIGIN) ? ISC_R_SUCCESS : result, \ - "dns_dbiterator_current()") - static void dumpnode(dns_name_t *name, dns_dbnode_t *node) { + dns_rdataset_t rds; + dns_rdatasetiter_t *iter = NULL; + isc_buffer_t *buffer = NULL; + isc_region_t r; isc_result_t result; + unsigned bufsize = 4096; if (outputformat != dns_masterformat_text) return; - result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, name, - masterstyle, fp); - check_result(result, "dns_master_dumpnodetostream"); + + if (!output_dnssec_only) { + result = dns_master_dumpnodetostream(mctx, gdb, gversion, node, + name, masterstyle, fp); + check_result(result, "dns_master_dumpnodetostream"); + return; + } + + result = dns_db_allrdatasets(gdb, node, gversion, 0, &iter); + check_result(result, "dns_db_allrdatasets"); + + dns_rdataset_init(&rds); + + result = isc_buffer_allocate(mctx, &buffer, bufsize); + check_result(result, "isc_buffer_allocate"); + + for (result = dns_rdatasetiter_first(iter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) { + + dns_rdatasetiter_current(iter, &rds); + + if (rds.type != dns_rdatatype_rrsig && + rds.type != dns_rdatatype_nsec && + rds.type != dns_rdatatype_nsec3 && + rds.type != dns_rdatatype_nsec3param && + (!smartsign || rds.type != dns_rdatatype_dnskey)) { + dns_rdataset_disassociate(&rds); + continue; + } + + for (;;) { + result = dns_master_rdatasettotext(name, &rds, + masterstyle, buffer); + if (result != ISC_R_NOSPACE) + break; + + bufsize <<= 1; + isc_buffer_free(&buffer); + result = isc_buffer_allocate(mctx, &buffer, bufsize); + check_result(result, "isc_buffer_allocate"); + } + check_result(result, "dns_master_rdatasettotext"); + + isc_buffer_usedregion(buffer, &r); + result = isc_stdio_write(r.base, 1, r.length, fp, NULL); + check_result(result, "isc_stdio_write"); + isc_buffer_clear(buffer); + + dns_rdataset_disassociate(&rds); + } + + isc_buffer_free(&buffer); + dns_rdatasetiter_destroy(&iter); } /*% @@ -206,7 +265,7 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key, dns_ttl_t ttl, dns_diff_t *add, const char *logmsg) { isc_result_t result; - isc_stdtime_t jendtime; + isc_stdtime_t jendtime, expiry; char keystr[DST_KEY_FORMATSIZE]; dns_rdata_t trdata = DNS_RDATA_INIT; unsigned char array[BUFSIZE]; @@ -216,7 +275,12 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dst_key_t *key, dst_key_format(key, keystr, sizeof(keystr)); vbprintf(1, "\t%s %s\n", logmsg, keystr); - jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime; + if (rdataset->type == dns_rdatatype_dnskey) + expiry = dnskey_endtime; + else + expiry = endtime; + + jendtime = (jitter != 0) ? isc_random_jitter(expiry, jitter) : expiry; isc_buffer_init(&b, array, sizeof(array)); result = dns_dnssec_sign(name, rdataset, key, &starttime, &jendtime, mctx, &b, &trdata); @@ -254,6 +318,12 @@ issigningkey(dns_dnsseckey_t *key) { } static inline isc_boolean_t +ispublishedkey(dns_dnsseckey_t *key) { + return ((key->force_publish || key->hint_publish) && + !key->hint_remove); +} + +static inline isc_boolean_t iszonekey(dns_dnsseckey_t *key) { return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) && dst_key_iszonekey(key->key))); @@ -334,13 +404,16 @@ keythatsigned(dns_rdata_rrsig_t *rrsig) { directory, mctx, &privkey); if (result == ISC_R_SUCCESS) { dst_key_free(&pubkey); - dns_dnsseckey_create(mctx, &privkey, &key); - } else { - dns_dnsseckey_create(mctx, &pubkey, &key); + result = dns_dnsseckey_create(mctx, &privkey, &key); + } else + result = dns_dnsseckey_create(mctx, &pubkey, &key); + + if (result == ISC_R_SUCCESS) { + key->force_publish = ISC_FALSE; + key->force_sign = ISC_FALSE; + key->index = keycount++; + ISC_LIST_APPEND(keylist, key, link); } - key->force_publish = ISC_FALSE; - key->force_sign = ISC_FALSE; - ISC_LIST_APPEND(keylist, key, link); isc_rwlock_unlock(&keylist_lock, isc_rwlocktype_write); return (key); @@ -481,38 +554,38 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, "private dnskey not found\n", sigstr); } else if (key == NULL || future) { + keep = (!expired && !remove_orphans); vbprintf(2, "\trrsig by %s %s - dnskey not found\n", - expired ? "retained" : "dropped", sigstr); - if (!expired) - keep = ISC_TRUE; + keep ? "retained" : "dropped", sigstr); } else if (issigningkey(key)) { + wassignedby[key->index] = ISC_TRUE; + if (!expired && rrsig.originalttl == set->ttl && setverifies(name, set, key->key, &sigrdata)) { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; - wassignedby[key->index] = ISC_TRUE; - nowsignedby[key->index] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : rrsig.originalttl != set->ttl ? "ttl change" : "failed to verify"); - wassignedby[key->index] = ISC_TRUE; resign = ISC_TRUE; } + } else if (!ispublishedkey(key) && remove_orphans) { + vbprintf(2, "\trrsig by %s dropped - dnskey removed\n", + sigstr); } else if (iszonekey(key)) { + wassignedby[key->index] = ISC_TRUE; + if (!expired && rrsig.originalttl == set->ttl && setverifies(name, set, key->key, &sigrdata)) { vbprintf(2, "\trrsig by %s retained\n", sigstr); keep = ISC_TRUE; - wassignedby[key->index] = ISC_TRUE; - nowsignedby[key->index] = ISC_TRUE; } else { vbprintf(2, "\trrsig by %s dropped - %s\n", sigstr, expired ? "expired" : rrsig.originalttl != set->ttl ? "ttl change" : "failed to verify"); - wassignedby[key->index] = ISC_TRUE; } } else if (!expired) { vbprintf(2, "\trrsig by %s retained\n", sigstr); @@ -545,6 +618,7 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name, } } else { tuple = NULL; + vbprintf(2, "removing signature by %s\n", sigstr); result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name, sigset.ttl, &sigrdata, &tuple); @@ -922,26 +996,6 @@ loadds(dns_name_t *name, isc_uint32_t ttl, dns_rdataset_t *dsset) { } static isc_boolean_t -delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) { - dns_rdataset_t nsset; - isc_result_t result; - - if (dns_name_equal(name, gorigin)) - return (ISC_FALSE); - - dns_rdataset_init(&nsset); - result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ns, - 0, 0, &nsset, NULL); - if (dns_rdataset_isassociated(&nsset)) { - if (ttlp != NULL) - *ttlp = nsset.ttl; - dns_rdataset_disassociate(&nsset); - } - - return (ISC_TF(result == ISC_R_SUCCESS)); -} - -static isc_boolean_t secure(dns_name_t *name, dns_dbnode_t *node) { dns_rdataset_t dsset; isc_result_t result; @@ -976,7 +1030,7 @@ signname(dns_dbnode_t *node, dns_name_t *name) { /* * Determine if this is a delegation point. */ - if (delegation(name, node, NULL)) + if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) isdelegation = ISC_TRUE; /* @@ -1309,485 +1363,6 @@ postsign(void) { dns_dbiterator_destroy(&gdbiter); } -static isc_boolean_t -goodsig(dns_rdata_t *sigrdata, dns_name_t *name, dns_rdataset_t *keyrdataset, - dns_rdataset_t *rdataset) -{ - dns_rdata_dnskey_t key; - dns_rdata_rrsig_t sig; - dst_key_t *dstkey = NULL; - isc_result_t result; - - dns_rdata_tostruct(sigrdata, &sig, NULL); - - for (result = dns_rdataset_first(keyrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(keyrdataset)) { - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_current(keyrdataset, &rdata); - dns_rdata_tostruct(&rdata, &key, NULL); - result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx, - &dstkey); - if (result != ISC_R_SUCCESS) - return (ISC_FALSE); - if (sig.algorithm != key.algorithm || - sig.keyid != dst_key_id(dstkey) || - !dns_name_equal(&sig.signer, gorigin)) { - dst_key_free(&dstkey); - continue; - } - result = dns_dnssec_verify(name, rdataset, dstkey, ISC_FALSE, - mctx, sigrdata); - dst_key_free(&dstkey); - if (result == ISC_R_SUCCESS) - return(ISC_TRUE); - } - return (ISC_FALSE); -} - -static void -verifyset(dns_rdataset_t *rdataset, dns_name_t *name, dns_dbnode_t *node, - dns_rdataset_t *keyrdataset, unsigned char *ksk_algorithms, - unsigned char *bad_algorithms) -{ - unsigned char set_algorithms[256]; - char namebuf[DNS_NAME_FORMATSIZE]; - char algbuf[80]; - char typebuf[80]; - dns_rdataset_t sigrdataset; - dns_rdatasetiter_t *rdsiter = NULL; - isc_result_t result; - int i; - - dns_rdataset_init(&sigrdataset); - result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter); - check_result(result, "dns_db_allrdatasets()"); - for (result = dns_rdatasetiter_first(rdsiter); - result == ISC_R_SUCCESS; - result = dns_rdatasetiter_next(rdsiter)) { - dns_rdatasetiter_current(rdsiter, &sigrdataset); - if (sigrdataset.type == dns_rdatatype_rrsig && - sigrdataset.covers == rdataset->type) - break; - dns_rdataset_disassociate(&sigrdataset); - } - if (result != ISC_R_SUCCESS) { - dns_name_format(name, namebuf, sizeof(namebuf)); - type_format(rdataset->type, typebuf, sizeof(typebuf)); - fprintf(stderr, "no signatures for %s/%s\n", namebuf, typebuf); - for (i = 0; i < 256; i++) - if (ksk_algorithms[i] != 0) - bad_algorithms[i] = 1; - return; - } - - memset(set_algorithms, 0, sizeof(set_algorithms)); - for (result = dns_rdataset_first(&sigrdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&sigrdataset)) { - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_rrsig_t sig; - - dns_rdataset_current(&sigrdataset, &rdata); - dns_rdata_tostruct(&rdata, &sig, NULL); - if (rdataset->ttl != sig.originalttl) { - dns_name_format(name, namebuf, sizeof(namebuf)); - type_format(rdataset->type, typebuf, sizeof(typebuf)); - fprintf(stderr, "TTL mismatch for %s %s keytag %u\n", - namebuf, typebuf, sig.keyid); - continue; - } - if ((set_algorithms[sig.algorithm] != 0) || - (ksk_algorithms[sig.algorithm] == 0)) - continue; - if (goodsig(&rdata, name, keyrdataset, rdataset)) - set_algorithms[sig.algorithm] = 1; - } - dns_rdatasetiter_destroy(&rdsiter); - if (memcmp(set_algorithms, ksk_algorithms, sizeof(set_algorithms))) { - dns_name_format(name, namebuf, sizeof(namebuf)); - type_format(rdataset->type, typebuf, sizeof(typebuf)); - for (i = 0; i < 256; i++) - if ((ksk_algorithms[i] != 0) && - (set_algorithms[i] == 0)) { - dns_secalg_format(i, algbuf, sizeof(algbuf)); - fprintf(stderr, "Missing %s signature for " - "%s %s\n", algbuf, namebuf, typebuf); - bad_algorithms[i] = 1; - } - } - dns_rdataset_disassociate(&sigrdataset); -} - -static void -verifynode(dns_name_t *name, dns_dbnode_t *node, isc_boolean_t delegation, - dns_rdataset_t *keyrdataset, unsigned char *ksk_algorithms, - unsigned char *bad_algorithms) -{ - dns_rdataset_t rdataset; - dns_rdatasetiter_t *rdsiter = NULL; - isc_result_t result; - - result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter); - check_result(result, "dns_db_allrdatasets()"); - result = dns_rdatasetiter_first(rdsiter); - dns_rdataset_init(&rdataset); - while (result == ISC_R_SUCCESS) { - dns_rdatasetiter_current(rdsiter, &rdataset); - if (rdataset.type != dns_rdatatype_rrsig && - rdataset.type != dns_rdatatype_dnskey && - (!delegation || rdataset.type == dns_rdatatype_ds || - rdataset.type == dns_rdatatype_nsec)) { - verifyset(&rdataset, name, node, keyrdataset, - ksk_algorithms, bad_algorithms); - } - dns_rdataset_disassociate(&rdataset); - result = dns_rdatasetiter_next(rdsiter); - } - if (result != ISC_R_NOMORE) - fatal("rdataset iteration failed: %s", - isc_result_totext(result)); - dns_rdatasetiter_destroy(&rdsiter); -} - -/*% - * Verify that certain things are sane: - * - * The apex has a DNSKEY RRset with at least one KSK, and at least - * one ZSK if the -x flag was not used. - * - * The DNSKEY record was signed with at least one of the KSKs in - * the DNSKEY RRset. - * - * The rest of the zone was signed with at least one of the ZSKs - * present in the DNSKEY RRset. - */ -static void -verifyzone(void) { - char algbuf[80]; - dns_dbiterator_t *dbiter = NULL; - dns_dbnode_t *node = NULL, *nextnode = NULL; - dns_fixedname_t fname, fnextname, fzonecut; - dns_name_t *name, *nextname, *zonecut; - dns_rdata_dnskey_t dnskey; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t keyset, soaset; - dns_rdataset_t keysigs, soasigs; - int i; - isc_boolean_t done = ISC_FALSE; - isc_boolean_t first = ISC_TRUE; - isc_boolean_t goodksk = ISC_FALSE; - isc_result_t result; - unsigned char revoked_ksk[256]; - unsigned char revoked_zsk[256]; - unsigned char standby_ksk[256]; - unsigned char standby_zsk[256]; - unsigned char ksk_algorithms[256]; - unsigned char zsk_algorithms[256]; - unsigned char bad_algorithms[256]; -#ifdef ALLOW_KSKLESS_ZONES - isc_boolean_t allzsksigned = ISC_TRUE; - unsigned char self_algorithms[256]; -#endif - - if (disable_zone_check) - return; - - result = dns_db_findnode(gdb, gorigin, ISC_FALSE, &node); - if (result != ISC_R_SUCCESS) - fatal("failed to find the zone's origin: %s", - isc_result_totext(result)); - - dns_rdataset_init(&keyset); - dns_rdataset_init(&keysigs); - dns_rdataset_init(&soaset); - dns_rdataset_init(&soasigs); - - result = dns_db_findrdataset(gdb, node, gversion, - dns_rdatatype_dnskey, - 0, 0, &keyset, &keysigs); - if (result != ISC_R_SUCCESS) - fatal("cannot find DNSKEY rrset\n"); - - result = dns_db_findrdataset(gdb, node, gversion, - dns_rdatatype_soa, - 0, 0, &soaset, &soasigs); - dns_db_detachnode(gdb, &node); - if (result != ISC_R_SUCCESS) - fatal("cannot find SOA rrset\n"); - - if (!dns_rdataset_isassociated(&keysigs)) - fatal("cannot find DNSKEY RRSIGs\n"); - - if (!dns_rdataset_isassociated(&soasigs)) - fatal("cannot find SOA RRSIGs\n"); - - memset(revoked_ksk, 0, sizeof(revoked_ksk)); - memset(revoked_zsk, 0, sizeof(revoked_zsk)); - memset(standby_ksk, 0, sizeof(standby_ksk)); - memset(standby_zsk, 0, sizeof(standby_zsk)); - memset(ksk_algorithms, 0, sizeof(ksk_algorithms)); - memset(zsk_algorithms, 0, sizeof(zsk_algorithms)); - memset(bad_algorithms, 0, sizeof(bad_algorithms)); -#ifdef ALLOW_KSKLESS_ZONES - memset(self_algorithms, 0, sizeof(self_algorithms)); -#endif - - /* - * Check that the DNSKEY RR has at least one self signing KSK - * and one ZSK per algorithm in it (or, if -x was used, one - * self-signing KSK). - */ - for (result = dns_rdataset_first(&keyset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(&keyset)) { - dns_rdataset_current(&keyset, &rdata); - result = dns_rdata_tostruct(&rdata, &dnskey, NULL); - check_result(result, "dns_rdata_tostruct"); - - if ((dnskey.flags & DNS_KEYOWNER_ZONE) == 0) - ; - else if ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0) { - if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && - !dns_dnssec_selfsigns(&rdata, gorigin, &keyset, - &keysigs, ISC_FALSE, - mctx)) { - char namebuf[DNS_NAME_FORMATSIZE]; - char buffer[1024]; - isc_buffer_t buf; - - dns_name_format(gorigin, namebuf, - sizeof(namebuf)); - isc_buffer_init(&buf, buffer, sizeof(buffer)); - result = dns_rdata_totext(&rdata, NULL, &buf); - check_result(result, "dns_rdata_totext"); - fatal("revoked KSK is not self signed:\n" - "%s DNSKEY %.*s", namebuf, - (int)isc_buffer_usedlength(&buf), buffer); - } - if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && - revoked_ksk[dnskey.algorithm] != 255) - revoked_ksk[dnskey.algorithm]++; - else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && - revoked_zsk[dnskey.algorithm] != 255) - revoked_zsk[dnskey.algorithm]++; - } else if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) { - if (dns_dnssec_selfsigns(&rdata, gorigin, &keyset, - &keysigs, ISC_FALSE, mctx)) { - if (ksk_algorithms[dnskey.algorithm] != 255) - ksk_algorithms[dnskey.algorithm]++; - goodksk = ISC_TRUE; - } else { - if (standby_ksk[dnskey.algorithm] != 255) - standby_ksk[dnskey.algorithm]++; - } - } else if (dns_dnssec_selfsigns(&rdata, gorigin, &keyset, - &keysigs, ISC_FALSE, - mctx)) { -#ifdef ALLOW_KSKLESS_ZONES - if (self_algorithms[dnskey.algorithm] != 255) - self_algorithms[dnskey.algorithm]++; -#endif - if (zsk_algorithms[dnskey.algorithm] != 255) - zsk_algorithms[dnskey.algorithm]++; - } else if (dns_dnssec_signs(&rdata, gorigin, &soaset, - &soasigs, ISC_FALSE, mctx)) { - if (zsk_algorithms[dnskey.algorithm] != 255) - zsk_algorithms[dnskey.algorithm]++; - } else { - if (standby_zsk[dnskey.algorithm] != 255) - standby_zsk[dnskey.algorithm]++; -#ifdef ALLOW_KSKLESS_ZONES - allzsksigned = ISC_FALSE; -#endif - } - dns_rdata_freestruct(&dnskey); - dns_rdata_reset(&rdata); - } - dns_rdataset_disassociate(&keysigs); - dns_rdataset_disassociate(&soaset); - dns_rdataset_disassociate(&soasigs); - -#ifdef ALLOW_KSKLESS_ZONES - if (!goodksk) { - if (!ignore_kskflag) - fprintf(stderr, "No self signing KSK found. Using " - "self signed ZSK's for active " - "algorithm list.\n"); - memcpy(ksk_algorithms, self_algorithms, sizeof(ksk_algorithms)); - if (!allzsksigned) - fprintf(stderr, "warning: not all ZSK's are self " - "signed.\n"); - } -#else - if (!goodksk) { - fatal("No self signed KSK's found"); - } -#endif - - fprintf(stderr, "Verifying the zone using the following algorithms:"); - for (i = 0; i < 256; i++) { -#ifdef ALLOW_KSKLESS_ZONES - if (ksk_algorithms[i] != 0 || zsk_algorithms[i] != 0) -#else - if (ksk_algorithms[i] != 0) -#endif - { - dns_secalg_format(i, algbuf, sizeof(algbuf)); - fprintf(stderr, " %s", algbuf); - } - } - fprintf(stderr, ".\n"); - - if (!ignore_kskflag && !keyset_kskonly) { - for (i = 0; i < 256; i++) { - /* - * The counts should both be zero or both be non-zero. - * Mark the algorithm as bad if this is not met. - */ - if ((ksk_algorithms[i] != 0) == - (zsk_algorithms[i] != 0)) - continue; - dns_secalg_format(i, algbuf, sizeof(algbuf)); - fprintf(stderr, "Missing %s for algorithm %s\n", - (ksk_algorithms[i] != 0) - ? "ZSK" - : "self signing KSK", - algbuf); - bad_algorithms[i] = 1; - } - } - - /* - * Check that all the other records were signed by keys that are - * present in the DNSKEY RRSET. - */ - - dns_fixedname_init(&fname); - name = dns_fixedname_name(&fname); - dns_fixedname_init(&fnextname); - nextname = dns_fixedname_name(&fnextname); - dns_fixedname_init(&fzonecut); - zonecut = NULL; - - result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter); - check_result(result, "dns_db_createiterator()"); - - result = dns_dbiterator_first(dbiter); - check_result(result, "dns_dbiterator_first()"); - - while (!done) { - isc_boolean_t isdelegation = ISC_FALSE; - - result = dns_dbiterator_current(dbiter, &node, name); - check_dns_dbiterator_current(result); - if (!dns_name_issubdomain(name, gorigin)) { - dns_db_detachnode(gdb, &node); - result = dns_dbiterator_next(dbiter); - if (result == ISC_R_NOMORE) - done = ISC_TRUE; - else - check_result(result, "dns_dbiterator_next()"); - continue; - } - if (delegation(name, node, NULL)) { - zonecut = dns_fixedname_name(&fzonecut); - dns_name_copy(name, zonecut, NULL); - isdelegation = ISC_TRUE; - } - verifynode(name, node, isdelegation, &keyset, - ksk_algorithms, bad_algorithms); - result = dns_dbiterator_next(dbiter); - nextnode = NULL; - while (result == ISC_R_SUCCESS) { - result = dns_dbiterator_current(dbiter, &nextnode, - nextname); - check_dns_dbiterator_current(result); - if (!dns_name_issubdomain(nextname, gorigin) || - (zonecut != NULL && - dns_name_issubdomain(nextname, zonecut))) - { - dns_db_detachnode(gdb, &nextnode); - result = dns_dbiterator_next(dbiter); - continue; - } - dns_db_detachnode(gdb, &nextnode); - break; - } - if (result == ISC_R_NOMORE) { - done = ISC_TRUE; - } else if (result != ISC_R_SUCCESS) - fatal("iterating through the database failed: %s", - isc_result_totext(result)); - dns_db_detachnode(gdb, &node); - } - - dns_dbiterator_destroy(&dbiter); - - result = dns_db_createiterator(gdb, DNS_DB_NSEC3ONLY, &dbiter); - check_result(result, "dns_db_createiterator()"); - - for (result = dns_dbiterator_first(dbiter); - result == ISC_R_SUCCESS; - result = dns_dbiterator_next(dbiter) ) { - result = dns_dbiterator_current(dbiter, &node, name); - check_dns_dbiterator_current(result); - verifynode(name, node, ISC_FALSE, &keyset, - ksk_algorithms, bad_algorithms); - dns_db_detachnode(gdb, &node); - } - dns_dbiterator_destroy(&dbiter); - - dns_rdataset_disassociate(&keyset); - - /* - * If we made it this far, we have what we consider a properly signed - * zone. Set the good flag. - */ - for (i = 0; i < 256; i++) { - if (bad_algorithms[i] != 0) { - if (first) - fprintf(stderr, "The zone is not fully signed " - "for the following algorithms:"); - dns_secalg_format(i, algbuf, sizeof(algbuf)); - fprintf(stderr, " %s", algbuf); - first = ISC_FALSE; - } - } - if (!first) { - fprintf(stderr, ".\n"); - fatal("DNSSEC completeness test failed."); - } - - if (goodksk || ignore_kskflag) { - /* - * Print the success summary. - */ - fprintf(stderr, "Zone signing complete:\n"); - for (i = 0; i < 256; i++) { - if ((ksk_algorithms[i] != 0) || - (standby_ksk[i] != 0) || - (revoked_zsk[i] != 0) || - (zsk_algorithms[i] != 0) || - (standby_zsk[i] != 0) || - (revoked_zsk[i] != 0)) { - dns_secalg_format(i, algbuf, sizeof(algbuf)); - fprintf(stderr, "Algorithm: %s: KSKs: " - "%u active, %u stand-by, %u revoked\n", - algbuf, ksk_algorithms[i], - standby_ksk[i], revoked_ksk[i]); - fprintf(stderr, "%*sZSKs: " - "%u active, %u %s, %u revoked\n", - (int) strlen(algbuf) + 13, "", - zsk_algorithms[i], - standby_zsk[i], - keyset_kskonly ? "present" : "stand-by", - revoked_zsk[i]); - } - } - } -} - /*% * Sign the apex of the zone. * Note the origin may not be the first node if there are out of zone @@ -1885,7 +1460,7 @@ assignwork(isc_task_t *task, isc_task_t *worker) { if (dns_name_issubdomain(name, gorigin) && (zonecut == NULL || !dns_name_issubdomain(name, zonecut))) { - if (delegation(name, node, NULL)) { + if (is_delegation(gdb, gversion, gorigin, name, node, NULL)) { dns_fixedname_init(&fzonecut); zonecut = dns_fixedname_name(&fzonecut); dns_name_copy(name, zonecut, NULL); @@ -2181,7 +1756,7 @@ nsecify(void) { remove_records(node, dns_rdatatype_nsec3param, ISC_TRUE); - if (delegation(name, node, &nsttl)) { + if (is_delegation(gdb, gversion, gorigin, name, node, &nsttl)) { zonecut = dns_fixedname_name(&fzonecut); dns_name_copy(name, zonecut, NULL); remove_sigs(node, 0); @@ -2622,7 +2197,9 @@ nsec3ify(unsigned int hashalg, unsigned int iterations, result = dns_dbiterator_next(dbiter); continue; } - if (delegation(nextname, nextnode, &nsttl)) { + if (is_delegation(gdb, gversion, gorigin, + nextname, nextnode, &nsttl)) + { zonecut = dns_fixedname_name(&fzonecut); dns_name_copy(nextname, zonecut, NULL); remove_sigs(nextnode, 0); @@ -2751,7 +2328,9 @@ nsec3ify(unsigned int hashalg, unsigned int iterations, result = dns_dbiterator_next(dbiter); continue; } - if (delegation(nextname, nextnode, NULL)) { + if (is_delegation(gdb, gversion, gorigin, + nextname, nextnode, NULL)) + { zonecut = dns_fixedname_name(&fzonecut); dns_name_copy(nextname, zonecut, NULL); if (OPTOUT(nsec3flags) && @@ -3324,10 +2903,16 @@ usage(void) { fprintf(stderr, "update DS records based on child zones' " "dsset-* files\n"); fprintf(stderr, "\t-s [YYYYMMDDHHMMSS|+offset]:\n"); - fprintf(stderr, "\t\tRRSIG start time - absolute|offset (now - 1 hour)\n"); + fprintf(stderr, "\t\tRRSIG start time " + "- absolute|offset (now - 1 hour)\n"); fprintf(stderr, "\t-e [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); - fprintf(stderr, "\t\tRRSIG end time - absolute|from start|from now " + fprintf(stderr, "\t\tRRSIG end time " + "- absolute|from start|from now " "(now + 30 days)\n"); + fprintf(stderr, "\t-X [YYYYMMDDHHMMSS|+offset|\"now\"+offset]:\n"); + fprintf(stderr, "\t\tDNSKEY RRSIG end " + "- absolute|from start|from now " + "(matches -e)\n"); fprintf(stderr, "\t-i interval:\n"); fprintf(stderr, "\t\tcycle interval - resign " "if < interval from end ( (end-start)/4 )\n"); @@ -3345,6 +2930,8 @@ usage(void) { fprintf(stderr, "\t\tfile format of signed zone file (text)\n"); fprintf(stderr, "\t-N format:\n"); fprintf(stderr, "\t\tsoa serial format of signed zone file (keep)\n"); + fprintf(stderr, "\t-D:\n"); + fprintf(stderr, "\t\toutput only DNSSEC-related records\n"); fprintf(stderr, "\t-r randomdev:\n"); fprintf(stderr, "\t\ta file containing random data\n"); fprintf(stderr, "\t-a:\t"); @@ -3361,6 +2948,8 @@ usage(void) { fprintf(stderr, "use pseudorandom data (faster but less secure)\n"); fprintf(stderr, "\t-P:\t"); fprintf(stderr, "disable post-sign verification\n"); + fprintf(stderr, "\t-R:\t"); + fprintf(stderr, "remove signatures from keys that no longer exist\n"); fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n"); fprintf(stderr, "\t-t:\t"); fprintf(stderr, "print statistics\n"); @@ -3398,36 +2987,39 @@ print_stats(isc_time_t *timer_start, isc_time_t *timer_finish, isc_uint64_t time_us; /* Time in microseconds */ isc_uint64_t time_ms; /* Time in milliseconds */ isc_uint64_t sig_ms; /* Signatures per millisecond */ + FILE *out = output_stdout ? stderr : stdout; - printf("Signatures generated: %10d\n", nsigned); - printf("Signatures retained: %10d\n", nretained); - printf("Signatures dropped: %10d\n", ndropped); - printf("Signatures successfully verified: %10d\n", nverified); - printf("Signatures unsuccessfully verified: %10d\n", nverifyfailed); + fprintf(out, "Signatures generated: %10d\n", nsigned); + fprintf(out, "Signatures retained: %10d\n", nretained); + fprintf(out, "Signatures dropped: %10d\n", ndropped); + fprintf(out, "Signatures successfully verified: %10d\n", nverified); + fprintf(out, "Signatures unsuccessfully " + "verified: %10d\n", nverifyfailed); time_us = isc_time_microdiff(sign_finish, sign_start); time_ms = time_us / 1000; - printf("Signing time in seconds: %7u.%03u\n", - (unsigned int) (time_ms / 1000), - (unsigned int) (time_ms % 1000)); + fprintf(out, "Signing time in seconds: %7u.%03u\n", + (unsigned int) (time_ms / 1000), + (unsigned int) (time_ms % 1000)); if (time_us > 0) { sig_ms = ((isc_uint64_t)nsigned * 1000000000) / time_us; - printf("Signatures per second: %7u.%03u\n", - (unsigned int) sig_ms / 1000, - (unsigned int) sig_ms % 1000); + fprintf(out, "Signatures per second: %7u.%03u\n", + (unsigned int) sig_ms / 1000, + (unsigned int) sig_ms % 1000); } time_us = isc_time_microdiff(timer_finish, timer_start); time_ms = time_us / 1000; - printf("Runtime in seconds: %7u.%03u\n", - (unsigned int) (time_ms / 1000), - (unsigned int) (time_ms % 1000)); + fprintf(out, "Runtime in seconds: %7u.%03u\n", + (unsigned int) (time_ms / 1000), + (unsigned int) (time_ms % 1000)); } int main(int argc, char *argv[]) { int i, ch; char *startstr = NULL, *endstr = NULL, *classname = NULL; + char *dnskey_endstr = NULL; char *origin = NULL, *file = NULL, *output = NULL; char *inputformatstr = NULL, *outputformatstr = NULL; char *serialformatstr = NULL; @@ -3447,20 +3039,20 @@ main(int argc, char *argv[]) { #endif unsigned int eflags; isc_boolean_t free_output = ISC_FALSE; - int tempfilelen; + int tempfilelen = 0; dns_rdataclass_t rdclass; isc_task_t **tasks = NULL; isc_buffer_t b; int len; hashlist_t hashlist; - isc_boolean_t smartsign = ISC_FALSE; isc_boolean_t make_keyset = ISC_FALSE; isc_boolean_t set_salt = ISC_FALSE; isc_boolean_t set_optout = ISC_FALSE; isc_boolean_t set_iter = ISC_FALSE; + isc_boolean_t nonsecify = ISC_FALSE; #define CMDLINE_FLAGS \ - "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:pPr:s:ST:tuUv:xz" + "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xzZ:" /* * Process memory debugging argument first. @@ -3546,6 +3138,10 @@ main(int argc, char *argv[]) { dsdir, isc_result_totext(result)); break; + case 'D': + output_dnssec_only = ISC_TRUE; + break; + case 'E': engine = isc_commandline_argument; break; @@ -3556,6 +3152,8 @@ main(int argc, char *argv[]) { case 'f': output = isc_commandline_argument; + if (strcmp(output, "-") == 0) + output_stdout = ISC_TRUE; break; case 'g': @@ -3604,6 +3202,17 @@ main(int argc, char *argv[]) { dskeyfile[ndskeys++] = isc_commandline_argument; break; + case 'L': + snset = ISC_TRUE; + endp = NULL; + serialnum = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "source serial number " + "must be numeric"); + exit(1); + } + break; + case 'l': len = strlen(isc_commandline_argument); isc_buffer_init(&b, isc_commandline_argument, len); @@ -3646,6 +3255,10 @@ main(int argc, char *argv[]) { pseudorandom = ISC_TRUE; break; + case 'R': + remove_orphans = ISC_TRUE; + break; + case 'r': setup_entropy(mctx, isc_commandline_argument, &ectx); break; @@ -3683,6 +3296,10 @@ main(int argc, char *argv[]) { fatal("verbose level must be numeric"); break; + case 'X': + dnskey_endstr = isc_commandline_argument; + break; + case 'x': keyset_kskonly = ISC_TRUE; break; @@ -3705,6 +3322,10 @@ main(int argc, char *argv[]) { fprintf(stderr, "%s: unhandled option -%c\n", program, isc_commandline_option); exit(1); + case 'Z': /* Undocumented test options */ + if (!strcmp(isc_commandline_argument, "nonsecify")) + nonsecify = ISC_TRUE; + break; } } @@ -3730,11 +3351,19 @@ main(int argc, char *argv[]) { } else starttime = now - 3600; /* Allow for some clock skew. */ - if (endstr != NULL) { + if (endstr != NULL) endtime = strtotime(endstr, now, starttime); - } else + else endtime = starttime + (30 * 24 * 60 * 60); + if (dnskey_endstr != NULL) { + dnskey_endtime = strtotime(dnskey_endstr, now, starttime); + if (endstr != NULL && dnskey_endtime == endtime) + fprintf(stderr, "WARNING: -e and -X were both set, " + "but have identical values.\n"); + } else + dnskey_endtime = endtime; + if (cycle == -1) cycle = (endtime - starttime) / 4; @@ -3777,16 +3406,36 @@ main(int argc, char *argv[]) { inputformat = dns_masterformat_text; else if (strcasecmp(inputformatstr, "raw") == 0) inputformat = dns_masterformat_raw; - else - fatal("unknown file format: %s\n", inputformatstr); + else if (strncasecmp(inputformatstr, "raw=", 4) == 0) { + inputformat = dns_masterformat_raw; + fprintf(stderr, + "WARNING: input format version ignored\n"); + } else + fatal("unknown file format: %s", inputformatstr); + } if (outputformatstr != NULL) { - if (strcasecmp(outputformatstr, "text") == 0) + if (strcasecmp(outputformatstr, "text") == 0) { outputformat = dns_masterformat_text; - else if (strcasecmp(outputformatstr, "raw") == 0) + } else if (strcasecmp(outputformatstr, "full") == 0) { + outputformat = dns_masterformat_text; + masterstyle = &dns_master_style_full; + } else if (strcasecmp(outputformatstr, "raw") == 0) { outputformat = dns_masterformat_raw; - else + } else if (strncasecmp(outputformatstr, "raw=", 4) == 0) { + char *end; + outputformat = dns_masterformat_raw; + + outputformat = dns_masterformat_raw; + rawversion = strtol(outputformatstr + 4, &end, 10); + if (end == outputformatstr + 4 || *end != '\0' || + rawversion > 1U) { + fprintf(stderr, + "unknown raw format version\n"); + exit(1); + } + } else fatal("unknown file format: %s\n", outputformatstr); } @@ -3803,6 +3452,12 @@ main(int argc, char *argv[]) { serialformatstr); } + if (output_dnssec_only && outputformat != dns_masterformat_text) + fatal("option -D can only be used with \"-O text\"\n"); + + if (output_dnssec_only && serialformat != SOA_SERIAL_KEEP) + fatal("option -D can only be used with \"-N keep\"\n"); + result = dns_master_stylecreate(&dsstyle, DNS_STYLEFLAG_NO_TTL, 0, 24, 0, 0, 0, 8, mctx); check_result(result, "dns_master_stylecreate"); @@ -3826,18 +3481,6 @@ main(int argc, char *argv[]) { else set_nsec3params(update_chain, set_salt, set_optout, set_iter); - if (IS_NSEC3) { - isc_boolean_t answer; - hash_length = dns_nsec3_hashlength(dns_hash_sha1); - hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2, - hash_length); - result = dns_nsec_nseconly(gdb, gversion, &answer); - check_result(result, "dns_nsec_nseconly"); - if (answer) - fatal("NSEC3 generation requested with " - "NSEC only DNSKEY"); - } - /* * We need to do this early on, as we start messing with the list * of keys rather early. @@ -3890,6 +3533,22 @@ main(int argc, char *argv[]) { if (IS_NSEC3) { unsigned int max; + isc_boolean_t answer; + + hash_length = dns_nsec3_hashlength(dns_hash_sha1); + hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2, + hash_length); + result = dns_nsec_nseconly(gdb, gversion, &answer); + if (result == ISC_R_NOTFOUND) + fprintf(stderr, "%s: warning: NSEC3 generation " + "requested with no DNSKEY; ignoring\n", + program); + else if (result != ISC_R_SUCCESS) + check_result(result, "dns_nsec_nseconly"); + else if (answer) + fatal("NSEC3 generation requested with " + "NSEC-only DNSKEY"); + result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max); check_result(result, "dns_nsec3_maxiterations()"); if (nsec3iter > max) @@ -3916,11 +3575,13 @@ main(int argc, char *argv[]) { remove_duplicates(); - if (IS_NSEC3) - nsec3ify(dns_hash_sha1, nsec3iter, salt, salt_length, - &hashlist); - else - nsecify(); + if (!nonsecify) { + if (IS_NSEC3) + nsec3ify(dns_hash_sha1, nsec3iter, salt, salt_length, + &hashlist); + else + nsecify(); + } if (!nokeys) { writeset("dsset-", dns_rdatatype_ds); @@ -3931,24 +3592,29 @@ main(int argc, char *argv[]) { } } - tempfilelen = strlen(output) + 20; - tempfile = isc_mem_get(mctx, tempfilelen); - if (tempfile == NULL) - fatal("out of memory"); + if (output_stdout) { + fp = stdout; + if (outputformatstr == NULL) + masterstyle = &dns_master_style_full; + } else { + tempfilelen = strlen(output) + 20; + tempfile = isc_mem_get(mctx, tempfilelen); + if (tempfile == NULL) + fatal("out of memory"); - result = isc_file_mktemplate(output, tempfile, tempfilelen); - check_result(result, "isc_file_mktemplate"); + result = isc_file_mktemplate(output, tempfile, tempfilelen); + check_result(result, "isc_file_mktemplate"); - fp = NULL; - if (outputformat == dns_masterformat_text) - result = isc_file_openunique(tempfile, &fp); - else - result = isc_file_bopenunique(tempfile, &fp); - if (result != ISC_R_SUCCESS) - fatal("failed to open temporary output file: %s", - isc_result_totext(result)); - removefile = ISC_TRUE; - setfatalcallback(&removetempfile); + if (outputformat == dns_masterformat_text) + result = isc_file_openunique(tempfile, &fp); + else + result = isc_file_bopenunique(tempfile, &fp); + if (result != ISC_R_SUCCESS) + fatal("failed to open temporary output file: %s", + isc_result_totext(result)); + removefile = ISC_TRUE; + setfatalcallback(&removetempfile); + } print_time(fp); print_version(fp); @@ -4005,29 +3671,42 @@ main(int argc, char *argv[]) { isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *)); postsign(); TIME_NOW(&sign_finish); - verifyzone(); + + if (!disable_zone_check) + verifyzone(gdb, gversion, gorigin, mctx, + ignore_kskflag, keyset_kskonly); if (outputformat != dns_masterformat_text) { - result = dns_master_dumptostream2(mctx, gdb, gversion, + dns_masterrawheader_t header; + dns_master_initrawheader(&header); + if (rawversion == 0U) + header.flags = DNS_MASTERRAW_COMPAT; + else if (snset) { + header.flags = DNS_MASTERRAW_SOURCESERIALSET; + header.sourceserial = serialnum; + } + result = dns_master_dumptostream3(mctx, gdb, gversion, masterstyle, outputformat, - fp); - check_result(result, "dns_master_dumptostream2"); + &header, fp); + check_result(result, "dns_master_dumptostream3"); } - result = isc_stdio_close(fp); - check_result(result, "isc_stdio_close"); - removefile = ISC_FALSE; - - result = isc_file_rename(tempfile, output); - if (result != ISC_R_SUCCESS) - fatal("failed to rename temp file to %s: %s\n", - output, isc_result_totext(result)); - DESTROYLOCK(&namelock); if (printstats) DESTROYLOCK(&statslock); - printf("%s\n", output); + if (!output_stdout) { + result = isc_stdio_close(fp); + check_result(result, "isc_stdio_close"); + removefile = ISC_FALSE; + + result = isc_file_rename(tempfile, output); + if (result != ISC_R_SUCCESS) + fatal("failed to rename temp file to %s: %s\n", + output, isc_result_totext(result)); + + printf("%s\n", output); + } dns_db_closeversion(gdb, &gversion, ISC_FALSE); dns_db_detach(&gdb); @@ -4038,7 +3717,8 @@ main(int argc, char *argv[]) { dns_dnsseckey_destroy(mctx, &key); } - isc_mem_put(mctx, tempfile, tempfilelen); + if (tempfilelen != 0) + isc_mem_put(mctx, tempfile, tempfilelen); if (free_output) isc_mem_free(mctx, output); |