From abce4875c33782ea88253a92d6f6391b3be88995 Mon Sep 17 00:00:00 2001 From: Brian Wellington Date: Fri, 28 Apr 2000 15:47:36 +0000 Subject: [PATCH] Import the parent zone key signature, create null keys for unsigned children or set the zone status bit for signed children. --- bin/dnssec/dnssec-signzone.c | 317 +++++++++++++++++++++++++++++++---- bin/tests/signer.c | 317 +++++++++++++++++++++++++++++++---- 2 files changed, 564 insertions(+), 70 deletions(-) diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index 2c96b60c7a..e2642ca6d7 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -54,9 +54,9 @@ #include +/*#define USE_ZONESTATUS*/ + #define BUFSIZE 2048 -#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \ - == DNS_KEYOWNER_ZONE) typedef struct signer_key_struct signer_key_t; typedef struct signer_array_struct signer_array_t; @@ -76,7 +76,7 @@ static ISC_LIST(signer_key_t) keylist; static isc_stdtime_t starttime = 0, endtime = 0, now; static int cycle = -1; static int verbose; -static int tryverify = 0; +static isc_boolean_t tryverify = ISC_FALSE; static isc_mem_t *mctx = NULL; @@ -172,13 +172,13 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, mctx, b, rdata); check_result(result, "dns_dnssec_sign()"); - if (tryverify != 0) { + if (tryverify) { result = dns_dnssec_verify(name, rdataset, key, ISC_TRUE, mctx, rdata); - if (result == ISC_R_SUCCESS) - vbprintf(3, "\tsignature verified\n"); - else - vbprintf(3, "\tsignature failed to verify\n"); + if (result == ISC_R_SUCCESS) + vbprintf(3, "\tsignature verified\n"); + else + vbprintf(3, "\tsignature failed to verify\n"); } } @@ -525,6 +525,8 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, result = ISC_R_SUCCESS; check_result(result, "dns_db_deleterdataset"); #endif + fatal("File is currently signed but no private keys were " + "found. This won't work."); } trdata = ISC_LIST_HEAD(siglist.rdata); @@ -542,37 +544,195 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, } } +#ifndef USE_ZONESTATUS /* Determine if a KEY set contains a null key */ static isc_boolean_t -hasnullkey(dns_rdataset_t rdataset) { +hasnullkey(dns_rdataset_t *rdataset) { isc_result_t result; dns_rdata_t rdata; - isc_uint32_t flags; + isc_boolean_t found = ISC_FALSE; - result = dns_rdataset_first(&rdataset); + result = dns_rdataset_first(rdataset); while (result == ISC_R_SUCCESS) { dst_key_t *key = NULL; - dns_rdataset_current(&rdataset, &rdata); + dns_rdataset_current(rdataset, &rdata); result = dns_dnssec_keyfromrdata(dns_rootname, &rdata, mctx, &key); check_result(result, "dns_dnssec_keyfromrdata()"); - flags = dst_key_flags(key); - dst_key_free(key); - if (((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) && - ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE)) + if (dst_key_isnullkey(key)) + found = ISC_TRUE; + dst_key_free(key); + if (found == ISC_TRUE) return (ISC_TRUE); - result = dns_rdataset_next(&rdataset); + result = dns_rdataset_next(rdataset); + } + if (result != ISC_R_NOMORE) + check_result(result, "iteration over keys"); + return (ISC_FALSE); +} +#endif + +/* + * Looks for signatures of the zone keys by the parent, and imports them + * if found. + */ +static void +importparentsig(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, + dns_name_t *name, dns_rdataset_t *set) +{ + unsigned char filename[256]; + isc_buffer_t b; + isc_region_t r; + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t newset, sigset; + dns_rdata_t rdata, newrdata; + isc_result_t result; + + isc_buffer_init(&b, filename, sizeof(filename) - 10); + result = dns_name_totext(name, ISC_FALSE, &b); + check_result(result, "dns_name_totext()"); + isc_buffer_usedregion(&b, &r); + strcpy((char *)r.base + r.length, "signedkey"); + result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db), + 0, NULL, &newdb); + check_result(result, "dns_db_create()"); + result = dns_db_load(newdb, filename); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(&newset); + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, 0, + 0, &newset, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (dns_rdataset_count(set) != dns_rdataset_count(&newset)) + goto failure; + + dns_rdata_init(&rdata); + dns_rdata_init(&newrdata); + + result = dns_rdataset_first(set); + check_result(result, "dns_rdata_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_rdata_first()"); + for (; + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&newset)) + { + dns_rdataset_current(&newset, &newrdata); + if (dns_rdata_compare(&rdata, &newrdata) == 0) + break; + } + if (result != ISC_R_SUCCESS) + break; } - if (result != ISC_R_NOMORE) - check_result(result, "iteration over keys"); - return (ISC_FALSE); + if (result != ISC_R_NOMORE) + goto failure; + + vbprintf(2, "found the parent's signature of our zone key\n"); + + result = dns_db_addrdataset(db, node, version, 0, &sigset, 0, NULL); + check_result(result, "dns_db_addrdataset"); + dns_rdataset_disassociate(&newset); + dns_rdataset_disassociate(&sigset); + + failure: + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); +} + +/* + * Looks for our signatures of child keys. If present, inform the caller, + * who will set the zone status (KEY) bit in the NXT record. + */ +static isc_boolean_t +haschildkey(dns_db_t *db, dns_name_t *name) { + unsigned char filename[256]; + isc_buffer_t b; + isc_region_t r; + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t set, sigset; + dns_rdata_t sigrdata; + isc_result_t result; + isc_boolean_t found = ISC_FALSE; + dns_rdata_sig_t sig; + signer_key_t *key; + + isc_buffer_init(&b, filename, sizeof(filename) - 10); + result = dns_name_totext(name, ISC_FALSE, &b); + check_result(result, "dns_name_totext()"); + isc_buffer_usedregion(&b, &r); + strcpy((char *)r.base + r.length, "signedkey"); + result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db), + 0, NULL, &newdb); + check_result(result, "dns_db_create()"); + result = dns_db_load(newdb, filename); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(&set); + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, 0, + 0, &set, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (!dns_rdataset_isassociated(&set) || + !dns_rdataset_isassociated(&sigset)) + goto disfail; + + 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, mctx); + if (result != ISC_R_SUCCESS) + goto disfail; + key = keythatsigned(&sig); + dns_rdata_freestruct(&sig); + if (key == NULL) + goto disfail; + result = dns_dnssec_verify(name, &set, key->key, + ISC_FALSE, mctx, &sigrdata); + if (result == ISC_R_SUCCESS) { + found = ISC_TRUE; + break; + } + } + + disfail: + if (dns_rdataset_isassociated(&set)) + dns_rdataset_disassociate(&set); + if (dns_rdataset_isassociated(&sigset)) + dns_rdataset_disassociate(&sigset); + + failure: + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); + + return (found); } /* * Signs all records at a name. This mostly just signs each set individually, - * but also handles exceptional cases and adds the SIG bit to any NXTs - * generated earlier. + * but also adds the SIG bit to any NXTs generated earlier, deals with + * parent/child KEY signatures, and handles other exceptional cases. */ static void signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, @@ -580,9 +740,10 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, { isc_result_t result; dns_rdata_t rdata; - dns_rdataset_t rdataset, nsset; + dns_rdataset_t rdataset; dns_rdatasetiter_t *rdsiter; isc_boolean_t isdelegation = ISC_FALSE; + isc_boolean_t childkey = ISC_FALSE; static int warnwild = 0; if (dns_name_iswildcard(name)) { @@ -593,6 +754,8 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, "wildcards in secure zones\n"); } if (!atorigin) { + dns_rdataset_t nsset; + dns_rdataset_init(&nsset); result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, 0, 0, &nsset, @@ -615,37 +778,50 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, if (rdataset.type == dns_rdatatype_sig) goto skip; - /* If this is a KEY set at the apex, skip it. */ - if (rdataset.type == dns_rdatatype_key && atorigin) + /* + * If this is a KEY set at the apex, look for a signedkey file. + */ + if (rdataset.type == dns_rdatatype_key && atorigin) { + importparentsig(db, version, node, name, &rdataset); goto skip; + } /* * If this name is a delegation point, skip all records - * except a KEY set containing a NULL key or an NXT set. + * except an NXT set, unless we're using null keys, in + * which case we need to check for a null key and add one + * if it's not present. */ if (isdelegation) { switch (rdataset.type) { - case dns_rdatatype_nxt: + case dns_rdatatype_nxt: + childkey = haschildkey(db, name); + break; +#ifndef USE_ZONESTATUS + case dns_rdatatype_key: + if (hasnullkey(&rdataset)) break; - case dns_rdatatype_key: - if (hasnullkey(rdataset)) - break; - goto skip; - default: - goto skip; + goto skip; +#endif + default: + goto skip; } + } /* * There probably should be a dns_nxtsetbit, but it can get * complicated if we need to extend the length of the * bit set. In this case, since the NXT bit is set and - * SIG < NXT, the easy way works. + * SIG < NXT and KEY < NXT, the easy way works. */ if (rdataset.type == dns_rdatatype_nxt) { unsigned char *nxt_bits; dns_name_t nxtname; isc_region_t r, r2; + unsigned char keydata[4]; + dst_key_t *dstkey; + isc_buffer_t b; result = dns_rdataset_first(&rdataset); check_result(result, "dns_rdataset_first()"); @@ -656,6 +832,77 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, dns_name_toregion(&nxtname, &r2); nxt_bits = r.base + r2.length; set_bit(nxt_bits, dns_rdatatype_sig, 1); +#ifdef USE_ZONESTATUS + if (isdelegation && childkey) { + set_bit(nxt_bits, dns_rdatatype_key, 1); + vbprintf(2, "found a child key for %s, " + "setting KEY bit in NXT\n", + nametostr(name)); + } + +#else + if (isdelegation && !childkey) { + dns_rdataset_t keyset; + dns_rdatalist_t keyrdatalist; + dns_rdata_t keyrdata; + + dns_rdataset_init(&keyset); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_key, + 0, 0, &keyset, + NULL); + if (result == ISC_R_SUCCESS && + hasnullkey(&keyset)) + goto alreadyhavenullkey; + + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + check_result(result, "dns_db_findrdataset"); + + if (dns_rdataset_isassociated(&keyset)) + dns_rdataset_disassociate(&keyset); + + vbprintf(2, "no child key for %s, " + "adding null key\n", + nametostr(name)); + dns_rdatalist_init(&keyrdatalist); + dstkey = NULL; + + result = dst_key_generate("", DNS_KEYALG_DSA, + 0, 0, + DNS_KEYTYPE_NOKEY, + DNS_KEYPROTO_DNSSEC, + mctx, &dstkey); + check_result(result, "dst_key_generate"); + isc_buffer_init(&b, keydata, sizeof keydata); + result = dst_key_todns(dstkey, &b); + dst_key_free(dstkey); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(&keyrdata, + rdataset.rdclass, + dns_rdatatype_key, &r); + + ISC_LIST_APPEND(keyrdatalist.rdata, &keyrdata, + link); + keyrdatalist.rdclass = rdataset.rdclass; + keyrdatalist.type = dns_rdatatype_key; + keyrdatalist.covers = 0; + keyrdatalist.ttl = rdataset.ttl; + result = dns_rdatalist_tordataset(&keyrdatalist, + &keyset); + check_result(result, + "dns_rdatalist_tordataset"); + dns_db_addrdataset(db, node, version, 0, + &keyset, DNS_DBADD_MERGE, + NULL); + set_bit(nxt_bits, dns_rdatatype_key, 1); + signset(db, version, node, name, &keyset); + + dns_rdataset_disassociate(&keyset); + + alreadyhavenullkey: + } +#endif } signset(db, version, node, name, &rdataset); @@ -1097,7 +1344,7 @@ main(int argc, char *argv[]) { break; case 'a': - tryverify = 1; + tryverify = ISC_TRUE; break; case 'h': diff --git a/bin/tests/signer.c b/bin/tests/signer.c index 2c96b60c7a..e2642ca6d7 100644 --- a/bin/tests/signer.c +++ b/bin/tests/signer.c @@ -54,9 +54,9 @@ #include +/*#define USE_ZONESTATUS*/ + #define BUFSIZE 2048 -#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \ - == DNS_KEYOWNER_ZONE) typedef struct signer_key_struct signer_key_t; typedef struct signer_array_struct signer_array_t; @@ -76,7 +76,7 @@ static ISC_LIST(signer_key_t) keylist; static isc_stdtime_t starttime = 0, endtime = 0, now; static int cycle = -1; static int verbose; -static int tryverify = 0; +static isc_boolean_t tryverify = ISC_FALSE; static isc_mem_t *mctx = NULL; @@ -172,13 +172,13 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata, mctx, b, rdata); check_result(result, "dns_dnssec_sign()"); - if (tryverify != 0) { + if (tryverify) { result = dns_dnssec_verify(name, rdataset, key, ISC_TRUE, mctx, rdata); - if (result == ISC_R_SUCCESS) - vbprintf(3, "\tsignature verified\n"); - else - vbprintf(3, "\tsignature failed to verify\n"); + if (result == ISC_R_SUCCESS) + vbprintf(3, "\tsignature verified\n"); + else + vbprintf(3, "\tsignature failed to verify\n"); } } @@ -525,6 +525,8 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, result = ISC_R_SUCCESS; check_result(result, "dns_db_deleterdataset"); #endif + fatal("File is currently signed but no private keys were " + "found. This won't work."); } trdata = ISC_LIST_HEAD(siglist.rdata); @@ -542,37 +544,195 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, } } +#ifndef USE_ZONESTATUS /* Determine if a KEY set contains a null key */ static isc_boolean_t -hasnullkey(dns_rdataset_t rdataset) { +hasnullkey(dns_rdataset_t *rdataset) { isc_result_t result; dns_rdata_t rdata; - isc_uint32_t flags; + isc_boolean_t found = ISC_FALSE; - result = dns_rdataset_first(&rdataset); + result = dns_rdataset_first(rdataset); while (result == ISC_R_SUCCESS) { dst_key_t *key = NULL; - dns_rdataset_current(&rdataset, &rdata); + dns_rdataset_current(rdataset, &rdata); result = dns_dnssec_keyfromrdata(dns_rootname, &rdata, mctx, &key); check_result(result, "dns_dnssec_keyfromrdata()"); - flags = dst_key_flags(key); - dst_key_free(key); - if (((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) && - ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE)) + if (dst_key_isnullkey(key)) + found = ISC_TRUE; + dst_key_free(key); + if (found == ISC_TRUE) return (ISC_TRUE); - result = dns_rdataset_next(&rdataset); + result = dns_rdataset_next(rdataset); + } + if (result != ISC_R_NOMORE) + check_result(result, "iteration over keys"); + return (ISC_FALSE); +} +#endif + +/* + * Looks for signatures of the zone keys by the parent, and imports them + * if found. + */ +static void +importparentsig(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, + dns_name_t *name, dns_rdataset_t *set) +{ + unsigned char filename[256]; + isc_buffer_t b; + isc_region_t r; + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t newset, sigset; + dns_rdata_t rdata, newrdata; + isc_result_t result; + + isc_buffer_init(&b, filename, sizeof(filename) - 10); + result = dns_name_totext(name, ISC_FALSE, &b); + check_result(result, "dns_name_totext()"); + isc_buffer_usedregion(&b, &r); + strcpy((char *)r.base + r.length, "signedkey"); + result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db), + 0, NULL, &newdb); + check_result(result, "dns_db_create()"); + result = dns_db_load(newdb, filename); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(&newset); + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, 0, + 0, &newset, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (dns_rdataset_count(set) != dns_rdataset_count(&newset)) + goto failure; + + dns_rdata_init(&rdata); + dns_rdata_init(&newrdata); + + result = dns_rdataset_first(set); + check_result(result, "dns_rdata_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_rdata_first()"); + for (; + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&newset)) + { + dns_rdataset_current(&newset, &newrdata); + if (dns_rdata_compare(&rdata, &newrdata) == 0) + break; + } + if (result != ISC_R_SUCCESS) + break; } - if (result != ISC_R_NOMORE) - check_result(result, "iteration over keys"); - return (ISC_FALSE); + if (result != ISC_R_NOMORE) + goto failure; + + vbprintf(2, "found the parent's signature of our zone key\n"); + + result = dns_db_addrdataset(db, node, version, 0, &sigset, 0, NULL); + check_result(result, "dns_db_addrdataset"); + dns_rdataset_disassociate(&newset); + dns_rdataset_disassociate(&sigset); + + failure: + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); +} + +/* + * Looks for our signatures of child keys. If present, inform the caller, + * who will set the zone status (KEY) bit in the NXT record. + */ +static isc_boolean_t +haschildkey(dns_db_t *db, dns_name_t *name) { + unsigned char filename[256]; + isc_buffer_t b; + isc_region_t r; + dns_db_t *newdb = NULL; + dns_dbnode_t *newnode = NULL; + dns_rdataset_t set, sigset; + dns_rdata_t sigrdata; + isc_result_t result; + isc_boolean_t found = ISC_FALSE; + dns_rdata_sig_t sig; + signer_key_t *key; + + isc_buffer_init(&b, filename, sizeof(filename) - 10); + result = dns_name_totext(name, ISC_FALSE, &b); + check_result(result, "dns_name_totext()"); + isc_buffer_usedregion(&b, &r); + strcpy((char *)r.base + r.length, "signedkey"); + result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db), + 0, NULL, &newdb); + check_result(result, "dns_db_create()"); + result = dns_db_load(newdb, filename); + if (result != ISC_R_SUCCESS) + goto failure; + result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode); + if (result != ISC_R_SUCCESS) + goto failure; + dns_rdataset_init(&set); + dns_rdataset_init(&sigset); + result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key, 0, + 0, &set, &sigset); + if (result != ISC_R_SUCCESS) + goto failure; + + if (!dns_rdataset_isassociated(&set) || + !dns_rdataset_isassociated(&sigset)) + goto disfail; + + 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, mctx); + if (result != ISC_R_SUCCESS) + goto disfail; + key = keythatsigned(&sig); + dns_rdata_freestruct(&sig); + if (key == NULL) + goto disfail; + result = dns_dnssec_verify(name, &set, key->key, + ISC_FALSE, mctx, &sigrdata); + if (result == ISC_R_SUCCESS) { + found = ISC_TRUE; + break; + } + } + + disfail: + if (dns_rdataset_isassociated(&set)) + dns_rdataset_disassociate(&set); + if (dns_rdataset_isassociated(&sigset)) + dns_rdataset_disassociate(&sigset); + + failure: + if (newnode != NULL) + dns_db_detachnode(newdb, &newnode); + if (newdb != NULL) + dns_db_detach(&newdb); + + return (found); } /* * Signs all records at a name. This mostly just signs each set individually, - * but also handles exceptional cases and adds the SIG bit to any NXTs - * generated earlier. + * but also adds the SIG bit to any NXTs generated earlier, deals with + * parent/child KEY signatures, and handles other exceptional cases. */ static void signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, @@ -580,9 +740,10 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, { isc_result_t result; dns_rdata_t rdata; - dns_rdataset_t rdataset, nsset; + dns_rdataset_t rdataset; dns_rdatasetiter_t *rdsiter; isc_boolean_t isdelegation = ISC_FALSE; + isc_boolean_t childkey = ISC_FALSE; static int warnwild = 0; if (dns_name_iswildcard(name)) { @@ -593,6 +754,8 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, "wildcards in secure zones\n"); } if (!atorigin) { + dns_rdataset_t nsset; + dns_rdataset_init(&nsset); result = dns_db_findrdataset(db, node, version, dns_rdatatype_ns, 0, 0, &nsset, @@ -615,37 +778,50 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, if (rdataset.type == dns_rdatatype_sig) goto skip; - /* If this is a KEY set at the apex, skip it. */ - if (rdataset.type == dns_rdatatype_key && atorigin) + /* + * If this is a KEY set at the apex, look for a signedkey file. + */ + if (rdataset.type == dns_rdatatype_key && atorigin) { + importparentsig(db, version, node, name, &rdataset); goto skip; + } /* * If this name is a delegation point, skip all records - * except a KEY set containing a NULL key or an NXT set. + * except an NXT set, unless we're using null keys, in + * which case we need to check for a null key and add one + * if it's not present. */ if (isdelegation) { switch (rdataset.type) { - case dns_rdatatype_nxt: + case dns_rdatatype_nxt: + childkey = haschildkey(db, name); + break; +#ifndef USE_ZONESTATUS + case dns_rdatatype_key: + if (hasnullkey(&rdataset)) break; - case dns_rdatatype_key: - if (hasnullkey(rdataset)) - break; - goto skip; - default: - goto skip; + goto skip; +#endif + default: + goto skip; } + } /* * There probably should be a dns_nxtsetbit, but it can get * complicated if we need to extend the length of the * bit set. In this case, since the NXT bit is set and - * SIG < NXT, the easy way works. + * SIG < NXT and KEY < NXT, the easy way works. */ if (rdataset.type == dns_rdatatype_nxt) { unsigned char *nxt_bits; dns_name_t nxtname; isc_region_t r, r2; + unsigned char keydata[4]; + dst_key_t *dstkey; + isc_buffer_t b; result = dns_rdataset_first(&rdataset); check_result(result, "dns_rdataset_first()"); @@ -656,6 +832,77 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, dns_name_toregion(&nxtname, &r2); nxt_bits = r.base + r2.length; set_bit(nxt_bits, dns_rdatatype_sig, 1); +#ifdef USE_ZONESTATUS + if (isdelegation && childkey) { + set_bit(nxt_bits, dns_rdatatype_key, 1); + vbprintf(2, "found a child key for %s, " + "setting KEY bit in NXT\n", + nametostr(name)); + } + +#else + if (isdelegation && !childkey) { + dns_rdataset_t keyset; + dns_rdatalist_t keyrdatalist; + dns_rdata_t keyrdata; + + dns_rdataset_init(&keyset); + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_key, + 0, 0, &keyset, + NULL); + if (result == ISC_R_SUCCESS && + hasnullkey(&keyset)) + goto alreadyhavenullkey; + + if (result == ISC_R_NOTFOUND) + result = ISC_R_SUCCESS; + check_result(result, "dns_db_findrdataset"); + + if (dns_rdataset_isassociated(&keyset)) + dns_rdataset_disassociate(&keyset); + + vbprintf(2, "no child key for %s, " + "adding null key\n", + nametostr(name)); + dns_rdatalist_init(&keyrdatalist); + dstkey = NULL; + + result = dst_key_generate("", DNS_KEYALG_DSA, + 0, 0, + DNS_KEYTYPE_NOKEY, + DNS_KEYPROTO_DNSSEC, + mctx, &dstkey); + check_result(result, "dst_key_generate"); + isc_buffer_init(&b, keydata, sizeof keydata); + result = dst_key_todns(dstkey, &b); + dst_key_free(dstkey); + isc_buffer_usedregion(&b, &r); + dns_rdata_fromregion(&keyrdata, + rdataset.rdclass, + dns_rdatatype_key, &r); + + ISC_LIST_APPEND(keyrdatalist.rdata, &keyrdata, + link); + keyrdatalist.rdclass = rdataset.rdclass; + keyrdatalist.type = dns_rdatatype_key; + keyrdatalist.covers = 0; + keyrdatalist.ttl = rdataset.ttl; + result = dns_rdatalist_tordataset(&keyrdatalist, + &keyset); + check_result(result, + "dns_rdatalist_tordataset"); + dns_db_addrdataset(db, node, version, 0, + &keyset, DNS_DBADD_MERGE, + NULL); + set_bit(nxt_bits, dns_rdatatype_key, 1); + signset(db, version, node, name, &keyset); + + dns_rdataset_disassociate(&keyset); + + alreadyhavenullkey: + } +#endif } signset(db, version, node, name, &rdataset); @@ -1097,7 +1344,7 @@ main(int argc, char *argv[]) { break; case 'a': - tryverify = 1; + tryverify = ISC_TRUE; break; case 'h':