]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1328. [func] DS (delegation signer) support.
authorMark Andrews <marka@isc.org>
Mon, 17 Jun 2002 04:01:37 +0000 (04:01 +0000)
committerMark Andrews <marka@isc.org>
Mon, 17 Jun 2002 04:01:37 +0000 (04:01 +0000)
24 files changed:
CHANGES
bin/dnssec/Makefile.in
bin/dnssec/dnssec-signzone.c
bin/named/query.c
bin/tests/system/conf.sh.in
bin/tests/system/dnssec/ns1/sign.sh
bin/tests/system/dnssec/ns2/sign.sh
bin/tests/system/dnssec/ns3/sign.sh
bin/tests/system/dnssec/tests.sh
lib/dns/Makefile.in
lib/dns/ds.c [new file with mode: 0644]
lib/dns/include/dns/Makefile.in
lib/dns/include/dns/ds.h [new file with mode: 0644]
lib/dns/include/dns/rdata.h
lib/dns/include/dns/result.h
lib/dns/include/dns/validator.h
lib/dns/rbtdb.c
lib/dns/rdata.c
lib/dns/rdata/generic/ds_43.c [new file with mode: 0644]
lib/dns/rdata/generic/ds_43.h [new file with mode: 0644]
lib/dns/resolver.c
lib/dns/result.c
lib/dns/validator.c
version

diff --git a/CHANGES b/CHANGES
index adec805082c30911116c7b01c3ac5924ee23a0f5..d4ec2a17d9926aeb361c51651796243dd0d4e54d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+1328.  [func]          DS (delegation signer) support.
+
 1327.  [bug]           nsupdate: allow white space base64 key data.
 
 1326.  [bug]           Badly encoded LOC record when the size, horizontal
index 6dbf709236342648853353cdf4b29ed6852e9fd2..d9b363bfa49a74d843bb70f4a695edd64f53e917 100644 (file)
@@ -13,7 +13,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.21 2001/11/06 20:05:00 bwelling Exp $
+# $Id: Makefile.in,v 1.22 2002/06/17 04:01:03 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -39,26 +39,15 @@ DEPLIBS =   ${DNSDEPLIBS} ${ISCDEPLIBS}
 LIBS =         ${DNSLIBS} ${ISCLIBS} @LIBS@
 
 # Alphabetically
-TARGETS =      dnssec-keygen \
-               dnssec-makekeyset \
-               dnssec-signkey \
-               dnssec-signzone
+TARGETS =      dnssec-keygen dnssec-signzone
 
 OBJS =         dnssectool.@O@
 
-SRCS =         dnssec-keygen.c dnssec-makekeyset.c \
-               dnssec-signkey.c dnssec-signzone.c \
-               dnssectool.c
+SRCS =         dnssec-keygen.c dnssec-signzone.c dnssectool.c
 
-MANPAGES =     dnssec-keygen.8 \
-               dnssec-makekeyset.8 \
-               dnssec-signkey.8 \
-               dnssec-signzone.8
+MANPAGES =     dnssec-keygen.8 dnssec-signzone.8
 
-HTMLPAGES =    dnssec-keygen.html \
-               dnssec-makekeyset.html \
-               dnssec-signkey.html \
-               dnssec-signzone.html
+HTMLPAGES =    dnssec-keygen.html dnssec-signzone.html
 
 MANOBJS =      ${MANPAGES} ${HTMLPAGES}
 
@@ -67,12 +56,6 @@ MANOBJS =    ${MANPAGES} ${HTMLPAGES}
 dnssec-keygen: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS}
        ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ dnssec-keygen.@O@ ${OBJS} ${LIBS}
 
-dnssec-makekeyset: dnssec-makekeyset.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ dnssec-makekeyset.@O@ ${OBJS} ${LIBS}
-
-dnssec-signkey: dnssec-signkey.@O@ ${OBJS} ${DEPLIBS}
-       ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ dnssec-signkey.@O@ ${OBJS} ${LIBS}
-
 dnssec-signzone.@O@: dnssec-signzone.c
        ${LIBTOOL} ${PURIFY} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" -c $<
 
index 57f2068ebc8552a502374cc1b56a9ee22e66bd67..0073f6d0403fbb9f0ff60de009cfd23f717ca67e 100644 (file)
@@ -17,7 +17,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-signzone.c,v 1.159 2002/02/20 03:33:02 marka Exp $ */
+/* $Id: dnssec-signzone.c,v 1.160 2002/06/17 04:01:05 marka Exp $ */
 
 #include <config.h>
 
@@ -42,6 +42,7 @@
 #include <dns/dbiterator.h>
 #include <dns/diff.h>
 #include <dns/dnssec.h>
+#include <dns/ds.h>
 #include <dns/fixedname.h>
 #include <dns/keyvalues.h>
 #include <dns/log.h>
@@ -65,12 +66,14 @@ const char *program = "dnssec-signzone";
 int verbose;
 
 #define BUFSIZE 2048
+#define MAXDSKEYS 8
 
 typedef struct signer_key_struct signer_key_t;
 
 struct signer_key_struct {
        dst_key_t *key;
        isc_boolean_t isdefault;
+       isc_boolean_t keysigning;
        unsigned int position;
        ISC_LINK(signer_key_t) link;
 };
@@ -106,6 +109,7 @@ static isc_taskmgr_t *taskmgr = NULL;
 static dns_db_t *gdb;                  /* The database */
 static dns_dbversion_t *gversion;      /* The database version */
 static dns_dbiterator_t *gdbiter;      /* The database iterator */
+static dns_rdataclass_t gclass;                /* The class */
 static dns_name_t *gorigin;            /* The database origin */
 static isc_task_t *master = NULL;
 static unsigned int ntasks = 0;
@@ -147,8 +151,41 @@ dumpnode(dns_name_t *name, dns_dbnode_t *node) {
        check_result(result, "dns_master_dumpnodetostream");
 }
 
+static void
+dumpdb(dns_db_t *db) {
+       dns_dbiterator_t *dbiter = NULL;
+       dns_dbnode_t *node;
+       dns_fixedname_t fname;
+       dns_name_t *name;
+       isc_result_t result;
+
+       dbiter = NULL;
+       result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+       check_result(result, "dns_db_createiterator()");
+
+       dns_fixedname_init(&fname);
+       name = dns_fixedname_name(&fname);
+       node = NULL;
+
+       for (result = dns_dbiterator_first(dbiter);
+            result == ISC_R_SUCCESS;
+            result = dns_dbiterator_next(dbiter))
+       {
+               result = dns_dbiterator_current(dbiter, &node, name);
+               check_result(result, "dns_dbiterator_current()");
+               dumpnode(name, node);
+               dns_db_detachnode(db, &node);
+       }
+       if (result != ISC_R_NOMORE)
+               fatal("iterating database: %s", isc_result_totext(result));
+
+       dns_dbiterator_destroy(&dbiter);
+}
+
 static signer_key_t *
-newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault) {
+newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault,
+            isc_boolean_t iskeysigning)
+{
        signer_key_t *key;
 
        key = isc_mem_get(mctx, sizeof(signer_key_t));
@@ -156,6 +193,7 @@ newkeystruct(dst_key_t *dstkey, isc_boolean_t isdefault) {
                fatal("out of memory");
        key->key = dstkey;
        key->isdefault = isdefault;
+       key->keysigning = iskeysigning;
        key->position = keycount++;
        ISC_LINK_INIT(key, link);
        return (key);
@@ -231,9 +269,9 @@ keythatsigned(dns_rdata_sig_t *sig) {
                                  NULL, mctx, &privkey);
        if (result == ISC_R_SUCCESS) {
                dst_key_free(&pubkey);
-               key = newkeystruct(privkey, ISC_FALSE);
+               key = newkeystruct(privkey, ISC_FALSE, ISC_FALSE);
        } else
-               key = newkeystruct(pubkey, ISC_FALSE);
+               key = newkeystruct(pubkey, ISC_FALSE, ISC_FALSE);
        ISC_LIST_APPEND(keylist, key, link);
        return (key);
 }
@@ -462,7 +500,13 @@ signset(dns_diff_t *diff, dns_dbnode_t *node, dns_name_t *name,
                unsigned char array[BUFSIZE];
                char keystr[KEY_FORMATSIZE];
 
-               if (!key->isdefault || nowsignedby[key->position])
+               if (nowsignedby[key->position])
+                       continue;
+
+               if (!(key->isdefault ||
+                     (key->keysigning &&
+                      set->type == dns_rdatatype_key &&
+                      dns_name_equal(name, gorigin))))
                        continue;
 
                key_format(key->key, keystr, sizeof(keystr));
@@ -481,36 +525,6 @@ signset(dns_diff_t *diff, dns_dbnode_t *node, dns_name_t *name,
        isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
 }
 
-/* Determine if a KEY set contains a null key */
-static isc_boolean_t
-hasnullkey(dns_rdataset_t *rdataset) {
-       isc_result_t result;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-
-       for (result = dns_rdataset_first(rdataset);
-            result == ISC_R_SUCCESS;
-            result = dns_rdataset_next(rdataset))
-       {
-               dst_key_t *key = NULL;
-
-               dns_rdata_reset(&rdata);
-               dns_rdataset_current(rdataset, &rdata);
-               result = dns_dnssec_keyfromrdata(dns_rootname,
-                                                &rdata, mctx, &key);
-               if (result != ISC_R_SUCCESS)
-                       fatal("could not convert KEY into internal " 
-                             "format: %s", isc_result_totext(result));
-               if (dst_key_isnullkey(key)) {
-                       dst_key_free(&key);
-                       return (ISC_TRUE);
-               }
-               dst_key_free(&key);
-       }
-       if (result != ISC_R_NOMORE)
-               fatal("failure looking for null keys");
-       return (ISC_FALSE);
-}
-
 static void
 opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
        dns_db_t **dbp)
@@ -545,236 +559,137 @@ opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
 }
 
 /*
- * Looks for signatures of the zone keys by the parent, and imports them
- * if found.
+ * Loads the key set for a child zone, if there is one, and builds DS records.
  */
-static void
-importparentsig(dns_diff_t *diff, dns_name_t *name, dns_rdataset_t *set) {
-       dns_db_t *newdb = NULL;
-       dns_dbnode_t *newnode = NULL;
-       dns_rdataset_t newset, sigset;
-       dns_rdata_t rdata = DNS_RDATA_INIT, newrdata = DNS_RDATA_INIT;
+static isc_result_t
+loadds(dns_name_t *name, dns_rdataset_t *dsset) {
+       dns_db_t *db = NULL;
+       dns_dbversion_t *ver = NULL;
+       dns_dbnode_t *node = NULL;
        isc_result_t result;
+       dns_rdataset_t keyset;
+       dns_rdata_t key, ds;
+       unsigned char dsbuf[DNS_DS_BUFFERSIZE];
+       dns_diff_t diff;
+       dns_difftuple_t *tuple = NULL;
 
-       dns_rdataset_init(&newset);
-       dns_rdataset_init(&sigset);
-
-       opendb("signedkey-", name, dns_db_class(gdb), &newdb);
-       if (newdb == NULL)
-               return;
-
-       result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
-       if (result != ISC_R_SUCCESS)
-               goto failure;
-       result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
-                                    0, 0, &newset, &sigset);
-       if (result != ISC_R_SUCCESS)
-               goto failure;
-
-       if (!dns_rdataset_isassociated(&newset) ||
-           !dns_rdataset_isassociated(&sigset))
-               goto failure;
-
-       if (dns_rdataset_count(set) != dns_rdataset_count(&newset)) {
-               result = DNS_R_BADDB;
-               goto failure;
-       }
+       opendb("keyset-", name, gclass, &db);
+       if (db == NULL)
+               return (ISC_R_NOTFOUND);
 
-       result = dns_rdataset_first(set);
-       check_result(result, "dns_rdataset_first()");
-       for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(set)) {
-               dns_rdataset_current(set, &rdata);
-               result = dns_rdataset_first(&newset);
-               check_result(result, "dns_rdataset_first()");
-               for (;
-                    result == ISC_R_SUCCESS;
-                    result = dns_rdataset_next(&newset))
-               {
-                       dns_rdataset_current(&newset, &newrdata);
-                       if (dns_rdata_compare(&rdata, &newrdata) == 0)
-                               break;
-                       dns_rdata_reset(&newrdata);
-               }
-               dns_rdata_reset(&newrdata);
-               dns_rdata_reset(&rdata);
-               if (result != ISC_R_SUCCESS)
-                       break;
+       result = dns_db_findnode(db, name, ISC_FALSE, &node);
+       if (result != ISC_R_SUCCESS) {
+               dns_db_detach(&db);
+               return (DNS_R_BADDB);
        }
-       if (result != ISC_R_NOMORE)
-               goto failure;
-
-       vbprintf(2, "found the parent's signature of our zone key\n");
-
-       result = dns_rdataset_first(&sigset);
-       while (result == ISC_R_SUCCESS) {
-               dns_difftuple_t *tuple = NULL;
-
-               dns_rdataset_current(&sigset, &rdata);
-               result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, 
-                                             sigset.ttl, &rdata, &tuple);
-               check_result(result, "dns_difftuple_create");
-               dns_diff_append(diff, &tuple);
-               result = dns_rdataset_next(&sigset);
-               dns_rdata_reset(&rdata);
+       dns_rdataset_init(&keyset);
+       result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_key, 0, 0,
+                                    &keyset, NULL);
+       if (result != ISC_R_SUCCESS) {
+               dns_db_detachnode(db, &node);
+               dns_db_detach(&db);
+               return (result);
        }
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
- failure:
-       if (dns_rdataset_isassociated(&newset))
-               dns_rdataset_disassociate(&newset);
-       if (dns_rdataset_isassociated(&sigset))
-               dns_rdataset_disassociate(&sigset);
-       if (newnode != NULL)
-               dns_db_detachnode(newdb, &newnode);
-       if (newdb != NULL)
-               dns_db_detach(&newdb);
-       if (result != ISC_R_SUCCESS)
-               fatal("zone signedkey file is invalid or does not match zone");
-}
-
-/*
- * Looks for our signatures of child keys.  If present, inform the caller.
- */
-static isc_boolean_t
-haschildkey(dns_name_t *name) {
-       dns_db_t *newdb = NULL;
-       dns_dbnode_t *newnode = NULL;
-       dns_rdataset_t set, sigset;
-       dns_rdata_t sigrdata = DNS_RDATA_INIT;
-       isc_result_t result;
-       isc_boolean_t found = ISC_FALSE;
-       dns_rdata_sig_t sig;
-       signer_key_t *key;
 
-       dns_rdataset_init(&set);
-       dns_rdataset_init(&sigset);
+       vbprintf(2, "found KEY records\n");
 
-       opendb("signedkey-", name, dns_db_class(gdb), &newdb);
-       if (newdb == NULL)
-               return (ISC_FALSE);
+       result = dns_db_newversion(db, &ver);
+       check_result(result, "dns_db_newversion");
 
-       result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
-       if (result != ISC_R_SUCCESS)
-               goto failure;
-       result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
-                                    0, 0, &set, &sigset);
-       if (result != ISC_R_SUCCESS)
-               goto failure;
+       dns_diff_init(mctx, &diff);
 
-       if (!dns_rdataset_isassociated(&set) ||
-           !dns_rdataset_isassociated(&sigset))
-               goto failure;
+       for (result = dns_rdataset_first(&keyset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&keyset))
+       {
+               dns_rdata_init(&key);
+               dns_rdata_init(&ds);
+               dns_rdataset_current(&keyset, &key);
+               result = dns_ds_buildrdata(name, &key, DNS_DSDIGEST_SHA1,
+                                          dsbuf, &ds);
+               check_result(result, "dns_ds_buildrdata");
 
-       result = dns_rdataset_first(&sigset);
-       check_result(result, "dns_rdataset_first()");
-       dns_rdata_init(&sigrdata);
-       for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigset)) {
-               dns_rdataset_current(&sigset, &sigrdata);
-               result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
-               if (result != ISC_R_SUCCESS)
-                       goto failure;
-               key = keythatsigned(&sig);
-               dns_rdata_freestruct(&sig);
-               if (key == NULL) {
-                       char namestr[DNS_NAME_FORMATSIZE];
-                       dns_name_format(name, namestr, sizeof(namestr));
-                       vbprintf(1, "unknown KEY in %s signedkey file\n",
-                                namestr);
-                       goto failure;
-               }
-               result = dns_dnssec_verify(name, &set, key->key,
-                                          ISC_FALSE, mctx, &sigrdata);
-               if (result == ISC_R_SUCCESS) {
-                       found = ISC_TRUE;
-                       break;
-               } else {
-                       char namestr[DNS_NAME_FORMATSIZE];
-                       dns_name_format(name, namestr, sizeof(namestr));
-                       vbprintf(1, "verifying SIG in %s signedkey file: %s\n",
-                                namestr, isc_result_totext(result));
-               }
-               dns_rdata_reset(&sigrdata);
+               result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
+                                             zonettl, &ds, &tuple);
+               check_result(result, "dns_difftuple_create");
+               dns_diff_append(&diff, &tuple);
        }
+       result = dns_diff_apply(&diff, db, ver);
+       check_result(result, "dns_diff_apply");
+       dns_diff_clear(&diff);
 
- failure:
-       if (dns_rdataset_isassociated(&set))
-               dns_rdataset_disassociate(&set);
-       if (dns_rdataset_isassociated(&sigset))
-               dns_rdataset_disassociate(&sigset);
-       if (newnode != NULL)
-               dns_db_detachnode(newdb, &newnode);
-       if (newdb != NULL)
-               dns_db_detach(&newdb);
+       dns_db_closeversion(db, &ver, ISC_TRUE);
 
-       return (found);
+       result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0, 0,
+                                    dsset, NULL);
+       check_result(result, "dns_db_findrdataset");
+
+       dns_rdataset_disassociate(&keyset);
+       dns_db_detachnode(db, &node);
+       dns_db_detach(&db);
+       return (result);
 }
 
-/*
- * There probably should be a dns_nxt_setbit, but it can get complicated if
- * the length of the bit set needs to be increased.  In this case, since the
- * NXT bit is set and both SIG and KEY are less than NXT, the easy way works.
- */
+/* XXX fix me */
 static void
-nxt_setbit(dns_rdataset_t *rdataset, dns_rdatatype_t type) {
+nxt_setbit(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdatatype_t type,
+          unsigned int val)
+{
        isc_result_t result;
        dns_rdata_t rdata = DNS_RDATA_INIT;
        dns_rdata_nxt_t nxt;
+       unsigned int newlen;
 
-       REQUIRE(type <= dns_rdatatype_nxt);
+       INSIST(type < 128);
 
        result = dns_rdataset_first(rdataset);
        check_result(result, "dns_rdataset_first()");
        dns_rdataset_current(rdataset, &rdata);
        result = dns_rdata_tostruct(&rdata, &nxt, NULL);
        check_result(result, "dns_rdata_tostruct");
-       set_bit(nxt.typebits, type, 1);
-       dns_rdata_freestruct(&nxt);
-}
 
-static void
-createnullkey(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
-             dns_ttl_t ttl)
-{
-       unsigned char keydata[4];
-       dns_rdata_t keyrdata = DNS_RDATA_INIT;
-       dns_rdata_key_t key;
-       dns_diff_t diff;
-       dns_difftuple_t *tuple = NULL;
-       isc_buffer_t b;
-       isc_result_t result;
-       char namestr[DNS_NAME_FORMATSIZE];
-
-       dns_name_format(name, namestr, sizeof(namestr));
-       vbprintf(2, "adding null key at %s\n", namestr);
-
-       key.common.rdclass = dns_db_class(db);
-       key.common.rdtype = dns_rdatatype_key;
-       ISC_LINK_INIT(&key.common, link);
-       key.mctx = NULL;
-       key.flags = DNS_KEYTYPE_NOKEY | DNS_KEYOWNER_ZONE;
-       key.protocol = DNS_KEYPROTO_DNSSEC;
-       key.algorithm = DNS_KEYALG_DSA;
-       key.datalen = 0;
-       key.data = NULL;
-       isc_buffer_init(&b, keydata, sizeof(keydata));
-       result = dns_rdata_fromstruct(&keyrdata, dns_db_class(db),
-                                     dns_rdatatype_key, &key, &b);
-       if (result != ISC_R_SUCCESS)
-               fatal("failed to build null key");
+       newlen = type / 8 + 1;
 
-       dns_diff_init(mctx, &diff);
+       if (newlen <= nxt.len)
+               set_bit(nxt.typebits, type, val);
+       else {
+               unsigned char bitmap[16];
+               unsigned char nxtdata[16 + DNS_NAME_MAXWIRE];
+               unsigned int len = newlen;
+               dns_rdata_t newrdata = DNS_RDATA_INIT;
+               isc_buffer_t b;
+               dns_diff_t diff;
+               dns_difftuple_t *tuple = NULL;
 
-       result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name, ttl,
-                                     &keyrdata, &tuple);
-       check_result(result, "dns_difftuple_create");
+               INSIST(nxt.len < sizeof(bitmap));
 
-       dns_diff_append(&diff, &tuple);
+               dns_diff_init(mctx, &diff);
+               result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name,
+                                             rdataset->ttl, &rdata, &tuple);
+               check_result(result, "dns_difftuple_create");
+               dns_diff_append(&diff, &tuple);
+
+               memset(bitmap, 0, sizeof(bitmap));
+               memcpy(bitmap, nxt.typebits, nxt.len);
+               set_bit(bitmap, type, val);
+               nxt.typebits = bitmap;
+               nxt.len = len;
+               isc_buffer_init(&b, nxtdata, sizeof(nxtdata));
+               result = dns_rdata_fromstruct(&newrdata, rdata.rdclass,
+                                             dns_rdatatype_nxt, &nxt, &b);
+               check_result(result, "dns_rdata_fromstruct");
 
-       result = dns_diff_apply(&diff, db, version);
-       check_result(result, "dns_diff_apply");
+               result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, name,
+                                             rdataset->ttl, &newrdata,
+                                             &tuple);
+               check_result(result, "dns_difftuple_create");
+               dns_diff_append(&diff, &tuple);
 
-       dns_diff_clear(&diff);
+               result = dns_diff_apply(&diff, gdb, gversion);
+               check_result(result, "dns_difftuple_apply");
+               dns_diff_clear(&diff);
+       }
+       dns_rdata_freestruct(&nxt);
 }
 
 static void
@@ -822,9 +737,8 @@ signname(dns_dbnode_t *node, dns_name_t *name) {
        dns_rdataset_t rdataset;
        dns_rdatasetiter_t *rdsiter;
        isc_boolean_t isdelegation = ISC_FALSE;
-       isc_boolean_t childkey = ISC_FALSE;
+       isc_boolean_t hasds = ISC_FALSE;
        isc_boolean_t atorigin;
-       isc_boolean_t neednullkey = ISC_FALSE;
        dns_diff_t diff;
        char namestr[DNS_NAME_FORMATSIZE];
 
@@ -842,43 +756,20 @@ signname(dns_dbnode_t *node, dns_name_t *name) {
                isdelegation = ISC_TRUE;
 
        /*
-        * If this is a delegation point, determine if we need to generate
-        * a null key.
+        * If this is a delegation point, look for a DS set.
         */
        if (isdelegation) {
-               dns_rdataset_t keyset;
-               dns_ttl_t nullkeyttl;
+               dns_rdataset_t dsset;
 
-               childkey = haschildkey(name);
-               neednullkey = ISC_TRUE;
-               nullkeyttl = zonettl;
-
-               dns_rdataset_init(&keyset);
-               result = dns_db_findrdataset(gdb, node, gversion,
-                                            dns_rdatatype_key, 0, 0, &keyset,
-                                            NULL);
-               if (result == ISC_R_SUCCESS && childkey) {
-                       if (hasnullkey(&keyset)) {
-                               fatal("%s has both a signedkey file and "
-                                     "null keys in the zone.  Aborting.",
-                                     namestr);
-                       }
-                       vbprintf(2, "child key for %s found\n", namestr);
-                       neednullkey = ISC_FALSE;
-                       dns_rdataset_disassociate(&keyset);
-               }
-               else if (result == ISC_R_SUCCESS) {
-                       if (hasnullkey(&keyset))
-                               neednullkey = ISC_FALSE;
-                       nullkeyttl = keyset.ttl;
-                       dns_rdataset_disassociate(&keyset);
-               } else if (childkey) {
-                       vbprintf(2, "child key for %s found\n", namestr);
-                       neednullkey = ISC_FALSE;
+               dns_rdataset_init(&dsset);
+               result = loadds(name, &dsset);
+               if (result == ISC_R_SUCCESS) {
+                       result = dns_db_addrdataset(gdb, node, gversion, 0,
+                                                   &dsset, 0, NULL);
+                       check_result(result, "dns_db_deleterdataset");
+                       hasds = ISC_TRUE;
+                       dns_rdataset_disassociate(&dsset);
                }
-
-               if (neednullkey)
-                       createnullkey(gdb, gversion, name, nullkeyttl);
        }
 
        /*
@@ -897,30 +788,23 @@ signname(dns_dbnode_t *node, dns_name_t *name) {
                if (rdataset.type == dns_rdatatype_sig)
                        goto skip;
 
-               /*
-                * If this is a KEY set at the apex, look for a signedkey file.
-                */
-               if (atorigin && rdataset.type == dns_rdatatype_key) {
-                       importparentsig(&diff, name, &rdataset);
-                       goto skip;
-               }
-
                /*
                 * If this name is a delegation point, skip all records
-                * except an NXT set and a KEY set containing a null key.
+                * except NXT and DS sets.
                 */
                if (isdelegation) {
-                       if (!(rdataset.type == dns_rdatatype_nxt ||
-                             (rdataset.type == dns_rdatatype_key &&
-                              hasnullkey(&rdataset))))
+                       if (rdataset.type != dns_rdatatype_nxt &&
+                           rdataset.type != dns_rdatatype_ds)
                                goto skip;
                }
 
                if (rdataset.type == dns_rdatatype_nxt) {
                        if (!nokeys)
-                               nxt_setbit(&rdataset, dns_rdatatype_sig);
-                       if (neednullkey)
-                               nxt_setbit(&rdataset, dns_rdatatype_key);
+                               nxt_setbit(name, &rdataset, dns_rdatatype_sig,
+                                          1);
+                       if (hasds)
+                               nxt_setbit(name, &rdataset, dns_rdatatype_ds,
+                                          1);
                }
 
                signset(&diff, node, name, &rdataset);
@@ -1333,7 +1217,7 @@ loadzonekeys(dns_db_t *db) {
        for (i = 0; i < nkeys; i++) {
                signer_key_t *key;
 
-               key = newkeystruct(keys[i], ISC_FALSE);
+               key = newkeystruct(keys[i], ISC_FALSE, ISC_FALSE);
                ISC_LIST_APPEND(keylist, key, link);
        }
        dns_db_detachnode(db, &node);
@@ -1381,7 +1265,7 @@ loadzonepubkeys(dns_db_t *db) {
                        goto next;
                }
 
-               key = newkeystruct(pubkey, ISC_FALSE);
+               key = newkeystruct(pubkey, ISC_FALSE, ISC_FALSE);
                ISC_LIST_APPEND(keylist, key, link);
  next:
                result = dns_rdataset_next(&rdataset);
@@ -1391,6 +1275,80 @@ loadzonepubkeys(dns_db_t *db) {
        dns_db_closeversion(db, &currentversion, ISC_FALSE);
 }
 
+static void
+writekeyset(void) {
+       char namestr[DNS_NAME_FORMATSIZE];
+       isc_buffer_t namebuf;
+       unsigned int filenamelen;
+       char *keyfile;
+       signer_key_t *key;
+       unsigned char keybuf[DST_KEY_MAXSIZE];
+       dns_diff_t diff;
+       dns_difftuple_t *tuple = NULL;
+       dns_db_t *db = NULL;
+       dns_dbversion_t *version = NULL;
+       dns_rdata_t rdata;
+       isc_buffer_t b;
+       isc_region_t r;
+       isc_result_t result;
+
+       isc_buffer_init(&namebuf, namestr, sizeof(namestr));
+       result = dns_name_tofilenametext(gorigin, ISC_FALSE, &namebuf);
+       check_result(result, "dns_name_tofilenametext");
+       isc_buffer_putuint8(&namebuf, 0);
+       filenamelen = strlen("keyset-") + strlen(namestr);
+       if (directory != NULL)
+               filenamelen += strlen(directory) + 1;
+       keyfile = isc_mem_get(mctx, filenamelen + 1);
+       if (keyfile == NULL)
+               fatal("out of memory");
+       if (directory != NULL)
+               sprintf(keyfile, "%s/", directory);
+       else
+               keyfile[0] = 0;
+       strcat(keyfile, "keyset-");
+       strcat(keyfile, namestr);
+
+       dns_diff_init(mctx, &diff);
+
+       for (key = ISC_LIST_HEAD(keylist);
+            key != NULL;
+            key = ISC_LIST_NEXT(key, link))
+       {
+               if (!key->keysigning)
+                       continue;
+               dns_rdata_init(&rdata);
+               isc_buffer_init(&b, keybuf, sizeof(keybuf));
+               result = dst_key_todns(key->key, &b);
+               check_result(result, "dst_key_todns");
+               isc_buffer_usedregion(&b, &r);
+               dns_rdata_fromregion(&rdata, gclass, dns_rdatatype_key, &r);
+               result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD, gorigin,
+                                             zonettl, &rdata, &tuple);
+               check_result(result, "dns_difftuple_create");
+               dns_diff_append(&diff, &tuple);
+       }
+
+       result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+                              gclass, 0, NULL, &db);
+       check_result(result, "dns_db_create");
+
+       result = dns_db_newversion(db, &version);
+       check_result(result, "dns_db_newversion");
+
+       result = dns_diff_apply(&diff, db, version);
+       check_result(result, "dns_diff_apply");
+       dns_diff_clear(&diff);
+
+       result = dns_master_dump(mctx, db, version, masterstyle, keyfile);
+       check_result(result, "dns_master_dump");
+
+       isc_mem_put(mctx, keyfile, filenamelen + 1);
+
+       dns_db_closeversion(db, &version, ISC_FALSE);
+       dns_db_detach(&db);
+}
+
 static void
 print_time(FILE *fp) {
        time_t currenttime;
@@ -1438,6 +1396,7 @@ usage(void) {
        fprintf(stderr, "\t-t:\t");
        fprintf(stderr, "print statistics\n");
        fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
+       fprintf(stderr, "\t-k key_signing_key\n");
 
        fprintf(stderr, "\n");
 
@@ -1483,6 +1442,8 @@ main(int argc, char *argv[]) {
        int i, ch;
        char *startstr = NULL, *endstr = NULL, *classname = NULL;
        char *origin = NULL, *file = NULL, *output = NULL;
+       char *dskeyfile[MAXDSKEYS];
+       int ndskeys = 0;
        char *endp;
        isc_time_t timer_start, timer_finish;
        signer_key_t *key;
@@ -1493,6 +1454,7 @@ main(int argc, char *argv[]) {
        isc_boolean_t free_output = ISC_FALSE;
        int tempfilelen;
        dns_rdataclass_t rdclass;
+       dns_db_t *udb = NULL;
        isc_task_t **tasks = NULL;
        masterstyle = &dns_master_style_explicitttl;
 
@@ -1505,7 +1467,7 @@ main(int argc, char *argv[]) {
        dns_result_register();
 
        while ((ch = isc_commandline_parse(argc, argv,
-                                          "c:s:e:i:v:o:f:ahpr:td:n:S"))
+                                          "c:s:e:i:v:o:f:ahpr:td:n:Sk:"))
               != -1) {
                switch (ch) {
                case 'c':
@@ -1576,6 +1538,12 @@ main(int argc, char *argv[]) {
                        masterstyle = &dns_master_style_simple;
                        break;
 
+               case 'k':
+                       if (ndskeys == MAXDSKEYS)
+                               fatal("too many key-signing keys specified");
+                       dskeyfile[ndskeys++] = isc_commandline_argument;
+                       break;
+
                case 'h':
                default:
                        usage();
@@ -1626,6 +1594,9 @@ main(int argc, char *argv[]) {
        argc -= 1;
        argv += 1;
 
+       if (origin == NULL)
+               origin = file;
+
        if (output == NULL) {
                free_output = ISC_TRUE;
                output = isc_mem_allocate(mctx,
@@ -1635,13 +1606,11 @@ main(int argc, char *argv[]) {
                sprintf(output, "%s.signed", file);
        }
 
-       if (origin == NULL)
-               origin = file;
-
        gdb = NULL;
        TIME_NOW(&timer_start);
        loadzone(file, origin, rdclass, &gdb);
        gorigin = dns_db_origin(gdb);
+       gclass = dns_db_class(gdb);
        zonettl = soattl();
 
        ISC_LIST_INIT(keylist);
@@ -1652,6 +1621,8 @@ main(int argc, char *argv[]) {
                key = ISC_LIST_HEAD(keylist);
                while (key != NULL) {
                        key->isdefault = ISC_TRUE;
+                       if (ndskeys == 0)
+                               key->keysigning = ISC_TRUE;
                        key = ISC_LIST_NEXT(key, link);
                }
        } else {
@@ -1684,7 +1655,11 @@ main(int argc, char *argv[]) {
                                key = ISC_LIST_NEXT(key, link);
                        }
                        if (key == NULL) {
-                               key = newkeystruct(newkey, ISC_TRUE);
+                               isc_boolean_t iskeysigning = ISC_FALSE;
+                               if (ndskeys == 0)
+                                       iskeysigning = ISC_TRUE;
+                               key = newkeystruct(newkey, ISC_TRUE,
+                                                  iskeysigning);
                                ISC_LIST_APPEND(keylist, key, link);
                        } else
                                dst_key_free(&newkey);
@@ -1693,6 +1668,38 @@ main(int argc, char *argv[]) {
                loadzonepubkeys(gdb);
        }
 
+       for (i = 0; i < ndskeys; i++) {
+               dst_key_t *newkey = NULL;
+
+               result = dst_key_fromnamedfile(dskeyfile[i],
+                                              DST_TYPE_PUBLIC |
+                                              DST_TYPE_PRIVATE,
+                                              mctx, &newkey);
+               if (result != ISC_R_SUCCESS)
+                       fatal("cannot load key %s: %s", dskeyfile[i],
+                             isc_result_totext(result)); 
+
+               key = ISC_LIST_HEAD(keylist);
+               while (key != NULL) {
+                       dst_key_t *dkey = key->key;
+                       if (dst_key_id(dkey) == dst_key_id(newkey) &&
+                           dst_key_alg(dkey) == dst_key_alg(newkey) &&
+                           dns_name_equal(dst_key_name(dkey),
+                                          dst_key_name(newkey)))
+                       {
+                               key->keysigning = ISC_TRUE;
+                               dst_key_free(&dkey);
+                               key->key = newkey;
+                               break;
+                       }
+                       key = ISC_LIST_NEXT(key, link);
+               }
+               if (key == NULL) {
+                       key = newkeystruct(newkey, ISC_FALSE, ISC_TRUE);
+                       ISC_LIST_APPEND(keylist, key, link);
+               }
+       }
+
        if (ISC_LIST_EMPTY(keylist)) {
                fprintf(stderr, "%s: warning: No keys specified or found\n",
                        program);
@@ -1705,6 +1712,9 @@ main(int argc, char *argv[]) {
 
        nxtify();
 
+       if (!nokeys)
+               writekeyset();
+
        tempfilelen = strlen(output) + 20;
        tempfile = isc_mem_get(mctx, tempfilelen);
        if (tempfile == NULL)
@@ -1764,6 +1774,11 @@ main(int argc, char *argv[]) {
        isc_mem_put(mctx, tasks, ntasks * sizeof(isc_task_t *));
        postsign();
 
+       if (udb != NULL) {
+               dumpdb(udb);
+               dns_db_detach(&udb);
+       }
+
        result = isc_stdio_close(fp);
        check_result(result, "isc_stdio_close");
        removefile = ISC_FALSE;
index d75a0060195be2596da10ce554063de6cd99c502..a1a45236a4c2bf50f12a3149d22a6bbbdd750291 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: query.c,v 1.219 2002/03/28 04:03:50 marka Exp $ */
+/* $Id: query.c,v 1.220 2002/06/17 04:01:08 marka Exp $ */
 
 #include <config.h>
 
@@ -2045,6 +2045,70 @@ query_addbestns(ns_client_t *client) {
        }
 }
 
+static void
+query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node) {
+       dns_name_t *rname;
+       dns_rdataset_t *rdataset, *sigrdataset;
+       isc_result_t result;
+
+       CTRACE("query_addds");
+       rname = NULL;
+       rdataset = NULL;
+       sigrdataset = NULL;
+
+       /*
+        * We'll need some resources...
+        */
+       rdataset = query_newrdataset(client);
+       sigrdataset = query_newrdataset(client);
+       if (rdataset == NULL || sigrdataset == NULL)
+               return;
+
+       /*
+        * Look for the DS record, which may or may not be present.
+        */
+       result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds, 0,
+                                    client->now, rdataset, sigrdataset);
+       /*
+        * If we didn't find it, look for an NXT. */
+       if (result == ISC_R_NOTFOUND)
+               result = dns_db_findrdataset(db, node, NULL,
+                                            dns_rdatatype_nxt, 0, client->now,
+                                            rdataset, sigrdataset);
+       if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+               goto cleanup;
+       if (!dns_rdataset_isassociated(rdataset) ||
+           !dns_rdataset_isassociated(sigrdataset))
+               goto cleanup;
+
+       /*
+        * We've already added the NS record, so if the name's not there,
+        * we have other problems.  Use this name rather than calling
+        * query_addrrset().
+        */
+       result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       rname = NULL;
+       dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
+                               &rname);
+       result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       ISC_LIST_APPEND(rname->list, rdataset, link);
+       ISC_LIST_APPEND(rname->list, sigrdataset, link);
+       rdataset = NULL;
+       sigrdataset = NULL;
+
+ cleanup:
+       if (rdataset != NULL)
+               query_putrdataset(client, &rdataset);
+       if (sigrdataset != NULL)
+               query_putrdataset(client, &sigrdataset);
+}
+
 static void
 query_resume(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
@@ -2206,98 +2270,6 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
        return (result);
 }
 
-static inline isc_result_t
-query_findparentkey(ns_client_t *client, dns_name_t *name,
-                   dns_zone_t **zonep, dns_db_t **dbp,
-                   dns_dbversion_t **versionp, dns_dbnode_t **nodep,
-                   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
-{
-       dns_db_t *pdb;
-       dns_dbnode_t *pnode;
-       dns_dbversion_t *pversion;
-       dns_rdataset_t prdataset, psigrdataset;
-       dns_rdataset_t *psigrdatasetp;
-       isc_result_t result;
-       dns_zone_t *pzone;
-       isc_boolean_t is_zone;
-       dns_fixedname_t pfoundname;
-
-       /*
-        * 'name' is at a zone cut.  Try to find a KEY for 'name' in
-        * the deepest ancestor zone of 'name' (if any).  If it exists,
-        * update *zonep, *dbp, *nodep, rdataset, and sigrdataset and
-        * return ISC_R_SUCCESS.  If not, leave them alone and return a
-        * non-success status.
-        */
-
-       pzone = NULL;
-       pdb = NULL;
-       pnode = NULL;
-       pversion = NULL;
-       dns_rdataset_init(&prdataset);
-       if (sigrdataset != NULL)
-               dns_rdataset_init(&psigrdataset);
-       is_zone = ISC_FALSE;
-       dns_fixedname_init(&pfoundname);
-
-       result = query_getdb(client, name, DNS_GETDB_NOEXACT,
-                            &pzone, &pdb, &pversion, &is_zone);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-       if (!is_zone) {
-               result = ISC_R_FAILURE;
-               goto cleanup;
-       }
-
-       if (sigrdataset != NULL)
-               psigrdatasetp = &psigrdataset;
-       else
-               psigrdatasetp = NULL;
-       result = dns_db_find(pdb, name, pversion, dns_rdatatype_key,
-                            client->query.dboptions,
-                            client->now, &pnode,
-                            dns_fixedname_name(&pfoundname),
-                            &prdataset, psigrdatasetp);
-       if (result == ISC_R_SUCCESS) {
-               if (dns_rdataset_isassociated(rdataset))
-                       dns_rdataset_disassociate(rdataset);
-               dns_rdataset_clone(&prdataset, rdataset);
-               if (sigrdataset != NULL) {
-                       if (dns_rdataset_isassociated(sigrdataset))
-                               dns_rdataset_disassociate(sigrdataset);
-                       if (dns_rdataset_isassociated(&psigrdataset))
-                               dns_rdataset_clone(&psigrdataset, sigrdataset);
-               }
-               if (*nodep != NULL)
-                       dns_db_detachnode(*dbp, nodep);
-               *nodep = pnode;
-               pnode = NULL;
-               *versionp = pversion;
-               if (*dbp != NULL)
-                       dns_db_detach(dbp);
-               *dbp = pdb;
-               pdb = NULL;
-               if (*zonep != NULL)
-                       dns_zone_detach(zonep);
-               *zonep = pzone;
-               pzone = NULL;
-       }
-
- cleanup:
-       if (dns_rdataset_isassociated(&prdataset))
-               dns_rdataset_disassociate(&prdataset);
-       if (sigrdataset != NULL && dns_rdataset_isassociated(&psigrdataset))
-               dns_rdataset_disassociate(&psigrdataset);
-       if (pnode != NULL)
-               dns_db_detachnode(pdb, &pnode);
-       if (pdb != NULL)
-               dns_db_detach(&pdb);
-       if (pzone != NULL)
-               dns_zone_detach(&pzone);
-
-       return (result);
-}
-
 #define MAX_RESTARTS 16
 
 #define QUERY_ERROR(r) \
@@ -2419,6 +2391,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        dns_zone_t *zone;
        dns_rdata_cname_t cname;
        dns_rdata_dname_t dname;
+       unsigned int options;
 
        CTRACE("query_find");
 
@@ -2508,7 +2481,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        /*
         * First we must find the right database.
         */
-       result = query_getdb(client, client->query.qname, 0, &zone, &db,
+       options = 0;
+       if (dns_rdatatype_atparent(qtype) &&
+           !dns_name_equal(client->query.qname, dns_rootname))
+               options |= DNS_GETDB_NOEXACT;
+       result = query_getdb(client, client->query.qname, options, &zone, &db,
                             &version, &is_zone);
        if (result != ISC_R_SUCCESS) {
                if (result == DNS_R_REFUSED)
@@ -2560,63 +2537,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                             client->query.dboptions, client->now,
                             &node, fname, rdataset, sigrdataset);
 
-       /*
-        * We interrupt our normal query processing to bring you this special
-        * case...
-        *
-        * RFC 2535 (DNSSEC), section 2.3.4, discusses various special
-        * cases that can occur at delegation points.
-        *
-        * One of these cases is that the NULL KEY for an unsecure zone
-        * may occur in the delegating zone instead of in the delegated zone.
-        * If we're authoritative for both zones, we need to look for the
-        * key in the delegator if we didn't find it in the delegatee.  If
-        * we didn't do this, a client doing DNSSEC validation could fail
-        * because it couldn't get the NULL KEY.
-        */
-       if (type == dns_rdatatype_key &&
-           is_zone &&
-           result == DNS_R_NXRRSET &&
-           !dns_db_issecure(db) &&
-           dns_name_equal(client->query.qname, dns_db_origin(db))) {
-               /*
-                * We're looking for a KEY at the top of an unsecure zone,
-                * and we didn't find it.
-                */
-               result = query_findparentkey(client, client->query.qname,
-                                            &zone, &db, &version, &node,
-                                            rdataset, sigrdataset);
-               if (result == ISC_R_SUCCESS) {
-                       /*
-                        * We found the parent KEY.
-                        *
-                        * zone, db, version, node, rdataset, and sigrdataset
-                        * have all been updated to refer to the parent's
-                        * data.  We will resume query processing as if
-                        * we had looked for the KEY in the parent zone in
-                        * the first place.
-                        *
-                        * We need to set fname correctly.  We do this here
-                        * instead of in query_findparentkey() because
-                        * dns_name_copy() can fail (though it shouldn't
-                        * ever do so since we should have enough space).
-                        */
-                       result = dns_name_copy(client->query.qname,
-                                              fname, NULL);
-                       if (result != ISC_R_SUCCESS) {
-                               QUERY_ERROR(DNS_R_SERVFAIL);
-                               goto cleanup;
-                       }
-               } else {
-                       /*
-                        * We couldn't find the KEY in a parent zone.
-                        * Continue with processing of the original
-                        * results of dns_db_find().
-                        */
-                       result = DNS_R_NXRRSET;
-               }
-       }
-
  resume:
        CTRACE("query_find: resume");
        switch (result) {
@@ -2730,6 +2650,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                               &rdataset, sigrdatasetp,
                                               dbuf, DNS_SECTION_AUTHORITY);
                                client->query.gluedb = NULL;
+                               if (WANTDNSSEC(client) && dns_db_issecure(db))
+                                       query_addds(client, db, node);
                        } else {
                                /*
                                 * We might have a better answer or delegation
@@ -2789,6 +2711,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                /*
                                 * Recurse!
                                 */
+                               /* XXXBEW look at this? */
                                if (type == dns_rdatatype_key)
                                        result = query_recurse(client, qtype,
                                                               NULL, NULL);
@@ -2826,6 +2749,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                client->query.gluedb = NULL;
                                client->query.attributes &=
                                        ~NS_QUERYATTR_CACHEGLUEOK;
+                               if (WANTDNSSEC(client) &&
+                                   !dns_rdataset_isassociated(sigrdataset))
+                                       query_addds(client, db, node);
                        }
                }
                goto cleanup;
@@ -2857,8 +2783,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                /*
                 * Add NXT record if we found one.
                 */
-               if (dns_rdataset_isassociated(rdataset)) {
-                       if (WANTDNSSEC(client))
+               if (WANTDNSSEC(client)) {
+                       if (dns_rdataset_isassociated(rdataset))
                                query_addrrset(client, &fname, &rdataset,
                                               &sigrdataset,
                                               NULL, DNS_SECTION_AUTHORITY);
index 5b45b7df32712386d450d043f3e541874d555181..5d62fd16e0a609e8699290320f68bc795953aae7 100644 (file)
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: conf.sh.in,v 1.23 2001/08/01 19:00:58 gson Exp $
+# $Id: conf.sh.in,v 1.24 2002/06/17 04:01:10 marka Exp $
 
 #
 # Common configuration data for system tests, to be sourced into
@@ -37,8 +37,6 @@ RNDC=$TOP/bin/rndc/rndc
 NSUPDATE=$TOP/bin/nsupdate/nsupdate
 KEYGEN=$TOP/bin/dnssec/dnssec-keygen
 SIGNER=$TOP/bin/dnssec/dnssec-signzone
-KEYSIGNER=$TOP/bin/dnssec/dnssec-signkey
-KEYSETTOOL=$TOP/bin/dnssec/dnssec-makekeyset
 
 # The "stress" test is not run by default since it creates enough
 # load on the machine to make it unusable to other users.
index aa4e53100b4caece66dd5b97aef123f2fc169c99..c99aa35ababebed1e27b2b15de8454bb99e483c5 100644 (file)
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: sign.sh,v 1.13 2001/09/17 17:42:04 bwelling Exp $
+# $Id: sign.sh,v 1.14 2002/06/17 04:01:12 marka Exp $
 
 SYSTEMTESTTOP=../..
 . $SYSTEMTESTTOP/conf.sh
@@ -26,17 +26,11 @@ zone=.
 infile=root.db.in
 zonefile=root.db
 
-keyname=`$KEYGEN -r $RANDFILE -a RSA -b 768 -n zone $zone`
-
 (cd ../ns2 && sh sign.sh )
 
 cp ../ns2/keyset-example. .
 
-$KEYSIGNER -r $RANDFILE keyset-example. $keyname > /dev/null
-
-cat signedkey-example. >> ../ns2/example.db.signed
-
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname > /dev/null
+keyname=`$KEYGEN -r $RANDFILE -a RSA -b 768 -n zone $zone`
 
 cat $infile $keyname.key > $zonefile
 
index 56022836c4b89cd8f92eab5395b7d6abc7ba1b48..5708b627ce369ff8ed186978be3fccf1e6d3ce81 100644 (file)
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: sign.sh,v 1.19 2002/02/20 03:33:55 marka Exp $
+# $Id: sign.sh,v 1.20 2002/06/17 04:01:14 marka Exp $
 
 SYSTEMTESTTOP=../..
 . $SYSTEMTESTTOP/conf.sh
@@ -26,29 +26,21 @@ zone=example.
 infile=example.db.in
 zonefile=example.db
 
-keyname=`$KEYGEN -r $RANDFILE -a DSA -b 768 -n zone $zone`
-
-# Have the child generate a zone key and pass it to us,
-# sign it, and pass it back
+# Have the child generate a zone key and pass it to us.
 
 ( cd ../ns3 && sh sign.sh )
 
 for subdomain in secure bogus dynamic
 do
        cp ../ns3/keyset-$subdomain.example. .
-
-       $KEYSIGNER -r $RANDFILE keyset-$subdomain.example. $keyname > /dev/null
-
-       # This will leave two copies of the child's zone key in the signed db file;
-       # that shouldn't cause any problems.
-       cat signedkey-$subdomain.example. >>../ns3/$subdomain.example.db.signed
 done
 
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname > /dev/null
+keyname1=`$KEYGEN -r $RANDFILE -a DSA -b 768 -n zone $zone`
+keyname2=`$KEYGEN -r $RANDFILE -a DSA -b 768 -n zone $zone`
 
-cat $infile $keyname.key >$zonefile
+cat $infile $keyname1.key $keyname2.key >$zonefile
 
-$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -r $RANDFILE -o $zone -k $keyname1 $zonefile $keyname2 > /dev/null
 
 # Sign the privately secure file
 
index 70f704a18a487ba759782d194f084c5e8c80a489..ead54452b4e43e4accfbf5c4b06b774ee71d8050 100644 (file)
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: sign.sh,v 1.16 2002/02/20 03:33:59 marka Exp $
+# $Id: sign.sh,v 1.17 2002/06/17 04:01:15 marka Exp $
 
 RANDFILE=../random.data
 
@@ -25,8 +25,6 @@ zonefile=secure.example.db
 
 keyname=`$KEYGEN -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
 
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname.key > /dev/null
-
 cat $infile $keyname.key >$zonefile
 
 $SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
@@ -37,8 +35,6 @@ zonefile=bogus.example.db
 
 keyname=`$KEYGEN -r $RANDFILE -a RSA -b 768 -n zone $zone`
 
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname.key > /dev/null
-
 cat $infile $keyname.key >$zonefile
 
 $SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
@@ -49,8 +45,6 @@ zonefile=dynamic.example.db
 
 keyname=`$KEYGEN -r $RANDFILE -a RSA -b 768 -n zone $zone`
 
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname.key > /dev/null
-
 cat $infile $keyname.key >$zonefile
 
 $SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
@@ -61,8 +55,6 @@ zonefile=keyless.example.db
 
 keyname=`$KEYGEN -r $RANDFILE -a RSA -b 768 -n zone $zone`
 
-$KEYSETTOOL -r $RANDFILE -t 3600 $keyname.key > /dev/null
-
 cat $infile $keyname.key >$zonefile
 
 $SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
index 03a61d7a438820e523b4b30dca458952a543f98e..760473fd7822031c58700eab825c7bb31bb8c806 100644 (file)
@@ -15,7 +15,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: tests.sh,v 1.39 2002/02/20 03:33:50 marka Exp $
+# $Id: tests.sh,v 1.40 2002/06/17 04:01:11 marka Exp $
 
 SYSTEMTESTTOP=..
 . $SYSTEMTESTTOP/conf.sh
@@ -25,7 +25,7 @@ n=0
 
 rm -f dig.out.*
 
-DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocmd +dnssec -p 5300"
+DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300"
 
 # Check the example. domain
 
@@ -113,6 +113,14 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:checking that insecurity proofs fail with a misconfigured trusted key ($n)"
+ret=0
+$DIG $DIGOPTS a.insecure.example. a @10.53.0.5 > dig.out.ns5.test$n || ret=1
+grep "SERVFAIL" dig.out.ns5.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:checking that validation fails when key record is missing ($n)"
 ret=0
 $DIG $DIGOPTS a.b.keyless.example. a @10.53.0.4 > dig.out.ns4.test$n || ret=1
index 85a4dfb8e9e0f2058cf4ef980e610f26f497fe12..1a9a019cfc3d7d72d00c30c580fb3aae8473360d 100644 (file)
@@ -13,7 +13,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.129 2002/03/07 06:29:36 marka Exp $
+# $Id: Makefile.in,v 1.130 2002/06/17 04:01:17 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -46,7 +46,7 @@ DSTOBJS =     sec/dst/dst_api.@O@ \
 OBJS =         a6.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
                cache.@O@ callbacks.@O@ compress.@O@ \
                db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
-               dnssec.@O@ forward.@O@ journal.@O@ keytable.@O@ \
+               dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
                lib.@O@ log.@O@ lookup.@O@ \
                master.@O@ masterdump.@O@ message.@O@ \
                name.@O@ ncache.@O@ nxt.@O@ order.@O@ peer.@O@ \
@@ -62,7 +62,7 @@ OBJS =                a6.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
 SRCS =         a6.c acl.c adb.c byaddr.c \
                cache.c callbacks.c compress.c \
                db.c dbiterator.c dbtable.c diff.c dispatch.c \
-               dnssec.c forward.c journal.c keytable.c \
+               dnssec.c ds.c forward.c journal.c keytable.c \
                lib.c log.c lookup.c \
                master.c masterdump.c message.c \
                name.c ncache.c nxt.c order.c peer.c \
diff --git a/lib/dns/ds.c b/lib/dns/ds.c
new file mode 100644 (file)
index 0000000..c89e102
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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: ds.c,v 1.2 2002/06/17 04:01:18 marka Exp $ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/region.h>
+#include <isc/sha1.h>
+#include <isc/util.h>
+
+#include <dns/ds.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+
+#include <dst/dst.h>
+
+isc_result_t
+dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+                 unsigned int digest_type, unsigned char *buffer,
+                 dns_rdata_t *rdata)
+{
+       isc_sha1_t sha1;
+       dns_fixedname_t fname;
+       dns_name_t *name;
+       unsigned char digest[ISC_SHA1_DIGESTLENGTH];
+       isc_region_t r;
+       isc_buffer_t b;
+       dns_rdata_ds_t ds;
+
+       if (digest_type != DNS_DSDIGEST_SHA1)
+               return (ISC_R_NOTIMPLEMENTED);
+
+       dns_fixedname_init(&fname);
+       name = dns_fixedname_name(&fname);
+       (void)dns_name_downcase(owner, name, NULL);
+
+       memset(buffer, 0, DNS_DS_BUFFERSIZE);
+       isc_buffer_init(&b, buffer, DNS_DS_BUFFERSIZE);
+
+       isc_sha1_init(&sha1);
+       dns_name_toregion(name, &r);
+       isc_sha1_update(&sha1, r.base, r.length);
+       dns_rdata_toregion(key, &r);
+       INSIST(r.length >= 4);
+       isc_sha1_update(&sha1, r.base, r.length);
+       isc_sha1_final(&sha1, digest);
+
+       ds.mctx = NULL;
+       ds.common.rdclass = key->rdclass;
+       ds.common.rdtype = dns_rdatatype_ds;
+       ds.algorithm = r.base[3];
+       ds.key_tag = dst_region_computeid(&r, ds.algorithm);
+       ds.digest_type = DNS_DSDIGEST_SHA1;
+       ds.length = ISC_SHA1_DIGESTLENGTH;
+       ds.digest = digest;
+
+       return (dns_rdata_fromstruct(rdata, key->rdclass, dns_rdatatype_ds,
+                                    &ds, &b));
+}
index 4397333855bbe657f65856b294cf5b50d8cdd7fc..e2155105d366c4d8c056477a4ebcf84e4e14b1fe 100644 (file)
@@ -13,7 +13,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.45 2001/11/09 23:09:29 bwelling Exp $
+# $Id: Makefile.in,v 1.46 2002/06/17 04:01:28 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -24,7 +24,7 @@ top_srcdir =  @top_srcdir@
 HEADERS =      a6.h acl.h adb.h byaddr.h cache.h callbacks.h \
                cert.h compress.h \
                db.h dbiterator.h dbtable.h diff.h dispatch.h \
-               dnssec.h events.h fixedname.h journal.h keyflags.h \
+               dnssec.h ds.h events.h fixedname.h journal.h keyflags.h \
                keytable.h keyvalues.h lib.h log.h master.h masterdump.h \
                message.h name.h ncache.h \
                nxt.h peer.h rbt.h rcode.h \
diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h
new file mode 100644 (file)
index 0000000..a6e6843
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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: ds.h,v 1.2 2002/06/17 04:01:29 marka Exp $ */
+
+#ifndef DNS_DS_H
+#define DNS_DS_H 1
+
+#include <isc/lang.h>
+
+#include <dns/types.h>
+
+#define DNS_DSDIGEST_SHA1 (1)
+
+/*
+ * Assuming SHA-1 digest type.
+ */
+#define DNS_DS_BUFFERSIZE (24)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+                 unsigned int digest_type, unsigned char *buffer,
+                 dns_rdata_t *rdata);
+/*
+ * Build the rdata of a DS record.
+ *
+ * Requires:
+ *     key     Points to a valid DNS KEY record.
+ *     buffer  Points to a temporary buffer of at least
+ *             DNS_DS_BUFFERSIZE bytes.
+ *     rdata   Points to an initialized dns_rdata_t.
+ *
+ * Ensures:
+ *      *rdata Contains a valid DS rdata.  The 'data' member refers
+ *             to 'buffer'.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_DS_H */
index 38e62d260865e2c561ffd20ceaa7ccd9e2b3cc09..21b09a543be990aacee4c3a181cc43e32e118a6c 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.h,v 1.54 2002/02/20 03:34:36 marka Exp $ */
+/* $Id: rdata.h,v 1.55 2002/06/17 04:01:31 marka Exp $ */
 
 #ifndef DNS_RDATA_H
 #define DNS_RDATA_H 1
@@ -610,6 +610,17 @@ dns_rdatatype_notquestion(dns_rdatatype_t type);
  *
  */
 
+isc_boolean_t
+dns_rdatatype_atparent(dns_rdatatype_t type);
+/*
+ * Return true iff rdata of type 'type' should appear at the parent of
+ * a zone cut.
+ *
+ * Requires:
+ *     'type' is a valid rdata type.
+ *
+ */
+
 unsigned int
 dns_rdatatype_attributes(dns_rdatatype_t rdtype);
 /*
@@ -640,6 +651,8 @@ dns_rdatatype_attributes(dns_rdatatype_t rdtype);
 #define DNS_RDATATYPEATTR_QUESTIONONLY         0x00000080U
 /* is META, and can NOT be in a question section */
 #define DNS_RDATATYPEATTR_NOTQUESTION          0x00000100U
+/* Is present at zone cuts in the parent, not the child */
+#define DNS_RDATATYPEATTR_ATPARENT             0x00000200U
 
 dns_rdatatype_t
 dns_rdata_covers(dns_rdata_t *rdata);
index b3d23a7b6c3f8e11c94b72af603511a685fba0bf..3983d74b0dfbed0dc18ba25e8279c3decfc83bd6 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.88 2002/03/14 18:34:46 bwelling Exp $ */
+/* $Id: result.h,v 1.89 2002/06/17 04:01:32 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_FROZEN                   (ISC_RESULTCLASS_DNS + 81)
 #define DNS_R_UNKNOWNFLAG              (ISC_RESULTCLASS_DNS + 82)
 #define DNS_R_EXPECTEDRESPONSE         (ISC_RESULTCLASS_DNS + 83)
+#define DNS_R_NOVALIDDS                        (ISC_RESULTCLASS_DNS + 84)
 
-#define DNS_R_NRESULTS                 84      /* Number of results */
+#define DNS_R_NRESULTS                 85      /* Number of results */
 
 /*
  * DNS wire format rcodes.
index da55dae692268abec4db41163b9fa6dd42fa75cf..81020ee3bc7db90c82c3e5922d7f09c09dc84afc 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.h,v 1.20 2001/09/14 20:53:33 gson Exp $ */
+/* $Id: validator.h,v 1.21 2002/06/17 04:01:33 marka Exp $ */
 
 #ifndef DNS_VALIDATOR_H
 #define DNS_VALIDATOR_H 1
@@ -93,8 +93,8 @@ struct dns_validator {
        unsigned int                    attributes;
        dns_validatorevent_t *          event;
        dns_fetch_t *                   fetch;
-       dns_validator_t *               keyvalidator;
-       dns_validator_t *               authvalidator;
+       dns_validator_t *               subvalidator;
+       dns_validator_t *               parent;
        dns_keytable_t *                keytable;
        dns_keynode_t *                 keynode;
        dst_key_t *                     key;
@@ -106,8 +106,11 @@ struct dns_validator {
        dns_rdataset_t *                currentset;
        isc_boolean_t                   seensig;
        dns_rdataset_t *                keyset;
+       dns_rdataset_t *                dsset;
+       dns_rdataset_t *                soaset;
        dns_rdataset_t                  frdataset;
        dns_rdataset_t                  fsigrdataset;
+       dns_fixedname_t                 fname;
        ISC_LINK(dns_validator_t)       link;
 };
 
index 9dc15ae5eebbbaad84764129d6dcf44706c8dc2c..06c5436a805ebb0686a6ef978703e74fa7027582 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.175 2002/05/28 05:49:20 marka Exp $ */
+/* $Id: rbtdb.c,v 1.176 2002/06/17 04:01:20 marka Exp $ */
 
 /*
  * Principal Author: Bob Halley
@@ -1839,7 +1839,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                 */
                if (node->find_callback &&
                    (node != search.rbtdb->origin_node ||
-                    IS_STUB(search.rbtdb)))
+                    IS_STUB(search.rbtdb)) &&
+                   !dns_rdatatype_atparent(type))
                        maybe_zonecut = ISC_TRUE;
        }
 
index e0d7ce71a657db606dde0a0d496e4cc1c36a217b..6984b0c49a4aba34a015874ccc0cd72a66fbd386 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdata.c,v 1.171 2002/03/27 23:31:32 marka Exp $ */
+/* $Id: rdata.c,v 1.172 2002/06/17 04:01:21 marka Exp $ */
 
 #include <config.h>
 #include <ctype.h>
@@ -2047,6 +2047,13 @@ dns_rdatatype_questiononly(dns_rdatatype_t type) {
        return (ISC_FALSE);
 }
 
+isc_boolean_t
+dns_rdatatype_atparent(dns_rdatatype_t type) {
+       if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
+               return (ISC_TRUE);
+       return (ISC_FALSE);
+}
+
 isc_boolean_t
 dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
        REQUIRE(rdclass < 65536);
diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c
new file mode 100644 (file)
index 0000000..009b887
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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: ds_43.c,v 1.2 2002/06/17 04:01:35 marka Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+
+#ifndef RDATA_GENERIC_DS_43_C
+#define RDATA_GENERIC_DS_43_C
+
+#define RRTYPE_DS_ATTRIBUTES (DNS_RDATATYPEATTR_ATPARENT)
+
+static inline isc_result_t
+fromtext_ds(ARGS_FROMTEXT) {
+       isc_token_t token;
+
+       REQUIRE(type == 43);
+
+       UNUSED(type);
+       UNUSED(rdclass);
+       UNUSED(origin);
+       UNUSED(downcase);
+       UNUSED(callbacks);
+
+       /*
+        * Key tag.
+        */
+       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+                                     ISC_FALSE));
+       if (token.value.as_ulong > 0xffff)
+               RETTOK(ISC_R_RANGE);
+       RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+       /*
+        * Algorithm.
+        */
+       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+                                     ISC_FALSE));
+       if (token.value.as_ulong > 0xff)
+               RETTOK(ISC_R_RANGE);
+       RETERR(uint8_tobuffer(token.value.as_ulong, target));
+
+       /*
+        * Digest type.
+        */
+       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+                                     ISC_FALSE));
+       if (token.value.as_ulong > 0xff)
+               RETTOK(ISC_R_RANGE);
+       RETERR(uint8_tobuffer(token.value.as_ulong, target));
+       type = token.value.as_ulong;
+
+       /*
+        * Digest.
+        */
+       return (isc_hex_tobuffer(lexer, target, -1));
+}
+
+static inline isc_result_t
+totext_ds(ARGS_TOTEXT) {
+       isc_region_t sr;
+       char buf[sizeof("64000 ")];
+       unsigned int n;
+
+       REQUIRE(rdata->type == 43);
+       REQUIRE(rdata->length != 0);
+
+       UNUSED(tctx);
+
+       dns_rdata_toregion(rdata, &sr);
+
+       /*
+        * Key tag.
+        */
+       n = uint16_fromregion(&sr);
+       isc_region_consume(&sr, 2);
+       sprintf(buf, "%u ", n);
+       RETERR(str_totext(buf, target));
+
+       /*
+        * Algorithm.
+        */
+       n = uint8_fromregion(&sr);
+       isc_region_consume(&sr, 1);
+       sprintf(buf, "%u ", n);
+       RETERR(str_totext(buf, target));
+
+       /*
+        * Digest type.
+        */
+       n = uint8_fromregion(&sr);
+       isc_region_consume(&sr, 1);
+       sprintf(buf, "%u", n);
+       RETERR(str_totext(buf, target));
+
+       /*
+        * Digest.
+        */
+       if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+               RETERR(str_totext(" (", target));
+       RETERR(str_totext(tctx->linebreak, target));
+       RETERR(isc_hex_totext(&sr, tctx->width - 2, tctx->linebreak, target));
+       if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
+               RETERR(str_totext(" )", target));
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_ds(ARGS_FROMWIRE) {
+       isc_region_t sr;
+
+       REQUIRE(type == 43);
+
+       UNUSED(type);
+       UNUSED(rdclass);
+       UNUSED(dctx);
+       UNUSED(downcase);
+
+       isc_buffer_activeregion(source, &sr);
+       if (sr.length < 4)
+               return (ISC_R_UNEXPECTEDEND);
+
+       isc_buffer_forward(source, sr.length);
+       return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline isc_result_t
+towire_ds(ARGS_TOWIRE) {
+       isc_region_t sr;
+
+       REQUIRE(rdata->type == 43);
+       REQUIRE(rdata->length != 0);
+
+       UNUSED(cctx);
+
+       dns_rdata_toregion(rdata, &sr);
+       return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_ds(ARGS_COMPARE) {
+       isc_region_t r1;
+       isc_region_t r2;
+
+       REQUIRE(rdata1->type == rdata2->type);
+       REQUIRE(rdata1->rdclass == rdata2->rdclass);
+       REQUIRE(rdata1->type == 43);
+       REQUIRE(rdata1->length != 0);
+       REQUIRE(rdata2->length != 0);
+
+       dns_rdata_toregion(rdata1, &r1);
+       dns_rdata_toregion(rdata2, &r2);
+       return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_ds(ARGS_FROMSTRUCT) {
+       dns_rdata_ds_t *ds = source;
+
+       REQUIRE(type == 43);
+       REQUIRE(source != NULL);
+       REQUIRE(ds->common.rdtype == type);
+       REQUIRE(ds->common.rdclass == rdclass);
+
+       UNUSED(type);
+       UNUSED(rdclass);
+
+       RETERR(uint16_tobuffer(ds->key_tag, target));
+       RETERR(uint8_tobuffer(ds->algorithm, target));
+       RETERR(uint8_tobuffer(ds->digest_type, target));
+
+       return (mem_tobuffer(target, ds->digest, ds->length));
+}
+
+static inline isc_result_t
+tostruct_ds(ARGS_TOSTRUCT) {
+       dns_rdata_ds_t *ds = target;
+       isc_region_t region;
+
+       REQUIRE(rdata->type == 43);
+       REQUIRE(target != NULL);
+       REQUIRE(rdata->length != 0);
+
+       ds->common.rdclass = rdata->rdclass;
+       ds->common.rdtype = rdata->type;
+       ISC_LINK_INIT(&ds->common, link);
+
+       dns_rdata_toregion(rdata, &region);
+
+       ds->key_tag = uint16_fromregion(&region);
+       isc_region_consume(&region, 2);
+       ds->algorithm = uint8_fromregion(&region);
+       isc_region_consume(&region, 1);
+       ds->digest_type = uint8_fromregion(&region);
+       isc_region_consume(&region, 1);
+       ds->length = region.length;
+
+       ds->digest = mem_maybedup(mctx, region.base, region.length);
+       if (ds->digest == NULL)
+               return (ISC_R_NOMEMORY);
+
+       ds->mctx = mctx;
+       return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_ds(ARGS_FREESTRUCT) {
+       dns_rdata_ds_t *ds = source;
+
+       REQUIRE(ds != NULL);
+       REQUIRE(ds->common.rdtype == 43);
+
+       if (ds->mctx == NULL)
+               return;
+
+       if (ds->digest != NULL)
+               isc_mem_free(ds->mctx, ds->digest);
+       ds->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_ds(ARGS_ADDLDATA) {
+       REQUIRE(rdata->type == 43);
+
+       UNUSED(rdata);
+       UNUSED(add);
+       UNUSED(arg);
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_ds(ARGS_DIGEST) {
+       isc_region_t r;
+
+       REQUIRE(rdata->type == 43);
+
+       dns_rdata_toregion(rdata, &r);
+
+       return ((digest)(arg, &r));
+}
+
+#endif /* RDATA_GENERIC_DS_43_C */
diff --git a/lib/dns/rdata/generic/ds_43.h b/lib/dns/rdata/generic/ds_43.h
new file mode 100644 (file)
index 0000000..81e49bb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1999-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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: ds_43.h,v 1.2 2002/06/17 04:01:37 marka Exp $ */
+
+/* draft-ietf-dnsext-delegation-signer-05.txt */
+#ifndef GENERIC_DS_43_H
+#define GENERIC_DS_43_H 1
+
+typedef struct dns_rdata_ds {
+       dns_rdatacommon_t       common;
+       isc_mem_t               *mctx;
+       isc_uint16_t            key_tag;
+       isc_uint8_t             algorithm;
+       isc_uint8_t             digest_type;
+       isc_uint16_t            length;
+       unsigned char           *digest;
+} dns_rdata_ds_t;
+
+#endif /* GENERIC_DS_43_H */
index ef5a67e8e07ec1977857f1ae986c12f3fd5d985d..0b1ec444a25b9c15dfc5f826c1b94d0644085bdd 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.242 2002/05/27 06:30:24 marka Exp $ */
+/* $Id: resolver.c,v 1.243 2002/06/17 04:01:24 marka Exp $ */
 
 #include <config.h>
 
@@ -2198,7 +2198,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
                         * nameservers, and we're not in forward-only mode,
                         * so find the best nameservers to use.
                         */
-                       if (type == dns_rdatatype_key)
+                       if (dns_rdatatype_atparent(type))
                                findoptions |= DNS_DBFIND_NOEXACT;
                        dns_fixedname_init(&qdomain);
                        result = dns_view_findzonecut(res->view, name,
@@ -3478,7 +3478,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
 {
        isc_result_t result;
        dns_message_t *message;
-       dns_name_t *name, *qname, *ns_name, *soa_name;
+       dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
        dns_rdataset_t *rdataset, *ns_rdataset;
        isc_boolean_t done, aa, negative_response;
        dns_rdatatype_t type;
@@ -3543,6 +3543,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
        ns_name = NULL;
        ns_rdataset = NULL;
        soa_name = NULL;
+       ds_name = NULL;
        result = dns_message_firstname(message, section);
        while (!done && result == ISC_R_SUCCESS) {
                name = NULL;
@@ -3591,11 +3592,22 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
                                                        return (DNS_R_FORMERR);
                                                soa_name = name;
                                        }
-                                       negative_response = ISC_TRUE;
-                                       name->attributes |=
-                                               DNS_NAMEATTR_NCACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_NCACHE;
+                                       /*
+                                        * This is wrong, but maybe it'll
+                                        * work for now.
+                                        */
+                                       if (ns_name == NULL) {
+                                               negative_response = ISC_TRUE;
+                                               name->attributes |=
+                                                       DNS_NAMEATTR_NCACHE;
+                                               rdataset->attributes |=
+                                                       DNS_RDATASETATTR_NCACHE;
+                                       } else {
+                                               name->attributes |=
+                                                       DNS_NAMEATTR_CACHE;
+                                               rdataset->attributes |=
+                                                       DNS_RDATASETATTR_CACHE;
+                                       }
                                        if (aa)
                                                rdataset->trust =
                                                    dns_trust_authauthority;
@@ -3606,6 +3618,33 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
                                         * No additional data needs to be
                                         * marked.
                                         */
+                               } else if (type == dns_rdatatype_ds) {
+                                       /*
+                                        * DS or SIG DS.
+                                        *
+                                        * These should only be here if
+                                        * this is a referral, and there
+                                        * should only be one DS.
+                                        */
+                                       if (negative_response)
+                                               return (DNS_R_FORMERR);
+                                       if (rdataset->type ==
+                                           dns_rdatatype_ds) {
+                                               if (ds_name != NULL &&
+                                                   name != ds_name)
+                                                       return (DNS_R_FORMERR);
+                                               ds_name = name;
+                                       }
+                                       name->attributes |=
+                                               DNS_NAMEATTR_CACHE;
+                                       rdataset->attributes |=
+                                               DNS_RDATASETATTR_CACHE;
+                                       if (aa)
+                                               rdataset->trust =
+                                                   dns_trust_authauthority;
+                                       else
+                                               rdataset->trust =
+                                                       dns_trust_additional;
                                }
                        }
                }
@@ -4112,6 +4151,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
        isc_time_t tnow, *finish;
        dns_adbaddrinfo_t *addrinfo;
        unsigned int options;
+       unsigned int findoptions;
 
        REQUIRE(VALID_QUERY(query));
        fctx = query->fctx;
@@ -4548,10 +4588,14 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
                                fctx_done(fctx, DNS_R_SERVFAIL);
                                return;
                        }
+                       findoptions = 0;
+                       if (dns_rdatatype_atparent(fctx->type))
+                               findoptions |= DNS_DBFIND_NOEXACT;
                        result = dns_view_findzonecut(fctx->res->view,
                                                      &fctx->domain,
                                                      fname,
-                                                     now, 0, ISC_TRUE,
+                                                     now, findoptions,
+                                                     ISC_TRUE,
                                                      &fctx->nameservers,
                                                      NULL);
                        if (result != ISC_R_SUCCESS) {
index 8ce4aeb103b79eaefa27acb10d0fb60a735a652c..a65e32c280d130daa583a56dc4f08801a1adbe07 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.98 2002/03/14 18:34:44 bwelling Exp $ */
+/* $Id: result.c,v 1.99 2002/06/17 04:01:25 marka Exp $ */
 
 #include <config.h>
 
@@ -125,7 +125,8 @@ static const char *text[DNS_R_NRESULTS] = {
        "obsolete",                            /* 80 DNS_R_OBSOLETE          */
        "already frozen",                      /* 81 DNS_R_FROZEN            */
        "unknown flag",                        /* 82 DNS_R_UNKNOWNFLAG       */
-       "expected a response"                  /* 83 DNS_R_EXPECTEDRESPONSE  */
+       "expected a response",                 /* 83 DNS_R_EXPECTEDRESPONSE  */
+       "no valid DS"                          /* 84 DNS_R_NOVALIDDS         */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index 78a6705cb437f548b7ffb00536258df4f41b85a3..3bb82c2cce5a5649e74738b0dd17dc507715065e 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.104 2002/04/29 23:50:24 marka Exp $ */
+/* $Id: validator.c,v 1.105 2002/06/17 04:01:26 marka Exp $ */
 
 #include <config.h>
 
@@ -25,6 +25,7 @@
 #include <isc/util.h>
 
 #include <dns/db.h>
+#include <dns/ds.h>
 #include <dns/dnssec.h>
 #include <dns/events.h>
 #include <dns/keytable.h>
 #define VALATTR_SHUTDOWN               0x01
 #define VALATTR_FOUNDNONEXISTENCE      0x02
 #define VALATTR_TRIEDVERIFY            0x04
+#define VALATTR_NEGATIVE               0x08
+#define VALATTR_INSECURITY             0x10
 #define SHUTDOWN(v)            (((v)->attributes & VALATTR_SHUTDOWN) != 0)
 
 static void
-nullkeyvalidated(isc_task_t *task, isc_event_t *event);
-
-static isc_boolean_t
-containsnullkey(dns_validator_t *val, dns_rdataset_t *rdataset);
+destroy(dns_validator_t *val);
 
 static isc_result_t
 get_dst_key(dns_validator_t *val, dns_rdata_sig_t *siginfo,
@@ -61,6 +61,9 @@ get_dst_key(dns_validator_t *val, dns_rdata_sig_t *siginfo,
 static isc_result_t
 validate(dns_validator_t *val, isc_boolean_t resume);
 
+static isc_result_t
+validatezonekey(dns_validator_t *val, isc_boolean_t resume);
+
 static isc_result_t
 nxtvalidate(dns_validator_t *val, isc_boolean_t resume);
 
@@ -76,6 +79,11 @@ static void
 validator_log(dns_validator_t *val, int level, const char *fmt, ...)
      ISC_FORMAT_PRINTF(3, 4);
 
+static void
+validator_logcreate(dns_validator_t *val,
+                   dns_name_t *name, dns_rdatatype_t type,
+                   const char *caller, const char *operation);
+
 static void
 validator_done(dns_validator_t *val, isc_result_t result) {
        isc_task_t *task;
@@ -96,6 +104,22 @@ validator_done(dns_validator_t *val, isc_result_t result) {
        isc_task_sendanddetach(&task, (isc_event_t **)&val->event);
 }
 
+static inline isc_boolean_t
+exit_check(dns_validator_t *val) {
+       /*
+        * Caller must be holding the lock.
+        */
+       if (!SHUTDOWN(val))
+               return (ISC_FALSE);
+
+       INSIST(val->event == NULL);
+
+       if (val->fetch != NULL || val->subvalidator != NULL)
+               return (ISC_FALSE);
+
+       return (ISC_TRUE);
+}
+
 static void
 auth_nonpending(dns_message_t *message) {
        isc_result_t result;
@@ -123,6 +147,7 @@ fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent;
        dns_validator_t *val;
        dns_rdataset_t *rdataset;
+       isc_boolean_t want_destroy;
        isc_result_t result;
        isc_result_t eresult;
 
@@ -152,10 +177,8 @@ fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
                                val->keyset = &val->frdataset;
                }
                result = validate(val, ISC_TRUE);
-               if (result != DNS_R_WAIT) {
+               if (result != DNS_R_WAIT)
                        validator_done(val, result);
-                       goto out;
-               }
        } else {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "fetch_callback_validator: got %s",
@@ -165,24 +188,18 @@ fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
                else
                        validator_done(val, DNS_R_NOVALIDKEY);
        }
-
- out:
+       want_destroy = exit_check(val);
        UNLOCK(&val->lock);
-       /*
-        * Free stuff from the event.
-        */
-       if (dns_rdataset_isassociated(&val->frdataset) &&
-           val->keyset != &val->frdataset)
-               dns_rdataset_disassociate(&val->frdataset);
-       if (dns_rdataset_isassociated(&val->fsigrdataset))
-               dns_rdataset_disassociate(&val->fsigrdataset);
+       if (want_destroy)
+               destroy(val);
 }
 
 static void
-fetch_callback_nullkey(isc_task_t *task, isc_event_t *event) {
+dsfetched(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent;
        dns_validator_t *val;
-       dns_rdataset_t *rdataset, *sigrdataset;
+       dns_rdataset_t *rdataset;
+       isc_boolean_t want_destroy;
        isc_result_t result;
        isc_result_t eresult;
 
@@ -191,106 +208,105 @@ fetch_callback_nullkey(isc_task_t *task, isc_event_t *event) {
        devent = (dns_fetchevent_t *)event;
        val = devent->ev_arg;
        rdataset = &val->frdataset;
-       sigrdataset = &val->fsigrdataset;
        eresult = devent->result;
 
+       isc_event_free(&event);
        dns_resolver_destroyfetch(&val->fetch);
 
        INSIST(val->event != NULL);
 
-       validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_nullkey");
-
+       validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched");
        LOCK(&val->lock);
        if (eresult == ISC_R_SUCCESS) {
-               if (!containsnullkey(val, rdataset)) {
-                       /*
-                        * No null key.
-                        */
-                       validator_log(val, ISC_LOG_DEBUG(3),
-                                     "found a keyset, no null key");
-                       result = proveunsecure(val, ISC_TRUE);
-                       if (result != DNS_R_WAIT)
-                               validator_done(val, result);
-                       else {
-                               /*
-                                * Don't free rdataset & sigrdataset, since
-                                * they'll be freed in nullkeyvalidated.
-                                */
-                               isc_event_free(&event);
-                               UNLOCK(&val->lock);
-                               return;
-                       }
-               } else {
-                       validator_log(val, ISC_LOG_DEBUG(3),
-                                     "found a keyset with a null key");
-                       if (rdataset->trust >= dns_trust_secure) {
-                               validator_log(val, ISC_LOG_DEBUG(3),
-                                             "insecurity proof succeeded");
-                               val->event->rdataset->trust = dns_trust_answer;
-                               validator_done(val, ISC_R_SUCCESS);
-                       } else if (!dns_rdataset_isassociated(sigrdataset)) {
-                               validator_log(val, ISC_LOG_DEBUG(3),
-                                             "insecurity proof failed");
-                               validator_done(val, DNS_R_NOTINSECURE);
-                       } else {
-                               dns_name_t *tname;
-                               tname = dns_fixedname_name(&devent->foundname);
-                               result = dns_validator_create(val->view, tname,
-                                                          dns_rdatatype_key,
-                                                          rdataset,
-                                                          sigrdataset, NULL,
-                                                          0, val->task,
-                                                          nullkeyvalidated,
-                                                          val,
-                                                          &val->keyvalidator);
-                               if (result != ISC_R_SUCCESS)
-                                       validator_done(val, result);
-                               /*
-                                * Don't free rdataset & sigrdataset, since
-                                * they'll be freed in nullkeyvalidated.
-                                */
-                               isc_event_free(&event);
-                               UNLOCK(&val->lock);
-                               return;
-                       }
-               }
-       } else if (eresult ==  DNS_R_NCACHENXDOMAIN ||
-                  eresult == DNS_R_NCACHENXRRSET ||
-                  eresult == DNS_R_NXDOMAIN ||
-                  eresult == DNS_R_NXRRSET)
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "dsset with trust %d", rdataset->trust);
+               val->dsset = &val->frdataset;
+               result = validatezonekey(val, ISC_TRUE);
+               if (result != DNS_R_WAIT)
+                       validator_done(val, result);
+       } else if (eresult == DNS_R_NXRRSET ||
+                  eresult == DNS_R_NCACHENXRRSET)
        {
-               /*
-                * No keys.
-                */
-               validator_log(val, ISC_LOG_DEBUG(3), "no keys found");
-               result = proveunsecure(val, ISC_TRUE);
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "falling back to insecurity proof");
+               val->attributes |= VALATTR_INSECURITY;
+               result = proveunsecure(val, ISC_FALSE);
                if (result != DNS_R_WAIT)
                        validator_done(val, result);
        } else {
                validator_log(val, ISC_LOG_DEBUG(3),
-                             "fetch_callback_nullkey: got %s",
+                             "dsfetched: got %s",
                              isc_result_totext(eresult));
                if (eresult == ISC_R_CANCELED)
                        validator_done(val, eresult);
                else
-                       validator_done(val, DNS_R_NOVALIDKEY);
+                       validator_done(val, DNS_R_NOVALIDDS);
        }
+       want_destroy = exit_check(val);
        UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
+}
+
+/*
+ * XXX there's too much duplicated code here.
+ */
+static void
+dsfetched2(isc_task_t *task, isc_event_t *event) {
+       dns_fetchevent_t *devent;
+       dns_validator_t *val;
+       dns_rdataset_t *rdataset;
+       isc_boolean_t want_destroy;
+       isc_result_t result;
+       isc_result_t eresult;
+
+       UNUSED(task);
+       INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+       devent = (dns_fetchevent_t *)event;
+       val = devent->ev_arg;
+       rdataset = &val->frdataset;
+       eresult = devent->result;
 
-       /*
-        * Free stuff from the event.
-        */
-       if (dns_rdataset_isassociated(&val->frdataset))
-               dns_rdataset_disassociate(&val->frdataset);
-       if (dns_rdataset_isassociated(&val->fsigrdataset))
-               dns_rdataset_disassociate(&val->fsigrdataset);
        isc_event_free(&event);
+       dns_resolver_destroyfetch(&val->fetch);
+
+       INSIST(val->event != NULL);
+
+       validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched2");
+       LOCK(&val->lock);
+       if (eresult == DNS_R_NXRRSET || eresult == DNS_R_NCACHENXRRSET) {
+               /*
+                * There is no DS.  We're done.
+                */
+               val->event->rdataset->trust = dns_trust_answer;
+               validator_done(val, ISC_R_SUCCESS);
+       } else if (eresult == ISC_R_SUCCESS ||
+                  eresult == DNS_R_NXDOMAIN ||
+                  eresult == DNS_R_NCACHENXDOMAIN)
+       {
+               /*
+                * Either there is a DS or this is not a zone cut.  Continue.
+                */
+               result = proveunsecure(val, ISC_TRUE);
+               if (result != DNS_R_WAIT)
+                       validator_done(val, result);
+       } else {
+               if (eresult == ISC_R_CANCELED)
+                       validator_done(val, eresult);
+               else
+                       validator_done(val, DNS_R_NOVALIDDS);
+       }
+       want_destroy = exit_check(val);
+       UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
 }
 
 static void
 keyvalidated(isc_task_t *task, isc_event_t *event) {
        dns_validatorevent_t *devent;
        dns_validator_t *val;
+       isc_boolean_t want_destroy;
        isc_result_t result;
        isc_result_t eresult;
 
@@ -302,6 +318,7 @@ keyvalidated(isc_task_t *task, isc_event_t *event) {
        eresult = devent->result;
 
        isc_event_free(&event);
+       dns_validator_destroy(&val->subvalidator);
 
        INSIST(val->event != NULL);
 
@@ -316,27 +333,61 @@ keyvalidated(isc_task_t *task, isc_event_t *event) {
                if (val->frdataset.trust >= dns_trust_secure)
                        (void) get_dst_key(val, val->siginfo, &val->frdataset);
                result = validate(val, ISC_TRUE);
-               if (result != DNS_R_WAIT) {
+               if (result != DNS_R_WAIT)
                        validator_done(val, result);
-                       goto out;
-               }
        } else {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "keyvalidated: got %s",
                              isc_result_totext(eresult));
                validator_done(val, eresult);
        }
- out:
+       want_destroy = exit_check(val);
+       UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
+}
+
+static void
+dsvalidated(isc_task_t *task, isc_event_t *event) {
+       dns_validatorevent_t *devent;
+       dns_validator_t *val;
+       isc_boolean_t want_destroy;
+       isc_result_t result;
+       isc_result_t eresult;
+
+       UNUSED(task);
+       INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
+
+       devent = (dns_validatorevent_t *)event;
+       val = devent->ev_arg;
+       eresult = devent->result;
+
+       isc_event_free(&event);
+       dns_validator_destroy(&val->subvalidator);
+
+       INSIST(val->event != NULL);
 
+       validator_log(val, ISC_LOG_DEBUG(3), "in dsvalidated");
+       LOCK(&val->lock);
+       if (eresult == ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "dsset with trust %d", val->frdataset.trust);
+               if ((val->attributes & VALATTR_INSECURITY) != 0)
+                       result = proveunsecure(val, ISC_TRUE);
+               else
+                       result = validatezonekey(val, ISC_TRUE);
+               if (result != DNS_R_WAIT)
+                       validator_done(val, result);
+       } else {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "dsvalidated: got %s",
+                             isc_result_totext(eresult));
+               validator_done(val, eresult);
+       }
+       want_destroy = exit_check(val);
        UNLOCK(&val->lock);
-       dns_validator_destroy(&val->keyvalidator);
-       /*
-        * Free stuff from the event.
-        */
-       if (dns_rdataset_isassociated(&val->frdataset))
-               dns_rdataset_disassociate(&val->frdataset);
-       if (dns_rdataset_isassociated(&val->fsigrdataset))
-               dns_rdataset_disassociate(&val->fsigrdataset);
+       if (want_destroy)
+               destroy(val);
 }
 
 static isc_boolean_t
@@ -452,6 +503,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
        dns_validatorevent_t *devent;
        dns_validator_t *val;
        dns_rdataset_t *rdataset, *sigrdataset;
+       isc_boolean_t want_destroy;
        isc_result_t result;
        isc_result_t eresult;
 
@@ -463,7 +515,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
        sigrdataset = devent->sigrdataset;
        val = devent->ev_arg;
        eresult = devent->result;
-       dns_validator_destroy(&val->authvalidator);
+       dns_validator_destroy(&val->subvalidator);
 
        INSIST(val->event != NULL);
 
@@ -473,9 +525,13 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "authvalidated: got %s",
                              isc_result_totext(eresult));
-               result = nxtvalidate(val, ISC_TRUE);
-               if (result != DNS_R_WAIT)
+               if (result == ISC_R_CANCELED)
                        validator_done(val, result);
+               else {
+                       result = nxtvalidate(val, ISC_TRUE);
+                       if (result != DNS_R_WAIT)
+                               validator_done(val, result);
+               }
        } else {
                if (rdataset->type == dns_rdatatype_nxt &&
                    nxtprovesnonexistence(val, devent->name, rdataset,
@@ -486,7 +542,10 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
                if (result != DNS_R_WAIT)
                        validator_done(val, result);
        }
+       want_destroy = exit_check(val);
        UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
 
        /*
         * Free stuff from the event.
@@ -498,6 +557,7 @@ static void
 negauthvalidated(isc_task_t *task, isc_event_t *event) {
        dns_validatorevent_t *devent;
        dns_validator_t *val;
+       isc_boolean_t want_destroy;
        isc_result_t eresult;
 
        UNUSED(task);
@@ -507,7 +567,7 @@ negauthvalidated(isc_task_t *task, isc_event_t *event) {
        val = devent->ev_arg;
        eresult = devent->result;
        isc_event_free(&event);
-       dns_validator_destroy(&val->authvalidator);
+       dns_validator_destroy(&val->subvalidator);
 
        INSIST(val->event != NULL);
 
@@ -525,95 +585,84 @@ negauthvalidated(isc_task_t *task, isc_event_t *event) {
                              isc_result_totext(eresult));
                validator_done(val, eresult);
        }
+       want_destroy = exit_check(val);
        UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
+}
 
-       /*
-        * Free stuff from the event.
-        */
+static inline isc_result_t
+view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
        if (dns_rdataset_isassociated(&val->frdataset))
                dns_rdataset_disassociate(&val->frdataset);
-}
-
-static void
-nullkeyvalidated(isc_task_t *task, isc_event_t *event) {
-       dns_validatorevent_t *devent;
-       dns_validator_t *val;
-       isc_result_t result;
-       isc_result_t eresult;
-
-       UNUSED(task);
-       INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
-
-       devent = (dns_validatorevent_t *)event;
-       val = devent->ev_arg;
-       eresult = devent->result;
+       if (dns_rdataset_isassociated(&val->fsigrdataset))
+               dns_rdataset_disassociate(&val->fsigrdataset);
 
-       dns_name_free(devent->name, val->view->mctx);
-       isc_mem_put(val->view->mctx, devent->name, sizeof(dns_name_t));
-       dns_validator_destroy(&val->keyvalidator);
-       isc_event_free(&event);
+       if (val->view->zonetable == NULL)
+               return (ISC_R_CANCELED);
+       return (dns_view_simplefind(val->view, name, type, 0,
+                                   DNS_DBFIND_PENDINGOK, ISC_FALSE,
+                                   &val->frdataset, &val->fsigrdataset));
+}
 
-       INSIST(val->event != NULL);
+static inline isc_boolean_t
+check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
+       dns_validator_t *parent;
 
-       validator_log(val, ISC_LOG_DEBUG(3), "in nullkeyvalidated");
-       LOCK(&val->lock);
-       if (eresult == ISC_R_SUCCESS) {
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "proved that name is in an unsecure domain");
-               validator_log(val, ISC_LOG_DEBUG(3), "marking as answer");
-               val->event->rdataset->trust = dns_trust_answer;
-               validator_done(val, ISC_R_SUCCESS);
-       } else {
-               result = proveunsecure(val, ISC_TRUE);
-               if (result != DNS_R_WAIT)
-                       validator_done(val, result);
+       for (parent = val->parent; parent != NULL; parent = parent->parent) {
+               if (parent->event != NULL &&
+                   parent->event->type == type &&
+                   dns_name_equal(parent->event->name, name))
+               {
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "continuing validation would lead to "
+                                     "deadlock: aborting validation");
+                       return (ISC_TRUE);
+               }
        }
-       UNLOCK(&val->lock);
+       return (ISC_FALSE);
+}
 
-       /*
-        * Free stuff from the event.
-        */
+static inline isc_result_t
+create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
+            isc_taskaction_t callback, const char *caller)
+{
        if (dns_rdataset_isassociated(&val->frdataset))
                dns_rdataset_disassociate(&val->frdataset);
        if (dns_rdataset_isassociated(&val->fsigrdataset))
                dns_rdataset_disassociate(&val->fsigrdataset);
+
+       if (check_deadlock(val, name, type))
+               return (DNS_R_NOVALIDSIG);
+
+       validator_logcreate(val, name, type, caller, "fetch");
+       return (dns_resolver_createfetch(val->view->resolver, name, type,
+                                        NULL, NULL, NULL, 0,
+                                        val->event->ev_sender,
+                                        callback, val,
+                                        &val->frdataset,
+                                        &val->fsigrdataset,
+                                        &val->fetch));
 }
 
-/*
- * Try to find a null zone key among those in 'rdataset'.  If found, build
- * a dst_key_t for it and point val->key at it.
- */
-static isc_boolean_t
-containsnullkey(dns_validator_t *val, dns_rdataset_t *rdataset) {
+static inline isc_result_t
+create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
+                dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+                isc_taskaction_t action, const char *caller)
+{
        isc_result_t result;
-       dst_key_t *key = NULL;
-       isc_buffer_t b;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       isc_boolean_t found = ISC_FALSE;
 
-       result = dns_rdataset_first(rdataset);
-       if (result != ISC_R_SUCCESS)
-               return (ISC_FALSE);
-       while (result == ISC_R_SUCCESS && !found) {
-               dns_rdataset_current(rdataset, &rdata);
-               isc_buffer_init(&b, rdata.data, rdata.length);
-               isc_buffer_add(&b, rdata.length);
-               key = NULL;
-               /*
-                * The key name is unimportant, so we can avoid any name/text
-                * conversion.
-                */
-               result = dst_key_fromdns(dns_rootname, rdata.rdclass, &b,
-                                        val->view->mctx, &key);
-               if (result != ISC_R_SUCCESS)
-                       continue;
-               if (dst_key_isnullkey(key))
-                       found = ISC_TRUE;
-               dst_key_free(&key);
-               dns_rdata_reset(&rdata);
-               result = dns_rdataset_next(rdataset);
-       }
-       return (found);
+       if (check_deadlock(val, name, type))
+               return (DNS_R_NOVALIDSIG);
+
+       validator_logcreate(val, name, type, caller, "validator");
+       result = dns_validator_create(val->view, name, type,
+                                     rdataset, sigrdataset, NULL, 0,
+                                     val->task, action, val,
+                                     &val->subvalidator);
+       if (result == ISC_R_SUCCESS)
+               val->subvalidator->parent = val;
+       return (result);
 }
 
 /*
@@ -703,47 +752,26 @@ get_key(dns_validator_t *val, dns_rdata_sig_t *siginfo) {
            namereln != dns_namereln_equal)
                return (DNS_R_CONTINUE);
 
-       /*
-        * Is the key used for the signature a security root?
-        */
-       INSIST(val->keynode == NULL);
-       result = dns_keytable_findkeynode(val->keytable,
-                                         &siginfo->signer,
-                                         siginfo->algorithm, siginfo->keyid,
-                                         &val->keynode);
-       if (result == ISC_R_SUCCESS) {
+       if (namereln == dns_namereln_equal) {
                /*
-                * The key is a security root.
+                * If this is a self-signed keyset, it must not be a zone key
+                * (since get_key is not called from validatezonekey).
                 */
-               val->key = dns_keynode_key(val->keynode);
-               return (ISC_R_SUCCESS);
-       }
+               if (val->event->rdataset->type == dns_rdatatype_key)
+                       return (DNS_R_CONTINUE);
 
-       /*
-        * A key set may not be self-signed unless the signing key is a
-        * security root.  We don't want a KEY RR to authenticate
-        * itself, so we ignore the signature if it was not made by
-        * an ancestor of the KEY or a preconfigured key.
-        */
-       if (val->event->rdataset->type == dns_rdatatype_key &&
-           namereln == dns_namereln_equal)
-       {
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "keyset was self-signed but not preconfigured");
-               return (DNS_R_CONTINUE);
+               /*
+                * Records appearing in the parent zone at delegation
+                * points cannot be self-signed.
+                */
+               if (dns_rdatatype_atparent(val->event->rdataset->type))
+                       return (DNS_R_CONTINUE);
        }
 
        /*
         * Do we know about this key?
         */
-       if (dns_rdataset_isassociated(&val->frdataset))
-               dns_rdataset_disassociate(&val->frdataset);
-       if (dns_rdataset_isassociated(&val->fsigrdataset))
-               dns_rdataset_disassociate(&val->fsigrdataset);
-       result = dns_view_simplefind(val->view, &siginfo->signer,
-                                    dns_rdatatype_key, 0,
-                                    DNS_DBFIND_PENDINGOK, ISC_FALSE,
-                                    &val->frdataset, &val->fsigrdataset);
+       result = view_find(val, &siginfo->signer, dns_rdatatype_key);
        if (result == ISC_R_SUCCESS) {
                /*
                 * We have an rrset for the given keyname.
@@ -755,17 +783,12 @@ get_key(dns_validator_t *val, dns_rdata_sig_t *siginfo) {
                        /*
                         * We know the key but haven't validated it yet.
                         */
-                       result = dns_validator_create(val->view,
-                                                     &siginfo->signer,
-                                                     dns_rdatatype_key,
-                                                     &val->frdataset,
-                                                     &val->fsigrdataset,
-                                                     NULL,
-                                                     0,
-                                                     val->task,
-                                                     keyvalidated,
-                                                     val,
-                                                     &val->keyvalidator);
+                       result = create_validator(val, &siginfo->signer,
+                                                 dns_rdatatype_key,
+                                                 &val->frdataset,
+                                                 &val->fsigrdataset,
+                                                 keyvalidated,
+                                                 "get_key");
                        if (result != ISC_R_SUCCESS)
                                return (result);
                        return (DNS_R_WAIT);
@@ -803,17 +826,8 @@ get_key(dns_validator_t *val, dns_rdata_sig_t *siginfo) {
                /*
                 * We don't know anything about this key.
                 */
-               val->fetch = NULL;
-               result = dns_resolver_createfetch(val->view->resolver,
-                                                 &siginfo->signer,
-                                                 dns_rdatatype_key,
-                                                 NULL, NULL, NULL, 0,
-                                                 val->event->ev_sender,
-                                                 fetch_callback_validator,
-                                                 val,
-                                                 &val->frdataset,
-                                                 &val->fsigrdataset,
-                                                 &val->fetch);
+               result = create_fetch(val, &siginfo->signer, dns_rdatatype_key,
+                                     fetch_callback_validator, "get_key");
                if (result != ISC_R_SUCCESS)
                        return (result);
                return (DNS_R_WAIT);
@@ -837,66 +851,71 @@ get_key(dns_validator_t *val, dns_rdata_sig_t *siginfo) {
        return (result);
 }
 
+static dns_keytag_t
+compute_keytag(dns_rdata_t *rdata, dns_rdata_key_t *key) {
+       isc_region_t r;
+
+       dns_rdata_toregion(rdata, &r);
+       return (dst_region_computeid(&r, key->algorithm));
+}
+
 /*
- * If the rdataset being validated is a key set, is each key a security root?
+ * Is this keyset self-signed?
  */
 static isc_boolean_t
-issecurityroot(dns_validator_t *val) {
-       dns_name_t *name;
-       dns_rdataset_t *rdataset;
-       isc_mem_t *mctx;
+isselfsigned(dns_validator_t *val) {
+       dns_rdataset_t *rdataset, *sigrdataset;
        dns_rdata_t rdata = DNS_RDATA_INIT;
+       dns_rdata_t sigrdata = DNS_RDATA_INIT;
+       dns_rdata_key_t key;
+       dns_rdata_sig_t sig;
+       dns_keytag_t keytag;
        isc_result_t result;
-       dns_keynode_t *keynode, *nextnode;
-       dst_key_t *key, *secrootkey;
-       isc_boolean_t match = ISC_FALSE;
 
-       name = val->event->name;
        rdataset = val->event->rdataset;
-       mctx = val->view->mctx;
+       sigrdataset = val->event->sigrdataset;
+
+       INSIST(rdataset->type == dns_rdatatype_key);
 
        for (result = dns_rdataset_first(rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(rdataset))
        {
-               dns_rdataset_current(rdataset, &rdata);
-               key = NULL;
-               result = dns_dnssec_keyfromrdata(name, &rdata, mctx, &key);
                dns_rdata_reset(&rdata);
-               if (result != ISC_R_SUCCESS)
-                       continue;
-               keynode = NULL;
-               result = dns_keytable_findkeynode(
-                                               val->keytable, name,
-                                               (dns_secalg_t)dst_key_alg(key),
-                                               dst_key_id(key),
-                                               &keynode);
-
-               match = ISC_FALSE;
-               while (result == ISC_R_SUCCESS) {
-                       secrootkey = dns_keynode_key(keynode);
-                       if (dst_key_compare(key, secrootkey)) {
-                               match = ISC_TRUE;
-                               dns_keytable_detachkeynode(val->keytable,
-                                                          &keynode);
-                               break;
-                       }
-                       nextnode = NULL;
-                       result = dns_keytable_findnextkeynode(val->keytable,
-                                                             keynode,
-                                                             &nextnode);
-                       dns_keytable_detachkeynode(val->keytable, &keynode);
-               }
+               dns_rdataset_current(rdataset, &rdata);
+               (void)dns_rdata_tostruct(&rdata, &key, NULL);
+               keytag = compute_keytag(&rdata, &key);
+               for (result = dns_rdataset_first(sigrdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(sigrdataset))
+               {
+                       dns_rdata_reset(&sigrdata);
+                       dns_rdataset_current(sigrdataset, &sigrdata);
+                       (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
 
-               dst_key_free(&key);
-               if (!match)
-                       return (ISC_FALSE);
+                       if (sig.algorithm == key.algorithm &&
+                           sig.keyid == keytag)
+                               return (ISC_TRUE);
+               }
        }
-       return (match);
+       return (ISC_FALSE);
+}
+
+static isc_result_t
+verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata) {
+       isc_result_t result;
+
+       val->attributes |= VALATTR_TRIEDVERIFY;
+       result = dns_dnssec_verify(val->event->name, val->event->rdataset,
+                                  key, ISC_FALSE, val->view->mctx, rdata);
+       validator_log(val, ISC_LOG_DEBUG(3),
+                     "verify rdataset: %s",
+                     isc_result_totext(result));
+       return (result);
 }
 
 /*
- * Attempts positive response validation.
+ * Attempts positive response validation of a normal RRset.
  *
  * Returns:
  *     ISC_R_SUCCESS   Validation completed successfully
@@ -916,27 +935,6 @@ validate(dns_validator_t *val, isc_boolean_t resume) {
 
        event = val->event;
 
-       /*
-        * If this is a security root, it's ok.
-        */
-       if (val->event->type == dns_rdatatype_key && !resume) {
-               dns_fixedname_t fsecroot;
-               dns_name_t *secroot;
-
-               dns_fixedname_init(&fsecroot);
-               secroot = dns_fixedname_name(&fsecroot);
-               result = dns_keytable_finddeepestmatch(val->keytable,
-                                                      val->event->name,
-                                                      secroot);
-               if (result == ISC_R_SUCCESS &&
-                   dns_name_equal(val->event->name, secroot) &&
-                   issecurityroot(val))
-               {
-                       val->event->rdataset->trust = dns_trust_secure;
-                       return (ISC_R_SUCCESS);
-               }
-       }
-
        if (resume) {
                /*
                 * We already have a sigrdataset.
@@ -990,14 +988,7 @@ validate(dns_validator_t *val, isc_boolean_t resume) {
                }
 
                do {
-                       val->attributes |= VALATTR_TRIEDVERIFY;
-                       result = dns_dnssec_verify(event->name,
-                                                  event->rdataset,
-                                                  val->key, ISC_FALSE,
-                                                  val->view->mctx, &rdata);
-                       validator_log(val, ISC_LOG_DEBUG(3),
-                                     "verify rdataset: %s",
-                                     isc_result_totext(result));
+                       result = verify(val, val->key, &rdata);
                        if (result == ISC_R_SUCCESS)
                                break;
                        if (val->keynode != NULL) {
@@ -1071,6 +1062,271 @@ validate(dns_validator_t *val, isc_boolean_t resume) {
        return (DNS_R_NOVALIDSIG);
 }
 
+/*
+ * Attempts positive response validation of an RRset containing zone keys.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS   Validation completed successfully
+ *     DNS_R_WAIT      Validation has started but is waiting
+ *                     for an event.
+ *     Other return codes are possible and all indicate failure.
+ */
+static isc_result_t
+validatezonekey(dns_validator_t *val, isc_boolean_t resume) {
+       isc_result_t result;
+       dns_validatorevent_t *event;
+       dns_rdataset_t trdataset;
+       dns_rdata_t dsrdata = DNS_RDATA_INIT;
+       dns_rdata_t newdsrdata = DNS_RDATA_INIT;
+       dns_rdata_t keyrdata = DNS_RDATA_INIT;
+       dns_rdata_t sigrdata = DNS_RDATA_INIT;
+       unsigned char dsbuf[DNS_DS_BUFFERSIZE];
+       dns_keytag_t keytag;
+       dns_rdata_ds_t ds;
+       dns_rdata_key_t key;
+       dns_rdata_sig_t sig;
+       dst_key_t *dstkey;
+
+       UNUSED(resume);
+
+       /*
+        * Caller must be holding the validator lock.
+        */
+
+       event = val->event;
+
+       if (val->dsset == NULL) {
+               /*
+                * First, see if this key was signed by a trusted key.
+                */
+               for (result = dns_rdataset_first(val->event->sigrdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(val->event->sigrdataset))
+               {
+                       dns_keynode_t *keynode = NULL, *nextnode = NULL;
+
+                       dns_rdata_reset(&sigrdata);
+                       dns_rdataset_current(val->event->sigrdataset,
+                                            &sigrdata);
+                       (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+                       result = dns_keytable_findkeynode(val->keytable,
+                                                         val->event->name,
+                                                         sig.algorithm,
+                                                         sig.keyid,
+                                                         &keynode);
+                       while (result == ISC_R_SUCCESS) {
+                               dstkey = dns_keynode_key(keynode);
+                               result = verify(val, dstkey, &sigrdata);
+                               if (result == ISC_R_SUCCESS) {
+                                       dns_keytable_detachkeynode(val->keytable,
+                                                                  &keynode);
+                                       break;
+                               }
+                               result = dns_keytable_findnextkeynode(
+                                                               val->keytable,
+                                                               keynode,
+                                                               &nextnode);
+                               dns_keytable_detachkeynode(val->keytable,
+                                                          &keynode);
+                               keynode = nextnode;
+                       }
+                       if (result == ISC_R_SUCCESS) {
+                               event->rdataset->trust = dns_trust_secure;
+                               event->sigrdataset->trust = dns_trust_secure;
+                               validator_log(val, ISC_LOG_DEBUG(3),
+                                             "signed by trusted key; "
+                                             "marking as secure");
+                               return (result);
+                       }
+               }
+
+               /*
+                * If this is the root name and there was no trusted key,
+                * give up, since there's no DS at the root.
+                */
+               if (dns_name_equal(event->name, dns_rootname)) {
+                       if ((val->attributes & VALATTR_TRIEDVERIFY) != 0)
+                               return (DNS_R_NOVALIDSIG);
+                       else
+                               return (DNS_R_NOVALIDDS);
+               }
+
+               /*
+                * Otherwise, try to find the DS record.
+                */
+               result = view_find(val, val->event->name, dns_rdatatype_ds);
+               if (result == ISC_R_SUCCESS) {
+                       /*
+                        * We have DS records.
+                        */
+                       val->dsset = &val->frdataset;
+                       if (val->frdataset.trust == dns_trust_pending &&
+                           dns_rdataset_isassociated(&val->fsigrdataset))
+                       {
+                               result = create_validator(val,
+                                                         val->event->name,
+                                                         dns_rdatatype_ds,
+                                                         &val->frdataset,
+                                                         &val->fsigrdataset,
+                                                         dsvalidated,
+                                                         "validatezonekey");
+                               if (result != ISC_R_SUCCESS)
+                                       return (result);
+                               return (DNS_R_WAIT);
+                       } else if (val->frdataset.trust == dns_trust_pending) {
+                               /*
+                                * There should never be an unsigned DS.
+                                */
+                               dns_rdataset_disassociate(&val->frdataset);
+                               validator_log(val, ISC_LOG_DEBUG(2),
+                                             "unsigned DS record");
+                               return (DNS_R_NOVALIDSIG);
+                       } else
+                               result = ISC_R_SUCCESS;
+               } else if (result == ISC_R_NOTFOUND) {
+                       /*
+                        * We don't have the DS.  Find it.
+                        */
+                       result = create_fetch(val, val->event->name,
+                                             dns_rdatatype_ds, dsfetched,
+                                             "validatezonekey");
+                       if (result != ISC_R_SUCCESS)
+                               return (result);
+                       return (DNS_R_WAIT);
+               } else if (result ==  DNS_R_NCACHENXDOMAIN ||
+                          result == DNS_R_NCACHENXRRSET ||
+                          result == DNS_R_NXDOMAIN ||
+                          result == DNS_R_NXRRSET)
+               {
+                       /*
+                        * The DS does not exist.
+                        */
+                       if (dns_rdataset_isassociated(&val->frdataset))
+                               dns_rdataset_disassociate(&val->frdataset);
+                       if (dns_rdataset_isassociated(&val->fsigrdataset))
+                               dns_rdataset_disassociate(&val->fsigrdataset);
+                       validator_log(val, ISC_LOG_DEBUG(2), "no DS record");
+                       return (DNS_R_NOVALIDSIG);
+               }
+       }
+
+       /*
+        * We have a DS set.
+        */
+       INSIST(val->dsset != NULL);
+
+       if (val->dsset->trust < dns_trust_secure) {
+               val->event->rdataset->trust = dns_trust_answer;
+               val->event->sigrdataset->trust = dns_trust_answer;
+               return (ISC_R_SUCCESS);
+       }
+
+       /*
+        * Look through the DS record and find the keys that can sign the
+        * key set and the matching signature.  For each such key, attempt
+        * verification.
+        */
+
+       for (result = dns_rdataset_first(val->dsset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(val->dsset))
+       {
+               dns_rdata_reset(&dsrdata);
+               dns_rdataset_current(val->dsset, &dsrdata);
+               (void)dns_rdata_tostruct(&dsrdata, &ds, NULL);
+
+               dns_rdataset_init(&trdataset);
+               dns_rdataset_clone(val->event->rdataset, &trdataset);
+
+               for (result = dns_rdataset_first(&trdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&trdataset))
+               {
+                       dns_rdata_reset(&keyrdata);
+                       dns_rdataset_current(&trdataset, &keyrdata);
+                       (void)dns_rdata_tostruct(&keyrdata, &key, NULL);
+                       keytag = compute_keytag(&keyrdata, &key);
+                       if (ds.key_tag != keytag ||
+                           ds.algorithm != key.algorithm)
+                               continue;
+                       dns_rdata_reset(&newdsrdata);
+                       result = dns_ds_buildrdata(val->event->name,
+                                                  &keyrdata, ds.digest_type,
+                                                  dsbuf, &newdsrdata);
+                       if (result != ISC_R_SUCCESS)
+                               continue;
+                       if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0)
+                               break;
+               }
+               if (result != ISC_R_SUCCESS) {
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "no KEY matching DS");
+                       continue;
+               }
+               
+               for (result = dns_rdataset_first(val->event->sigrdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(val->event->sigrdataset))
+               {
+                       dns_rdata_reset(&sigrdata);
+                       dns_rdataset_current(val->event->sigrdataset,
+                                            &sigrdata);
+                       (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+                       if (ds.key_tag == sig.keyid &&
+                           ds.algorithm == sig.algorithm)
+                               break;
+               }
+               if (result != ISC_R_SUCCESS) {
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "no SIG matching DS key");
+                       continue;
+               }
+
+               dstkey = NULL;
+               result = dns_dnssec_keyfromrdata(val->event->name,
+                                                &keyrdata,
+                                                val->view->mctx,
+                                                &dstkey);
+               if (result != ISC_R_SUCCESS)
+                       /*
+                        * This really shouldn't happen, but...
+                        */
+                       continue;
+
+               result = verify(val, dstkey, &sigrdata);
+               dst_key_free(&dstkey);
+               dns_rdataset_disassociate(&trdataset);
+               if (result == ISC_R_SUCCESS)
+                       break;
+       }
+       if (result == ISC_R_SUCCESS) {
+               event->rdataset->trust = dns_trust_secure;
+               event->sigrdataset->trust = dns_trust_secure;
+               validator_log(val, ISC_LOG_DEBUG(3), "marking as secure");
+               return (result);
+       } else
+               return (DNS_R_NOVALIDSIG);
+}
+
+/*
+ * Starts a positive response validation.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS   Validation completed successfully
+ *     DNS_R_WAIT      Validation has started but is waiting
+ *                     for an event.
+ *     Other return codes are possible and all indicate failure.
+ */
+static isc_result_t
+start_positive_validation(dns_validator_t *val) {
+       /*
+        * If this is not a key, go straight into validate().
+        */
+       if (val->event->type != dns_rdatatype_key || !isselfsigned(val))
+               return (validate(val, ISC_FALSE));
+
+       return (validatezonekey(val, ISC_FALSE));
+}
 
 static isc_result_t
 nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
@@ -1078,11 +1334,9 @@ nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
        dns_message_t *message = val->event->message;
        isc_result_t result;
 
-       if (!resume) {
+       if (!resume)
                result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
-               if (result != ISC_R_SUCCESS)
-                       validator_done(val, ISC_R_NOTFOUND);
-       } else {
+       else {
                result = ISC_R_SUCCESS;
                validator_log(val, ISC_LOG_DEBUG(3), "resuming nxtvalidate");
        }
@@ -1110,6 +1364,9 @@ nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
                        if (rdataset->type == dns_rdatatype_sig)
                                continue;
 
+                       if (rdataset->type == dns_rdatatype_soa)
+                               val->soaset = rdataset;
+
                        for (sigrdataset = ISC_LIST_HEAD(name->list);
                             sigrdataset != NULL;
                             sigrdataset = ISC_LIST_NEXT(sigrdataset,
@@ -1148,17 +1405,11 @@ nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
                                                        dns_rdatatype_soa))
                                        continue;
                        }
-                       val->authvalidator = NULL;
                        val->currentset = rdataset;
-                       result = dns_validator_create(val->view, name,
-                                                     rdataset->type,
-                                                     rdataset,
-                                                     sigrdataset,
-                                                     NULL, 0,
-                                                     val->task,
-                                                     authvalidated,
-                                                     val,
-                                                     &val->authvalidator);
+                       result = create_validator(val, name, rdataset->type,
+                                                 rdataset, sigrdataset,
+                                                 authvalidated,
+                                                 "nxtvalidate");
                        if (result != ISC_R_SUCCESS)
                                return (result);
                        return (DNS_R_WAIT);
@@ -1168,18 +1419,14 @@ nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
        if (result == ISC_R_NOMORE)
                result = ISC_R_SUCCESS;
        if (result != ISC_R_SUCCESS)
-               validator_done(val, result);
+               return (result);
 
        if ((val->attributes & VALATTR_FOUNDNONEXISTENCE) == 0) {
-               if (!val->seensig) {
-                       result = dns_validator_create(val->view, name,
-                                                     dns_rdatatype_soa,
-                                                     &val->frdataset,
-                                                     NULL, NULL, 0,
-                                                     val->task,
-                                                     negauthvalidated,
-                                                     val,
-                                                     &val->authvalidator);
+               if (!val->seensig && val->soaset != NULL) {
+                       result = create_validator(val, name, dns_rdatatype_soa,
+                                                 val->soaset, NULL,
+                                                 negauthvalidated,
+                                                 "nxtvalidate");
                        if (result != ISC_R_SUCCESS)
                                return (result);
                        return (DNS_R_WAIT);
@@ -1197,11 +1444,10 @@ nxtvalidate(dns_validator_t *val, isc_boolean_t resume) {
 static isc_result_t
 proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
        isc_result_t result;
-       dns_fixedname_t secroot, tfname;
+       dns_fixedname_t secroot;
        dns_name_t *tname;
 
        dns_fixedname_init(&secroot);
-       dns_fixedname_init(&tfname);
        result = dns_keytable_finddeepestmatch(val->keytable,
                                               val->event->name,
                                               dns_fixedname_name(&secroot));
@@ -1214,17 +1460,6 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
        else if (result != ISC_R_SUCCESS)
                return (result);
 
-       /*
-        * If this is a security root, it's ok.
-        */
-       if (val->event->type == dns_rdatatype_key &&
-           dns_name_equal(val->event->name, dns_fixedname_name(&secroot)) &&
-           issecurityroot(val))
-       {
-               val->event->rdataset->trust = dns_trust_secure;
-               return (ISC_R_SUCCESS);
-       }
-
        if (!resume)
                val->labels = dns_name_depth(dns_fixedname_name(&secroot)) + 1;
        else {
@@ -1239,11 +1474,10 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
                char namebuf[DNS_NAME_FORMATSIZE];
 
                if (val->labels == dns_name_depth(val->event->name)) {
-                       if (val->event->type == dns_rdatatype_key)
-                               break;
                        tname = val->event->name;
                } else {
-                       tname = dns_fixedname_name(&tfname);
+                       dns_fixedname_init(&val->fname);
+                       tname = dns_fixedname_name(&val->fname);
                        result = dns_name_splitatdepth(val->event->name,
                                                       val->labels,
                                                       NULL, tname);
@@ -1253,91 +1487,84 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
 
                dns_name_format(tname, namebuf, sizeof(namebuf));
                validator_log(val, ISC_LOG_DEBUG(3),
-                             "looking for null keyset at '%s'",
+                             "checking existence of DS at '%s'",
                              namebuf);
 
-               if (dns_rdataset_isassociated(&val->frdataset))
-                       dns_rdataset_disassociate(&val->frdataset);
-               if (dns_rdataset_isassociated(&val->fsigrdataset))
-                       dns_rdataset_disassociate(&val->fsigrdataset);
-
-               result = dns_view_simplefind(val->view, tname,
-                                            dns_rdatatype_key, 0,
-                                            DNS_DBFIND_PENDINGOK, ISC_FALSE,
-                                            &val->frdataset,
-                                            &val->fsigrdataset);
-               if (result == ISC_R_SUCCESS) {
-                       dns_name_t *fname = NULL;
-
-                       if (!dns_rdataset_isassociated(&val->fsigrdataset)) {
-                               result = DNS_R_NOTINSECURE;
+               result = view_find(val, tname, dns_rdatatype_ds);
+               if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
+                       /*
+                        * There is no DS.  We're hopefully done.
+                        */
+                       if (val->frdataset.trust < dns_trust_secure) {
+                               /*
+                                * This shouldn't happen, since the negative
+                                * response should have been validated.  Since
+                                * there's no way of validating existing
+                                * negative response blobs, give up.
+                                */
+                               result = DNS_R_NOVALIDSIG;
                                goto out;
                        }
-                       validator_log(val, ISC_LOG_DEBUG(3),
-                                     "found keyset, looking for null key");
-                       if (!containsnullkey(val, &val->frdataset))
+                       val->event->rdataset->trust = dns_trust_answer;
+                       return (ISC_R_SUCCESS);
+               } else if (result == ISC_R_SUCCESS) {
+                       /*
+                        * There is a DS here.  Verify that it's secure and
+                        * continue.
+                        */
+                       if (val->frdataset.trust >= dns_trust_secure)
                                continue;
-
-                       if (val->frdataset.trust >= dns_trust_secure) {
-                               validator_log(val, ISC_LOG_DEBUG(3),
-                                             "insecurity proof succeeded");
-                               val->event->rdataset->trust = dns_trust_answer;
-                               result = ISC_R_SUCCESS;
-                               goto out;
-                       }
-
-                       fname = isc_mem_get(val->view->mctx, sizeof(*fname));
-                       if (fname == NULL)
-                               return (ISC_R_NOMEMORY);
-                       dns_name_init(fname, NULL);
-                       result = dns_name_dup(tname, val->view->mctx, fname);
-                       if (result != ISC_R_SUCCESS) {
-                               isc_mem_put(val->view->mctx, fname,
-                                           sizeof(*fname));
-                               result = ISC_R_NOMEMORY;
+                       else if (!dns_rdataset_isassociated(&val->fsigrdataset))
+                       {
+                               result = DNS_R_NOVALIDSIG;
                                goto out;
                        }
-
-                       result = dns_validator_create(val->view,
-                                                     fname,
-                                                     dns_rdatatype_key,
-                                                     &val->frdataset,
-                                                     &val->fsigrdataset,
-                                                     NULL,
-                                                     0,
-                                                     val->task,
-                                                     nullkeyvalidated,
-                                                     val,
-                                                     &val->keyvalidator);
+                       result = create_validator(val, tname, dns_rdatatype_ds,
+                                                 &val->frdataset,
+                                                 &val->fsigrdataset,
+                                                 dsvalidated,
+                                                 "proveunsecure");
                        if (result != ISC_R_SUCCESS)
                                goto out;
                        return (DNS_R_WAIT);
+               } else if (result == DNS_R_NXDOMAIN ||
+                          result == DNS_R_NCACHENXDOMAIN)
+               {
+                       /*
+                        * This is not a zone cut.  Assuming things are
+                        * as expected, continue.
+                        */
+                       if (!dns_rdataset_isassociated(&val->frdataset)) {
+                               /*
+                                * There should be an NXT here, since we
+                                * are still in a secure zone.
+                                */
+                               result = DNS_R_NOVALIDNXT;
+                               goto out;
+                       } else if (val->frdataset.trust < dns_trust_secure) {
+                               /*
+                                * This shouldn't happen, since the negative
+                                * response should have been validated.  Since
+                                * there's no way of validating existing
+                                * negative response blobs, give up.
+                                */
+                               result = DNS_R_NOVALIDSIG;
+                               goto out;
+                       }
+                       continue;
                } else if (result == ISC_R_NOTFOUND) {
-                       val->fetch = NULL;
-                       result = dns_resolver_createfetch(val->view->resolver,
-                                                       tname,
-                                                       dns_rdatatype_key,
-                                                       NULL, NULL, NULL, 0,
-                                                       val->event->ev_sender,
-                                                       fetch_callback_nullkey,
-                                                       val,
-                                                       &val->frdataset,
-                                                       &val->fsigrdataset,
-                                                       &val->fetch);
+                       /*
+                        * We don't know anything about the DS.  Find it.
+                        */
+                       result = create_fetch(val, tname, dns_rdatatype_ds,
+                                             dsfetched2, "proveunsecure");
                        if (result != ISC_R_SUCCESS)
                                goto out;
                        return (DNS_R_WAIT);
-               } else if (result == DNS_R_NCACHENXDOMAIN ||
-                        result == DNS_R_NCACHENXRRSET ||
-                        result == DNS_R_NXDOMAIN ||
-                        result == DNS_R_NXRRSET)
-               {
-                       continue;
-               } else
-                       goto out;
+               }
        }
        validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed");
-       return (DNS_R_NOTINSECURE); /* Didn't find a null key */
+       return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */
 
  out:
        if (dns_rdataset_isassociated(&val->frdataset))
@@ -1351,6 +1578,7 @@ static void
 validator_start(isc_task_t *task, isc_event_t *event) {
        dns_validator_t *val;
        dns_validatorevent_t *vevent;
+       isc_boolean_t want_destroy = ISC_FALSE;
        isc_result_t result = ISC_R_FAILURE;
 
        UNUSED(task);
@@ -1376,13 +1604,16 @@ validator_start(isc_task_t *task, isc_event_t *event) {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "attempting positive response validation");
 
-               result = validate(val, ISC_FALSE);
+               INSIST(dns_rdataset_isassociated(val->event->rdataset));
+               INSIST(dns_rdataset_isassociated(val->event->sigrdataset));
+               result = start_positive_validation(val);
                if (result == DNS_R_NOVALIDSIG &&
                    (val->attributes & VALATTR_TRIEDVERIFY) == 0)
                {
                        saved_result = result;
                        validator_log(val, ISC_LOG_DEBUG(3),
                                      "falling back to insecurity proof");
+                       val->attributes |= VALATTR_INSECURITY;
                        result = proveunsecure(val, ISC_FALSE);
                        if (result == DNS_R_NOTINSECURE)
                                result = saved_result;
@@ -1392,9 +1623,11 @@ validator_start(isc_task_t *task, isc_event_t *event) {
                 * This is either an unsecure subdomain or a response from
                 * a broken server.
                 */
+               INSIST(dns_rdataset_isassociated(val->event->rdataset));
                validator_log(val, ISC_LOG_DEBUG(3),
                              "attempting insecurity proof");
 
+               val->attributes |= VALATTR_INSECURITY;
                result = proveunsecure(val, ISC_FALSE);
        } else if (val->event->rdataset == NULL &&
                   val->event->sigrdataset == NULL)
@@ -1405,6 +1638,7 @@ validator_start(isc_task_t *task, isc_event_t *event) {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "attempting negative response validation");
 
+               val->attributes |= VALATTR_NEGATIVE;
                result = nxtvalidate(val, ISC_FALSE);
        } else {
                /*
@@ -1413,10 +1647,14 @@ validator_start(isc_task_t *task, isc_event_t *event) {
                INSIST(0);
        }
 
-       if (result != DNS_R_WAIT)
+       if (result != DNS_R_WAIT) {
+               want_destroy = exit_check(val);
                validator_done(val, result);
+       }
 
        UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
 }
 
 isc_result_t
@@ -1470,8 +1708,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
        val->options = options;
        val->attributes = 0;
        val->fetch = NULL;
-       val->keyvalidator = NULL;
-       val->authvalidator = NULL;
+       val->subvalidator = NULL;
+       val->parent = NULL;
        val->keytable = NULL;
        dns_keytable_attach(val->view->secroots, &val->keytable);
        val->keynode = NULL;
@@ -1483,6 +1721,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
        val->labels = 0;
        val->currentset = NULL;
        val->keyset = NULL;
+       val->dsset = NULL;
+       val->soaset = NULL;
        val->seensig = ISC_FALSE;
        dns_rdataset_init(&val->frdataset);
        dns_rdataset_init(&val->fsigrdataset);
@@ -1518,11 +1758,8 @@ dns_validator_cancel(dns_validator_t *validator) {
                if (validator->fetch != NULL)
                        dns_resolver_cancelfetch(validator->fetch);
 
-               if (validator->keyvalidator != NULL)
-                       dns_validator_cancel(validator->keyvalidator);
-
-               if (validator->authvalidator != NULL)
-                       dns_validator_cancel(validator->authvalidator);
+               if (validator->subvalidator != NULL)
+                       dns_validator_cancel(validator->subvalidator);
        }
        UNLOCK(&validator->lock);
 }
@@ -1541,10 +1778,8 @@ destroy(dns_validator_t *val) {
                dst_key_free(&val->key);
        if (val->keytable != NULL)
                dns_keytable_detach(&val->keytable);
-       if (val->keyvalidator != NULL)
-               dns_validator_destroy(&val->keyvalidator);
-       if (val->authvalidator != NULL)
-               dns_validator_destroy(&val->authvalidator);
+       if (val->subvalidator != NULL)
+               dns_validator_destroy(&val->subvalidator);
        mctx = val->view->mctx;
        if (val->siginfo != NULL)
                isc_mem_put(mctx, val->siginfo, sizeof(*val->siginfo));
@@ -1565,14 +1800,10 @@ dns_validator_destroy(dns_validator_t **validatorp) {
 
        LOCK(&val->lock);
 
-       REQUIRE(val->event == NULL);
-
+       val->attributes |= VALATTR_SHUTDOWN;
        validator_log(val, ISC_LOG_DEBUG(3), "dns_validator_destroy");
 
-       val->attributes |= VALATTR_SHUTDOWN;
-       if (val->fetch == NULL && val->keyvalidator == NULL &&
-           val->authvalidator == NULL)
-               want_destroy = ISC_TRUE;
+       want_destroy = exit_check(val);
 
        UNLOCK(&val->lock);
 
@@ -1619,3 +1850,17 @@ validator_log(dns_validator_t *val, int level, const char *fmt, ...) {
                       DNS_LOGMODULE_VALIDATOR, level, fmt, ap);
        va_end(ap);
 }
+
+static void
+validator_logcreate(dns_validator_t *val,
+                   dns_name_t *name, dns_rdatatype_t type,
+                   const char *caller, const char *operation)
+{
+       char namestr[DNS_NAME_FORMATSIZE];
+       char typestr[DNS_RDATATYPE_FORMATSIZE];
+
+       dns_name_format(name, namestr, sizeof(namestr));
+       dns_rdatatype_format(type, typestr, sizeof(typestr));
+       validator_log(val, ISC_LOG_DEBUG(9), "%s: creating %s for %s %s",
+                     caller, operation, namestr, typestr);
+}
diff --git a/version b/version
index c1bf10f92219a7f1e72fa5cca7c572ec077c18a5..e8ea5b6aa344e451b07a00c09879201f40c1e8a4 100644 (file)
--- a/version
+++ b/version
@@ -1,4 +1,4 @@
-# $Id: version,v 1.27 2001/08/30 05:02:20 marka Exp $
+# $Id: version,v 1.28 2002/06/17 04:00:59 marka Exp $
 #
 # This file must follow /bin/sh rules.  It is imported directly via
 # configure.