dnssec-signzone.c revision 813b34ebecba1293ccfb91e52e3c69d5c819073d
/*
* Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1999-2003 Internet Software Consortium.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Portions Copyright (C) 1995-2000 by Network Associates, Inc.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dnssec-signzone.c,v 1.227 2009/08/14 01:07:00 each Exp $ */
/*! \file */
#include <config.h>
#include <stdlib.h>
#include <time.h>
#include <isc/commandline.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/keyvalues.h>
#include <dns/masterdump.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdataclass.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include "dnssectool.h"
#ifndef PATH_MAX
#endif
const char *program = "dnssec-signzone";
int verbose;
typedef struct hashlist hashlist_t;
static int nsec_datatype = dns_rdatatype_nsec;
#define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
#define BUFSIZE 2048
#define MAXDSKEYS 8
#define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
#define SOA_SERIAL_KEEP 0
#define SOA_SERIAL_INCREMENT 1
#define SOA_SERIAL_UNIXTIME 2
typedef struct signer_event sevent_t;
struct signer_event {
};
static dns_dnsseckeylist_t keylist;
static unsigned int keycount = 0;
static int cycle = -1;
static int jitter = 0;
static dns_ttl_t zone_soa_min_ttl;
static const dns_master_style_t *masterstyle;
static unsigned int nverified = 0, nverifyfailed = 0;
static int nsec3flags = 0;
static unsigned int ntasks = 0;
static dns_fixedname_t dlv_fixed;
static unsigned int serialformat = SOA_SERIAL_KEEP;
static unsigned int hash_length = 0;
static int keyttl = 3600;
if (printstats) { \
counter++; \
}
static void
static isc_boolean_t
static void
if (outputformat != dns_masterformat_text)
return;
masterstyle, fp);
}
/*%
* Sign the given RRset with given key, and add the signature record to the
* given tuple.
*/
static void
{
char keystr[KEY_FORMATSIZE];
isc_buffer_t b;
if (result != ISC_R_SUCCESS) {
char keystr[KEY_FORMATSIZE];
fatal("dnskey '%s' failed to sign data: %s",
}
if (tryverify) {
if (result == ISC_R_SUCCESS) {
} else {
}
}
&tuple);
}
static inline isc_boolean_t
}
static inline isc_boolean_t
}
static inline isc_boolean_t
}
static inline isc_boolean_t
}
/*%
* Find the key that generated an RRSIG, if it is in the key list. If
* so, return a pointer to it, otherwise return NULL.
*
* No locking is performed here, this must be done by the caller.
*/
static dns_dnsseckey_t *
return (key);
}
return (NULL);
}
/*%
* Finds the key that generated a RRSIG, if possible. First look at the keys
* that we've loaded already, and then see if there's a key on disk.
*/
static dns_dnsseckey_t *
return (key);
/*
* We did not find the key in our list. Get a write lock now, since
* we may be modifying the bits. We could do the tryupgrade() dance,
* but instead just get a write lock and check once again to see if
* it is on our list. It's possible someone else may have added it
* after all.
*/
return (key);
}
if (result != ISC_R_SUCCESS) {
return (NULL);
}
if (result == ISC_R_SUCCESS) {
} else {
}
return (key);
}
/*%
* Check to see if we expect to find a key at this name. If we see a RRSIG
* and can't find the signing key that we expect to find, we drop the rrsig.
* I'm not sure if this is completely correct, but it seems to work.
*/
static isc_boolean_t
unsigned int options = DNS_DBFIND_NOWILD;
char namestr[DNS_NAME_FORMATSIZE];
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_NXDOMAIN:
case DNS_R_NXRRSET:
return (ISC_TRUE);
case DNS_R_DELEGATION:
case DNS_R_CNAME:
case DNS_R_DNAME:
return (ISC_FALSE);
}
fatal("failure looking for '%s DNSKEY' in database: %s",
return (ISC_FALSE); /* removes a warning */
}
static inline isc_boolean_t
{
if (result == ISC_R_SUCCESS) {
return (ISC_TRUE);
} else {
return (ISC_FALSE);
}
}
/*%
* Signs a set. Goes through contortions to decide if each RRSIG should
* be dropped or retained, and then determines if any new SIGs need to
* be generated.
*/
static void
{
int arraysize;
int i;
char namestr[DNS_NAME_FORMATSIZE];
char typestr[TYPE_FORMATSIZE];
char sigstr[SIG_FORMATSIZE];
if (result == ISC_R_NOTFOUND) {
}
if (result != ISC_R_SUCCESS)
fatal("failed while looking for '%s RRSIG %s': %s",
if (!nosigs)
fatal("out of memory");
for (i = 0; i < arraysize; i++)
if (nosigs)
else
while (result == ISC_R_SUCCESS) {
else
/* rrsig is dropped and not replaced */
"invalid validity period\n",
sigstr);
/* rrsig is dropped and not replaced */
"private dnskey not found\n",
sigstr);
if (!expired)
} else if (issigningkey(key)) {
{
} else {
expired ? "expired" :
"failed to verify");
}
{
} else {
expired ? "expired" :
"failed to verify");
}
} else if (!expired) {
} else {
}
if (keep) {
&sigrdata,
&tuple);
&sigrdata,
&tuple);
}
} else {
}
if (resign) {
"resigning with dnskey");
}
}
if (result == ISC_R_NOMORE)
if (dns_rdataset_isassociated(&sigset))
{
continue;
if (!issigningkey(key))
continue;
"signing with dnskey");
}
}
}
struct hashlist {
unsigned char *hashbuf;
};
static void
l->entries = 0;
if (nodes != 0) {
l->size = 0;
} else {
l->size = 0;
}
}
static void
{
}
l->entries++;
}
static void
unsigned int hashalg, unsigned int iterations,
{
char nametext[DNS_NAME_FORMATSIZE];
unsigned int len;
size_t i;
if (verbose) {
for (i = 0 ; i < len; i++)
}
}
static int
hashlist_comp(const void *a, const void *b) {
}
static void
hashlist_sort(hashlist_t *l) {
}
static isc_boolean_t
hashlist_hasdup(hashlist_t *l) {
unsigned char *current;
/*
* Skip initial speculative wild card hashs.
*/
entries--;
}
while (entries-- > 1U) {
continue;
return (ISC_TRUE);
}
return (ISC_FALSE);
}
static const unsigned char *
hashlist_findnext(const hashlist_t *l,
const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
{
l->length, hashlist_comp);
do {
else
break;
} while (entries-- > 1);
return (next);
}
static isc_boolean_t
hashlist_exists(const hashlist_t *l,
const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
{
return (ISC_TRUE);
else
return (ISC_FALSE);
}
static void
unsigned int hashalg, unsigned int iterations,
{
char namestr[DNS_NAME_FORMATSIZE];
if (result == ISC_R_NOSPACE)
return;
if (result == ISC_R_SUCCESS) {
return;
}
if (verbose) {
}
ISC_TRUE);
}
static void
{
isc_buffer_t b;
/* allow room for a trailing slash */
isc_buffer_putstr(&b, dsdir);
isc_buffer_putstr(&b, "/");
}
isc_buffer_putstr(&b, prefix);
if (isc_buffer_availablelength(&b) == 0) {
char namestr[DNS_NAME_FORMATSIZE];
}
isc_buffer_putuint8(&b, 0);
}
/*%
* Load the DS set for a child zone, if a dsset-* file can be found.
* If not, try to find a keyset-* file from an earlier version of
* dnssec-signzone, and build DS records from that.
*/
static isc_result_t
unsigned char dsbuf[DNS_DS_BUFFERSIZE];
if (result == ISC_R_SUCCESS) {
dns_rdatatype_ds, 0, 0,
if (result == ISC_R_SUCCESS) {
dns_db_detach(&db);
return (result);
}
}
dns_db_detach(&db);
}
/* No DS records found; try again, looking for DNSKEY records */
return (ISC_R_NOTFOUND);
}
if (result != ISC_R_SUCCESS) {
dns_db_detach(&db);
return (result);
}
if (result != ISC_R_SUCCESS) {
dns_db_detach(&db);
return (result);
}
result == ISC_R_SUCCESS;
{
dns_rdata_init(&ds);
}
dns_db_detach(&db);
return (result);
}
static isc_boolean_t
return (ISC_FALSE);
if (dns_rdataset_isassociated(&nsset)) {
}
}
static isc_boolean_t
return (ISC_FALSE);
if (dns_rdataset_isassociated(&dsset))
}
/*%
* Signs all records at a name.
*/
static void
char namestr[DNS_NAME_FORMATSIZE];
/*
* Determine if this is a delegation point.
*/
/*
* Now iterate through the rdatasets.
*/
while (result == ISC_R_SUCCESS) {
/* If this is a RRSIG set, skip it. */
goto skip;
/*
* If this name is a delegation point, skip all records
* except NSEC and DS sets. Otherwise check that there
* isn't a DS record.
*/
if (isdelegation) {
goto skip;
char namebuf[DNS_NAME_FORMATSIZE];
fatal("'%s': found DS RRset without NS RRset\n",
namebuf);
}
skip:
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration for name '%s' failed: %s",
if (result != ISC_R_SUCCESS)
fatal("failed to delete SIGs at node '%s': %s",
if (result != ISC_R_SUCCESS)
fatal("failed to add SIGs at node '%s': %s",
}
static inline isc_boolean_t
while (result == ISC_R_SUCCESS) {
if (!active)
else
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
/*%
* The node is empty of everything but NSEC / RRSIG records.
*/
result == ISC_R_SUCCESS;
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
} else {
/*
* Delete RRSIGs for types that no longer exist.
*/
result == ISC_R_SUCCESS;
if (type != dns_rdatatype_rrsig)
continue;
}
if (!found) {
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
covers);
"dns_db_deleterdataset(rrsig)");
} else if (result != ISC_R_NOMORE &&
result != ISC_R_SUCCESS)
fatal("rdataset iteration failed: %s",
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
#if 0
/*
* Delete all NSEC records and RRSIG(NSEC) if we are in
* NSEC3 mode and vica versa.
*/
result == ISC_R_SUCCESS;
if (type == dns_rdatatype_rrsig)
if (type == nsec_datatype ||
(type != dns_rdatatype_nsec &&
type != dns_rdatatype_nsec3))
continue;
if (covers != 0)
}
#endif
}
return (active);
}
/*%
* Extracts the minimum TTL from the SOA.
*/
static dns_ttl_t
soa_min_ttl(void) {
if (result != ISC_R_SUCCESS)
fatal("failed to find an SOA at the zone apex: %s",
return (ttl);
}
/*%
* Increment (or set if nonzero) the SOA serial
*/
static isc_result_t
if (result != ISC_R_SUCCESS)
return result;
if (result != ISC_R_SUCCESS)
goto cleanup;
if (serial) {
/* Set SOA serial to the value provided. */
new_serial = serial;
} else {
/* Increment SOA serial using RFC 1982 arithmetics */
if (new_serial == 0)
new_serial = 1;
}
/* If the new serial is not likely to cause a zone transfer
*
* RFC1982 section 7 defines the maximum increment to be
* (2^(32-1))-1. Using u_int32_t arithmetic, we can do a single
* comparison. (5 - 6 == (2^32)-1, not negative-one)
*/
if (new_serial == old_serial ||
"zone may not transfer\n", program);
dns_rdatatype_soa, 0);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
return (result);
}
/*%
* Delete any RRSIG records at a node.
*/
static void
return;
while (result == ISC_R_SUCCESS) {
dns_rdatatype_t covers = 0;
}
if (destroy) {
covers);
}
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
}
/*%
* Set up the iterator and global state before starting the tasks.
*/
static void
presign(void) {
}
/*%
* Clean up the iterator and global state after the tasks complete.
*/
static void
postsign(void) {
}
static isc_boolean_t
{
result == ISC_R_SUCCESS;
&dstkey);
if (result != ISC_R_SUCCESS)
return (ISC_FALSE);
continue;
}
if (result == ISC_R_SUCCESS)
return(ISC_TRUE);
}
return (ISC_FALSE);
}
static void
unsigned char *bad_algorithms)
{
unsigned char set_algorithms[256];
char namebuf[DNS_NAME_FORMATSIZE];
char algbuf[80];
char typebuf[80];
int i;
result == ISC_R_SUCCESS;
break;
}
if (result != ISC_R_SUCCESS) {
for (i = 0; i < 256; i++)
if (ksk_algorithms[i] != 0)
bad_algorithms[i] = 1;
return;
}
result == ISC_R_SUCCESS;
continue;
}
for (i = 0; i < 256; i++)
if ((ksk_algorithms[i] != 0) &&
(set_algorithms[i] == 0)) {
bad_algorithms[i] = 1;
}
}
}
static void
unsigned char *bad_algorithms)
{
while (result == ISC_R_SUCCESS) {
}
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
}
/*%
* Verify that certain things are sane:
*
* The apex has a DNSKEY record with at least one KSK and at least
* one ZSK.
*
* The DNSKEY record was signed with at least one of the KSKs in this
* set.
*
* 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];
int i;
unsigned char revoked[256];
unsigned char standby[256];
unsigned char ksk_algorithms[256];
unsigned char zsk_algorithms[256];
unsigned char bad_algorithms[256];
#ifdef ALLOW_KSKLESS_ZONES
unsigned char self_algorithms[256];
#endif
if (disable_zone_check)
return;
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone's origin: %s",
0, 0, &rdataset, &sigrdataset);
if (result != ISC_R_SUCCESS)
fatal("cannot find DNSKEY rrset\n");
if (!dns_rdataset_isassociated(&sigrdataset))
fatal("cannot find DNSKEY RRSIGs\n");
#ifdef ALLOW_KSKLESS_ZONES
#endif
/*
* Check that the DNSKEY RR has at least one self signing KSK and
* one ZSK per algorithm in it.
*/
result == ISC_R_SUCCESS;
;
mctx)) {
char namebuf[DNS_NAME_FORMATSIZE];
char buffer[1024];
sizeof(namebuf));
fatal("revoked KSK is not self signed:\n"
"%s DNSKEY %.*s", namebuf,
}
} else {
}
mctx)) {
#ifdef ALLOW_KSKLESS_ZONES
#endif
} else {
#ifdef ALLOW_KSKLESS_ZONES
#endif
}
}
if (!goodksk) {
#ifdef ALLOW_KSKLESS_ZONES
if (!goodzsk)
fatal("no self signing keys found");
"ZSK's for active algorithm list.\n");
if (!allzsksigned)
"signed.\n");
#else
fatal("no self signed KSK's found");
#endif
}
for (i = 0; i < 256; i++) {
if (ksk_algorithms[i] != 0) {
}
}
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;
algbuf);
bad_algorithms[i] = 1;
}
/*
* Check that all the other records were signed by keys that are
* present in the DNSKEY RRSET.
*/
while (!done) {
}
while (result == ISC_R_SUCCESS) {
nextname);
if (result != ISC_R_SUCCESS)
break;
{
continue;
}
break;
}
if (result == ISC_R_NOMORE) {
} else if (result != ISC_R_SUCCESS)
fatal("iterating through the database failed: %s",
}
result == ISC_R_SUCCESS;
}
/*
* 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)
"for the following algorithms:");
}
}
if (!first) {
fatal("DNSSEC completeness test failed.");
}
if (goodksk) {
/*
* Print the success summary.
*/
for (i = 0; i < 256; i++) {
if ((zsk_algorithms[i] != 0) ||
(ksk_algorithms[i] != 0) ||
"KSKs: %u active, %u revoked, %u "
"stand-by\n", algbuf,
zsk_algorithms[i], ksk_algorithms[i],
}
}
}
}
/*%
* Sign the apex of the zone.
* Note the origin may not be the first node if there are out of zone
* records.
*/
static void
signapex(void) {
if (result == ISC_R_NOMORE)
else if (result != ISC_R_SUCCESS)
fatal("failure iterating database: %s",
}
/*%
* Assigns a node to a worker thread. This is protected by the master task's
* lock.
*/
static void
static unsigned int ended = 0; /* Protected by namelock. */
if (shuttingdown)
return;
if (finished) {
ended++;
}
goto unlock;
}
fatal("out of memory");
while (!found) {
if (result != ISC_R_SUCCESS)
fatal("failure iterating database: %s",
/*
* The origin was handled by signapex().
*/
goto next;
}
/*
* Sort the zone data from the glue and out-of-zone data.
* For NSEC zones nodes with zone data have NSEC records.
* For NSEC3 zones the NSEC3 nodes are zone data but
* outside of the zone name space. For the rest we need
* to track the bottom of zone cuts.
* Nodes which don't need to be signed are dumped here.
*/
nsec_datatype, 0, 0,
if (dns_rdataset_isassociated(&nsec))
if (result == ISC_R_SUCCESS) {
} else if (nsec_datatype == dns_rdatatype_nsec3) {
if (!OPTOUT(nsec3flags) ||
} else
}
}
if (!found) {
}
next:
if (result == ISC_R_NOMORE) {
break;
} else if (result != ISC_R_SUCCESS)
fatal("failure iterating database: %s",
}
if (!found) {
ended++;
}
goto unlock;
}
fatal("failed to allocate event\n");
}
/*%
* Start a worker task
*/
static void
}
/*%
* Write a node to the output file, and restart the worker task.
*/
static void
}
/*%
* Sign a database node.
*/
static void
fatal("failed to allocate event\n");
}
/*%
* Update / remove the DS RRset. Preserve RRSIG(DS) if possible.
*/
static void
if (result == ISC_R_SUCCESS) {
dns_rdatatype_ds, 0);
}
if (result == ISC_R_SUCCESS) {
} else if (dns_rdataset_isassociated(&sigdsset)) {
}
}
/*%
* Generate NSEC records for the zone.
*/
static void
nsecify(void) {
isc_uint32_t nsttl = 0;
while (!done) {
if (generateds)
}
while (result == ISC_R_SUCCESS) {
nextname);
if (result != ISC_R_SUCCESS)
break;
if (!active) {
continue;
}
{
continue;
}
break;
}
if (result == ISC_R_NOMORE) {
} else if (result != ISC_R_SUCCESS)
fatal("iterating through the database failed: %s",
}
}
/*%
* Does this node only contain NSEC3 records or RRSIG records or is empty.
*/
static isc_boolean_t
while (result == ISC_R_SUCCESS) {
} else
}
if (result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
return (answer);
}
static void
unsigned int iterations)
{
isc_buffer_t b;
nsec3param.flags = 0;
&nsec3param, &b);
if (result == DNS_R_UNCHANGED)
}
static void
{
unsigned char hash[NSEC3_MAX_HASH_LENGTH];
const unsigned char *nexthash;
unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
char namebuf[DNS_NAME_FORMATSIZE];
salt, salt_length);
nsec3buffer, &rdata);
0, NULL);
if (result == DNS_R_UNCHANGED)
}
/*%
* Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
*
* Extract the hash from the first label of 'name' then see if it
* is in hashlist. If 'name' is not in the hashlist then delete the
* any NSEC3 records which have the same parameters as the chain we
* are building.
*
* XXXMPA Should we also check that it of the form <hash>.<origin>?
*/
static void
unsigned int hashalg, unsigned int iterations,
{
/*
* Get the first label.
*/
/*
* We want just the label contents.
*/
/*
* Decode base32hex string.
*/
if (result != ISC_R_SUCCESS)
return;
return;
/*
* Verify that the NSEC3 parameters match the current ones
* otherwise we are dealing with a different NSEC3 chain.
*/
if (result != ISC_R_SUCCESS)
return;
/*
* Delete any matching NSEC3 records which have parameters that
* match the NSEC3 chain we are building.
*/
result == ISC_R_SUCCESS;
break;
&delrdataset, 0, NULL);
}
if (result != ISC_R_NOMORE)
if (!delete_rrsigs)
return;
/*
* Delete the NSEC3 RRSIGs
*/
}
/*
* Generate NSEC3 records for the zone.
*/
static void
{
isc_uint32_t nsttl = 0;
int order;
/*
* Walk the zone generating the hash names.
*/
while (!done) {
while (result == ISC_R_SUCCESS) {
nextname);
if (result != ISC_R_SUCCESS)
break;
if (!active) {
continue;
}
continue;
}
if (generateds)
if (OPTOUT(nsec3flags) &&
continue;
}
}
break;
}
if (result == ISC_R_NOMORE) {
} else if (result != ISC_R_SUCCESS)
fatal("iterating through the database failed: %s",
/*
* Add hashs for empty nodes. Use closest encloser logic.
* The closest encloser either has data or is a empty
* node for another <name,nextname> span so we don't add
* it here. Empty labels on nextname are within the span.
*/
salt, salt_length);
count--;
}
}
/*
* We have all the hashes now so we can sort them.
*/
/*
* Check for duplicate hashes. If found the salt needs to
* be changed.
*/
if (hashlist_hasdup(hashlist))
fatal("Duplicate hash detected. Pick a different salt.");
/*
* Generate the nsec3 records.
*/
while (!done) {
while (result == ISC_R_SUCCESS) {
nextname);
if (result != ISC_R_SUCCESS)
break;
/*
* Cleanout NSEC3 RRsets which don't exist in the
* hash table.
*/
/*
* Skip NSEC3 only nodes when looking for the next
* node in the zone. Also skips now empty nodes.
*/
continue;
}
continue;
}
if (OPTOUT(nsec3flags) &&
continue;
}
}
break;
}
if (result == ISC_R_NOMORE) {
} else if (result != ISC_R_SUCCESS)
fatal("iterating through the database failed: %s",
/*
* We need to pause here to release the lock on the database.
*/
/*
* Add NSEC3's for empty nodes. Use closest encloser logic.
*/
count--;
}
}
}
/*%
* Load the zone file from disk
*/
static void
isc_buffer_t b;
int len;
isc_buffer_add(&b, len);
if (result != ISC_R_SUCCESS)
fatal("failed converting name '%s' to dns format: %s",
fatal("failed loading zone from '%s': %s",
}
/*%
* Finds all public zone keys in the zone, and attempts to load the
* private keys from disk.
*/
static void
unsigned int nkeys, i;
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone's origin: %s",
/* Preserve the TTL of the DNSKEY RRset, if any */
dns_rdatatype_dnskey, 0, 0,
if (result == ISC_R_SUCCESS) {
}
/* Load keys corresponding to the existing DNSKEY RRset */
if (result == ISC_R_NOTFOUND) {
goto cleanup;
}
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone keys: %s",
for (i = 0; i < nkeys; i++) {
}
}
/*%
* Finds all public zone keys in the zone.
*/
static void
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone's origin: %s",
dns_rdatatype_dnskey, 0, 0, &rdataset,
NULL);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
while (result == ISC_R_SUCCESS) {
&pubkey);
if (result != ISC_R_SUCCESS)
goto next;
if (!dst_key_iszonekey(pubkey)) {
goto next;
}
next:
}
if (currentversion != NULL)
}
static isc_result_t
unsigned char data[DST_KEY_MAXSIZE];
isc_buffer_t b;
isc_region_t r;
isc_buffer_usedregion(&b, &r);
dns_rdatatype_dnskey, &r);
return (ISC_R_SUCCESS);
}
static void
char name[DNS_NAME_FORMATSIZE];
char alg[80];
if (result == ISC_R_NOTFOUND)
/*
* For each key in matchkeys, see if it has a match in keylist.
* - If not, and if the metadata says it should be published:
* add it to keylist and to the DNSKEY set
* - If so, and if the metadata says it should be removed:
* remove it from keylist and from the DNSKEY set
* - Otherwise, make sure keylist has up-to-date metadata
*
* (XXXEACH: logic is needed to make sure revoked keys
* can be matched correctly with nonrevoked)
*/
break;
}
/*
* No matching key found in keylist, so move the key
* we found into keylist
*/
/* move key from matchkeys to keylist */
continue;
}
/* Match found: remove it or update it as needed */
if (key1->hint_remove) {
"DNSKEY RRset.\n",
} else {
}
}
/*
* If a key was not in the zone already and needs to be published,
* add it now.
*/
continue;
"ZSK",
"file" :
"repository");
/* add key to the zone */
} else {
"ZSK",
}
}
/* free matchkeys */
while (!ISC_LIST_EMPTY(matchkeys)) {
}
if (result != ISC_R_SUCCESS)
fatal("failed to delete DNSKEYs at node '%s': %s",
if (result != ISC_R_SUCCESS)
fatal("failed to add DNSKEYs at node '%s': %s",
}
static void
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone's origin: %s",
dns_rdatatype_dnskey, 0, 0, &rdataset,
NULL);
if (result != ISC_R_SUCCESS)
fatal("failed to find keys at the zone apex: %s",
while (result == ISC_R_SUCCESS) {
} else
}
if (!have_non_ksk && !ignore_kskflag) {
if (disable_zone_check)
"supply a ZSK or use '-z'.\n",
program);
else
fatal("No non-KSK DNSKEY found; "
"supply a ZSK or use '-z'.");
}
}
static void
char *filename;
char namestr[DNS_NAME_FORMATSIZE];
isc_buffer_t b;
isc_region_t r;
unsigned char dsbuf[DNS_DS_BUFFERSIZE];
unsigned char keybuf[DST_KEY_MAXSIZE];
unsigned int filenamelen;
const dns_master_style_t *style =
isc_buffer_putuint8(&namebuf, 0);
fatal("out of memory");
else
filename[0] = 0;
break;
}
break;
}
if (type == dns_rdatatype_dlv) {
unsigned int labels;
} else
{
continue;
dns_rdata_init(&ds);
isc_buffer_usedregion(&b, &r);
if (type != dns_rdatatype_dnskey) {
if (type == dns_rdatatype_dlv)
if (type == dns_rdatatype_dlv)
} else
}
dns_db_detach(&db);
}
static void
if (outputformat != dns_masterformat_text)
return;
}
static void
if (outputformat != dns_masterformat_text)
return;
}
static void
usage(void) {
"\t\tfiles for the zone and determines they are to\n"
"\t\tbe used\n");
"\t\tfrom child zones' dsset files\n");
"(now + 30 days)\n");
"if < interval from end ( (end-start)/4 )\n");
"(zonefile + .signed)\n");
"\t\twith older versions of dnssec-signzone -g\n");
exit(0);
}
static void
removetempfile(void) {
if (removefile)
}
static void
printf("Runtime in seconds: %7u.%03u\n",
(unsigned int) (runtime_ms / 1000),
(unsigned int) (runtime_ms % 1000));
if (runtime_us > 0) {
printf("Signatures per second: %7u.%03u\n",
(unsigned int) sig_ms / 1000,
(unsigned int) sig_ms % 1000);
}
}
int
int i, ch;
char *serialformatstr = NULL;
int ndskeys = 0;
char *endp;
unsigned int eflags;
int tempfilelen;
isc_buffer_t b;
int len;
unsigned int iterations = 100U;
size_t salt_length = 0;
unsigned char saltbuf[255];
#define CMDLINE_FLAGS "3:AaCc:Dd:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:pPr:s:ST:tUv:z"
/*
* Process memory debugging argument first.
*/
switch (ch) {
case 'm':
break;
default:
break;
}
}
if (result != ISC_R_SUCCESS)
fatal("out of memory");
switch (ch) {
case '3':
char *sarg;
sizeof(saltbuf));
"isc_hex_decodestring(salt)");
} else {
salt_length = 0;
}
break;
case 'A':
break;
case 'a':
break;
case 'C':
break;
case 'c':
break;
case 'd':
fatal("DS directory must be non-empty string");
break;
case 'K':
break;
case 'e':
break;
case 'f':
break;
case 'g':
break;
case 'H':
&endp, 0);
if (*endp != '\0')
fatal("iterations must be numeric");
if (iterations > 0xffffU)
fatal("iterations too big");
break;
case 'h':
usage();
break;
case 'i':
fatal("cycle period must be numeric and "
"positive");
break;
case 'I':
break;
case 'j':
fatal("jitter must be numeric and positive");
break;
case 'k':
fatal("too many key-signing keys specified");
break;
case 'l':
isc_buffer_add(&b, len);
break;
case 'm':
break;
case 'n':
fatal("number of cpus must be numeric");
break;
case 'N':
break;
case 'o':
break;
case 'O':
break;
case 'p':
break;
case 'P':
break;
case 'r':
break;
case 's':
break;
case 'S':
break;
case 'T':
if (*endp != '\0')
fatal("key TTL must be numeric");
break;
case 't':
break;
case 'U': /* Undocumented for testing only. */
break;
case 'v':
if (*endp != '\0')
fatal("verbose level must be numeric");
break;
case 'z':
break;
case 'F':
/* Reserved for FIPS mode */
/* FALLTHROUGH */
case '?':
if (isc_commandline_option != '?')
usage();
break;
default:
exit(1);
}
}
if (!pseudorandom)
if (result != ISC_R_SUCCESS)
fatal("could not create hash context");
if (result != ISC_R_SUCCESS)
fatal("could not initialize dst");
} else
} else
if (cycle == -1)
if (ntasks == 0)
directory = ".";
if (argc < 1)
usage();
argc -= 1;
argv += 1;
fatal("out of memory");
}
if (inputformatstr != NULL) {
else
}
if (outputformatstr != NULL) {
else
}
if (serialformatstr != NULL) {
else
}
if (IS_NSEC3) {
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.
*/
isc_rwlock_init(&keylist_lock, 0, 0);
if (argc == 0) {
} else {
for (i = 0; i < argc; i++) {
if (result != ISC_R_SUCCESS)
{
if (!dst_key_isprivate(dkey))
fatal("cannot sign zone with "
"non-private dnskey %s",
argv[i]);
break;
}
}
} else
}
}
for (i = 0; i < ndskeys; i++) {
if (result != ISC_R_SUCCESS)
{
/* Override key flags. */
dst_key_free(&dkey);
break;
}
}
/* Override dnskey flags. */
}
}
/*
* If we're doing smart signing, look in the key repository for
* key files with metadata, and merge them with the keylist
* we have now.
*/
if (smartsign)
/* Now enumerate the key list */
}
if (keycount == 0) {
if (disable_zone_check)
"or found\n", program);
else
fatal("No signing keys specified or found.");
}
if (IS_NSEC3) {
unsigned int max;
if (iterations > max)
fatal("NSEC3 iterations too big for weakest DNSKEY "
"strength. Maximum iterations allowed %u.", max);
}
switch (serialformat) {
case SOA_SERIAL_INCREMENT:
setsoaserial(0);
break;
case SOA_SERIAL_UNIXTIME:
break;
case SOA_SERIAL_KEEP:
default:
/* do nothing */
break;
}
if (IS_NSEC3)
&hashlist);
else
nsecify();
if (!nokeys) {
if (make_keyset)
}
}
fatal("out of memory");
if (result != ISC_R_SUCCESS)
fatal("failed to open temporary output file: %s",
print_time(fp);
if (result != ISC_R_SUCCESS)
fatal("failed to create task manager: %s",
if (result != ISC_R_SUCCESS)
fatal("out of memory");
for (i = 0; i < (int)ntasks; i++) {
if (result != ISC_R_SUCCESS)
fatal("failed to create task: %s",
}
if (printstats)
presign();
signapex();
if (!finished) {
/*
* There is more work to do. Spread it out over multiple
* processors if possible.
*/
for (i = 0; i < (int)ntasks; i++) {
tasks[i]);
if (result != ISC_R_SUCCESS)
fatal("failed to start task: %s",
}
(void)isc_app_run();
if (!finished)
fatal("process aborted by user");
} else
for (i = 0; i < (int)ntasks; i++)
isc_task_detach(&tasks[i]);
postsign();
verifyzone();
if (outputformat != dns_masterformat_text) {
fp);
}
if (result != ISC_R_SUCCESS)
fatal("failed to rename temp file to %s: %s\n",
if (printstats)
dns_db_detach(&gdb);
while (!ISC_LIST_EMPTY(keylist)) {
}
if (free_output)
if (verbose > 10)
(void) isc_app_finish();
if (printstats) {
}
return (0);
}