+2735. [bug] dnssec-signzone could fail to read keys
+ that were specified on the command line with
+ full paths, but weren't in the current
+ directory. [RT #20421]
+
2734. [port] cygwin: arpaname did not compile. [RT #20473]
2733. [cleanup] Clean up coding style in pkcs11-* tools. [RT #20355]
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-signzone.c,v 1.248 2009/10/24 00:00:06 each Exp $ */
+/* $Id: dnssec-signzone.c,v 1.249 2009/10/27 03:59:45 each Exp $ */
/*! \file */
static void
loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
dns_dbnode_t *node;
- dns_dbversion_t *currentversion;
+ dns_dbversion_t *currentversion = NULL;
isc_result_t result;
- dns_rdataset_t rdataset;
-
- currentversion = NULL;
- dns_db_currentversion(gdb, ¤tversion);
+ dns_rdataset_t rdataset, keysigs, soasigs;
node = NULL;
result = dns_db_findnode(gdb, gorigin, ISC_FALSE, &node);
fatal("failed to find the zone's origin: %s",
isc_result_totext(result));
- /* Preserve the TTL of the DNSKEY RRset, if any */
+ dns_db_currentversion(gdb, ¤tversion);
+
dns_rdataset_init(&rdataset);
+ dns_rdataset_init(&soasigs);
+ dns_rdataset_init(&keysigs);
+
+ /* Make note of the keys which signed the SOA, if any */
+ result = dns_db_findrdataset(gdb, node, currentversion,
+ dns_rdatatype_soa, 0, 0,
+ &rdataset, &soasigs);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ /* Preserve the TTL of the DNSKEY RRset, if any */
+ dns_rdataset_disassociate(&rdataset);
result = dns_db_findrdataset(gdb, node, currentversion,
dns_rdatatype_dnskey, 0, 0,
- &rdataset, NULL);
+ &rdataset, &keysigs);
if (result != ISC_R_SUCCESS)
goto cleanup;
/* Load keys corresponding to the existing DNSKEY RRset */
result = dns_dnssec_keylistfromrdataset(gorigin, directory, mctx,
- &rdataset, NULL, preserve_keys,
- load_public, &keylist);
+ &rdataset, &keysigs, &soasigs,
+ preserve_keys, load_public,
+ &keylist);
if (result != ISC_R_SUCCESS)
fatal("failed to load the zone keys: %s",
isc_result_totext(result));
cleanup:
if (dns_rdataset_isassociated(&rdataset))
dns_rdataset_disassociate(&rdataset);
+ if (dns_rdataset_isassociated(&keysigs))
+ dns_rdataset_disassociate(&keysigs);
+ if (dns_rdataset_isassociated(&soasigs))
+ dns_rdataset_disassociate(&soasigs);
dns_db_detachnode(gdb, &node);
dns_db_closeversion(gdb, ¤tversion, ISC_FALSE);
}
+static void
+loadexplicitkeys(char *keyfiles[], int n, isc_boolean_t setksk) {
+ isc_result_t result;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ dns_dnsseckey_t *key = NULL;
+ dst_key_t *newkey = NULL;
+
+ result = dst_key_fromnamedfile(keyfiles[i], directory,
+ DST_TYPE_PUBLIC |
+ DST_TYPE_PRIVATE,
+ mctx, &newkey);
+ if (result != ISC_R_SUCCESS)
+ fatal("cannot load dnskey %s: %s", keyfiles[i],
+ isc_result_totext(result));
+
+ if (!dns_name_equal(gorigin, dst_key_name(newkey)))
+ fatal("key %s not at origin\n", keyfiles[i]);
+
+ if (!dst_key_isprivate(newkey))
+ fatal("cannot sign zone with non-private dnskey %s",
+ keyfiles[i]);
+
+ /* Skip any duplicates */
+ for (key = ISC_LIST_HEAD(keylist);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ if (dst_key_id(key->key) == dst_key_id(newkey) &&
+ dst_key_alg(key->key) == dst_key_alg(newkey))
+ break;
+ }
+
+ if (key == NULL) {
+ /* We haven't seen this key before */
+ dns_dnsseckey_create(mctx, &newkey, &key);
+ ISC_LIST_APPEND(keylist, key, link);
+ key->source = dns_keysource_user;
+ } else {
+ dst_key_free(&key->key);
+ key->key = newkey;
+ }
+
+ key->force_publish = ISC_TRUE;
+ key->force_sign = ISC_TRUE;
+
+ if (setksk)
+ key->ksk = ISC_TRUE;
+ }
+}
+
static void
report(const char *format, ...) {
va_list args;
}
static void
-build_final_keylist(dns_db_t *db, const char *directory, isc_mem_t *mctx) {
+build_final_keylist() {
isc_result_t result;
dns_dbversion_t *ver = NULL;
dns_diff_t del, add;
result = ISC_R_SUCCESS;
check_result(result, "dns_dnssec_findmatchingkeys");
- result = dns_db_newversion(db, &ver);
+ result = dns_db_newversion(gdb, &ver);
check_result(result, "dns_db_newversion");
dns_diff_init(mctx, &del);
dns_name_format(gorigin, name, sizeof(name));
- result = dns_diff_applysilently(&del, db, ver);
+ result = dns_diff_applysilently(&del, gdb, ver);
if (result != ISC_R_SUCCESS)
fatal("failed to delete DNSKEYs at node '%s': %s",
name, isc_result_totext(result));
- result = dns_diff_applysilently(&add, db, ver);
+ result = dns_diff_applysilently(&add, gdb, ver);
if (result != ISC_R_SUCCESS)
fatal("failed to add DNSKEYs at node '%s': %s",
name, isc_result_totext(result));
- dns_db_closeversion(db, &ver, ISC_TRUE);
+ dns_db_closeversion(gdb, &ver, ISC_TRUE);
dns_diff_clear(&del);
dns_diff_clear(&add);
ISC_LIST_INIT(keylist);
isc_rwlock_init(&keylist_lock, 0, 0);
+ /*
+ * Fill keylist with:
+ * 1) Keys listed in the DNSKEY set that have
+ * private keys associated
+ * 2) KSKs set on the command line
+ * 3) ZSKs set on the command line
+ * 4) Any keys remaining in the DNSKEY set which
+ * do not have private keys associated and were
+ * not specified on the command line.
+ */
loadzonekeys(!smartsign, ISC_FALSE);
-
- for (i = 0; i < ndskeys; i++) {
- dst_key_t *newkey = NULL;
-
- result = dst_key_fromnamedfile(dskeyfile[i], directory,
- DST_TYPE_PUBLIC |
- DST_TYPE_PRIVATE,
- mctx, &newkey);
- if (result != ISC_R_SUCCESS)
- fatal("cannot load dnskey %s: %s", dskeyfile[i],
- isc_result_totext(result));
-
- if (!dns_name_equal(gorigin, dst_key_name(newkey)))
- fatal("key %s not at origin\n", dskeyfile[i]);
-
- /* Skip any duplicates */
- for (key = ISC_LIST_HEAD(keylist);
- key != NULL;
- key = ISC_LIST_NEXT(key, link)) {
- if (dst_key_id(key->key) == dst_key_id(newkey) &&
- dst_key_alg(key->key) == dst_key_alg(newkey) &&
- dns_name_equal(dst_key_name(key->key), gorigin))
- break;
- }
-
- if (key == NULL) {
- /* We haven't seen this key before */
- dns_dnsseckey_create(mctx, &newkey, &key);
- ISC_LIST_APPEND(keylist, key, link);
- key->source = dns_keysource_user;
- } else {
- dst_key_free(&key->key);
- key->key = newkey;
- }
- key->force_publish = ISC_TRUE;
- key->force_sign = ISC_TRUE;
- key->ksk = ISC_TRUE;
- }
-
- for (i = 0; i < argc; i++) {
- dst_key_t *newkey = NULL;
-
- result = dst_key_fromnamedfile(argv[i], directory,
- DST_TYPE_PUBLIC |
- DST_TYPE_PRIVATE,
- mctx, &newkey);
- if (result != ISC_R_SUCCESS)
- fatal("cannot load dnskey %s: %s", argv[i],
- isc_result_totext(result));
-
- if (!dns_name_equal(gorigin, dst_key_name(newkey)))
- fatal("key %s not at origin\n", argv[i]);
-
- /* Skip any duplicates */
- for (key = ISC_LIST_HEAD(keylist);
- key != NULL;
- key = ISC_LIST_NEXT(key, link)) {
- 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), gorigin)) {
- if (!dst_key_isprivate(dkey))
- fatal("cannot sign zone with "
- "non-private dnskey %s",
- argv[i]);
- break;
- }
- }
-
- if (key == NULL) {
- /* We haven't seen this key before */
- dns_dnsseckey_create(mctx, &newkey, &key);
- key->force_publish = ISC_TRUE;
- key->force_sign = ISC_TRUE;
- key->source = dns_keysource_user;
- ISC_LIST_APPEND(keylist, key, link);
- } else {
- dst_key_free(&newkey);
- }
- }
-
- if (argc != 0)
- loadzonekeys(!smartsign, ISC_TRUE);
+ loadexplicitkeys(dskeyfile, ndskeys, ISC_TRUE);
+ loadexplicitkeys(argv, argc, ISC_FALSE);
+ loadzonekeys(!smartsign, ISC_TRUE);
/*
* If we're doing smart signing, look in the key repository for
* we have now.
*/
if (smartsign)
- build_final_keylist(gdb, directory, mctx);
+ build_final_keylist();
/* Now enumerate the key list */
for (key = ISC_LIST_HEAD(keylist);
*/
/*
- * $Id: dnssec.c,v 1.107 2009/10/26 21:18:24 each Exp $
+ * $Id: dnssec.c,v 1.108 2009/10/27 03:59:45 each Exp $
*/
/*! \file */
/*
* Found a match. If the old key was only public and the
* new key is private, replace the old one; otherwise
- * we're done.
+ * leave it. But either way, mark the key as having
+ * been found in the zone.
*/
if (dst_key_isprivate(key->key)) {
dst_key_free(newkey);
key->key = *newkey;
}
+ key->source = dns_keysource_zoneapex;
return;
}
*newkey = NULL;
}
+
+/*%
+ * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
+ * for future reference.
+ */
+static isc_result_t
+mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t sigs;
+ dns_dnsseckey_t *key;
+
+ REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
+
+ dns_rdataset_init(&sigs);
+ dns_rdataset_clone(rrsigs, &sigs);
+ for (key = ISC_LIST_HEAD(*keylist);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ isc_uint16_t keyid, sigid;
+ dns_secalg_t keyalg, sigalg;
+ keyid = dst_key_id(key->key);
+ keyalg = dst_key_alg(key->key);
+
+ for (result = dns_rdataset_first(&sigs);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&sigs)) {
+ dns_rdata_rrsig_t sig;
+
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(&sigs, &rdata);
+ result = dns_rdata_tostruct(&rdata, &sig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ sigalg = sig.algorithm;
+ sigid = sig.keyid;
+ if (keyid == sigid && keyalg == sigalg) {
+ key->is_active = ISC_TRUE;
+ break;
+ }
+ }
+ }
+
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ if (dns_rdataset_isassociated(&sigs))
+ dns_rdataset_disassociate(&sigs);
+ return (result);
+}
+
/*%
* Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
*/
isc_result_t
dns_dnssec_keylistfromrdataset(dns_name_t *origin,
const char *directory, isc_mem_t *mctx,
- dns_rdataset_t *keyset, dns_rdataset_t *sigset,
- isc_boolean_t savekeys, isc_boolean_t public,
+ dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
+ dns_rdataset_t *soasigs, isc_boolean_t savekeys,
+ isc_boolean_t public,
dns_dnsseckeylist_t *keylist)
{
- dns_rdataset_t keys, sigs;
+ dns_rdataset_t keys;
dns_rdata_t rdata = DNS_RDATA_INIT;
- dst_key_t *pubkey, *privkey;
- dns_dnsseckey_t *key;
+ dst_key_t *pubkey = NULL, *privkey = NULL;
isc_result_t result;
+ REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
+
dns_rdataset_init(&keys);
- dns_rdataset_init(&sigs);
- REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
dns_rdataset_clone(keyset, &keys);
-
for (result = dns_rdataset_first(&keys);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&keys)) {
- pubkey = NULL;
- privkey = NULL;
-
dns_rdata_reset(&rdata);
dns_rdataset_current(&keys, &rdata);
RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
if (!is_zone_key(pubkey) ||
(dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
- goto again;
+ goto skip;
/* Corrupted .key file? */
if (!dns_name_equal(origin, dst_key_name(pubkey)))
- goto again;
+ goto skip;
if (public) {
addkey(keylist, &pubkey, savekeys, mctx);
- goto again;
+ goto skip;
}
result = dst_key_fromfile(dst_key_name(pubkey),
directory, mctx, &privkey);
if (result == ISC_R_FILENOTFOUND) {
addkey(keylist, &pubkey, savekeys, mctx);
- goto again;
+ goto skip;
}
RETERR(result);
/* This should never happen. */
if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
- goto again;
+ goto skip;
addkey(keylist, &privkey, savekeys, mctx);
- again:
+ skip:
if (pubkey != NULL)
dst_key_free(&pubkey);
if (privkey != NULL)
dst_key_free(&privkey);
}
- if (result == ISC_R_NOMORE)
- result = ISC_R_SUCCESS;
- else if (result != ISC_R_SUCCESS)
- goto failure;
-
- if (sigset == NULL || !dns_rdataset_isassociated(sigset))
- goto success;
- dns_rdataset_clone(sigset, &sigs);
+ if (result != ISC_R_NOMORE)
+ RETERR(result);
- /*
- * Mark all keys which signed the DNSKEY set, for future reference.
- */
- for (key = ISC_LIST_HEAD(*keylist);
- key != NULL;
- key = ISC_LIST_NEXT(key, link)) {
- isc_uint16_t keyid, sigid;
- isc_uint8_t keyalg, sigalg;
- keyid = dst_key_id(key->key);
- keyalg = dst_key_alg(key->key);
+ if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
+ RETERR(mark_active_keys(keylist, keysigs));
- for (result = dns_rdataset_first(&sigs);
- result == ISC_R_SUCCESS;
- result = dns_rdataset_next(&sigs)) {
- dns_rdata_reset(&rdata);
- dns_rdataset_current(&sigs, &rdata);
- sigalg = rdata.data[2];
- sigid = (rdata.data[16] << 8) | rdata.data[17];
- if (keyid == sigid && keyalg == sigalg) {
- key->is_active = ISC_TRUE;
- break;
- }
- }
- }
+ if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
+ RETERR(mark_active_keys(keylist, soasigs));
- if (result == ISC_R_NOMORE)
- success:
- result = ISC_R_SUCCESS;
+ result = ISC_R_SUCCESS;
failure:
if (dns_rdataset_isassociated(&keys))
dns_rdataset_disassociate(&keys);
- if (dns_rdataset_isassociated(&sigs))
- dns_rdataset_disassociate(&sigs);
if (pubkey != NULL)
dst_key_free(&pubkey);
if (privkey != NULL)
return (result);
}
-
static isc_result_t
make_dnskey(dst_key_t *key, dns_rdata_t *target) {
isc_result_t result;
void (*report)(const char *, ...))
{
isc_result_t result;
- dns_dnsseckey_t *key1, *key2;
+ dns_dnsseckey_t *key, *key1, *key2, *next;
+
+ /*
+ * First, look through the existing key list to find keys
+ * supplied from the command line which are not in the zone.
+ * Update the zone to include them.
+ */
+ for (key = ISC_LIST_HEAD(*keys);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ if (key->source == dns_keysource_user &&
+ (key->hint_publish || key->force_publish)) {
+ RETERR(publish_key(add, key, origin, ttl,
+ mctx, allzsk, report));
+ }
+ }
- key1 = ISC_LIST_HEAD(*newkeys);
- while (key1 != NULL) {
+ /*
+ * Second, scan the list of newly found keys looking for matches
+ * with known keys, and update accordingly.
+ */
+ for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
isc_boolean_t key_revoked = ISC_FALSE;
+
+ next = ISC_LIST_NEXT(key1, link);
+
for (key2 = ISC_LIST_HEAD(*keys);
key2 != NULL;
key2 = ISC_LIST_NEXT(key2, link)) {
key1->first_sign = ISC_TRUE;
}
- key1 = next;
continue;
}
dns_dnsseckey_destroy(mctx, &key2);
} else if (key_revoked &&
(dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
- dns_dnsseckey_t *next;
/*
* A previously valid key has been revoked.
RETERR(publish_key(add, key1, origin, ttl,
mctx, allzsk, report));
- next = ISC_LIST_NEXT(key1, link);
ISC_LIST_UNLINK(*newkeys, key1, link);
ISC_LIST_APPEND(*keys, key1, link);
* sign other records with it.
*/
key1->ksk = ISC_TRUE;
- key1 = next;
continue;
} else {
if (!key2->is_active &&
(key1->hint_sign || key1->force_sign))
key2->first_sign = ISC_TRUE;
key2->hint_sign = key1->hint_sign;
-
- /*
- * If a key was specified on the command line,
- * not in the zone, it can be imported into the
- * zone now.
- */
key2->hint_publish = key1->hint_publish;
- if (key2->source == dns_keysource_user &&
- (key2->hint_publish || key2->force_publish))
- RETERR(publish_key(add, key2, origin, ttl,
- mctx, allzsk, report));
}
-
- key1 = ISC_LIST_NEXT(key1, link);
}
/* Free any leftover keys in newkeys */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec.h,v 1.38 2009/10/12 23:48:02 tbox Exp $ */
+/* $Id: dnssec.h,v 1.39 2009/10/27 03:59:45 each Exp $ */
#ifndef DNS_DNSSEC_H
#define DNS_DNSSEC_H 1
isc_result_t
dns_dnssec_keylistfromrdataset(dns_name_t *origin,
const char *directory, isc_mem_t *mctx,
- dns_rdataset_t *keyset, dns_rdataset_t *sigset,
- isc_boolean_t savekeys, isc_boolean_t public,
+ dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
+ dns_rdataset_t *soasigs, isc_boolean_t savekeys,
+ isc_boolean_t public,
dns_dnsseckeylist_t *keylist);
/*%<
* Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
* matching key files, and load the private keys that go with
* the public ones. If 'savekeys' is ISC_TRUE, mark the keys so
* they will not be deleted or inactivated regardless of metadata.
+ *
+ * 'keysigs' and 'soasigs', if not NULL and associated, contain the
+ * RRSIGS for the DNSKEY and SOA records respectively and are used to mark
+ * whether a key is already active int eh zone.
*/
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.520 2009/10/20 23:47:32 tbox Exp $ */
+/* $Id: zone.c,v 1.521 2009/10/27 03:59:45 each Exp $ */
/*! \file */
dns_db_t *db = NULL;
dns_dbnode_t *node = NULL;
dns_dbversion_t *ver = NULL;
- dns_rdataset_t soaset, keyset, sigset;
+ dns_rdataset_t soaset, soasigs, keyset, keysigs;
dns_dnsseckeylist_t dnskeys, keys, oldkeys;
dns_dnsseckey_t *key;
dns_diff_t add, del;
ISC_LIST_INIT(keys);
ISC_LIST_INIT(oldkeys);
dns_rdataset_init(&soaset);
+ dns_rdataset_init(&soasigs);
dns_rdataset_init(&keyset);
- dns_rdataset_init(&sigset);
+ dns_rdataset_init(&keysigs);
dir = dns_zone_getkeydirectory(zone);
mctx = zone->mctx;
dns_diff_init(mctx, &add);
/* Get the SOA record's TTL */
CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa,
- dns_rdatatype_none, 0, &soaset, NULL));
+ dns_rdatatype_none, 0, &soaset, &soasigs));
ttl = soaset.ttl;
dns_rdataset_disassociate(&soaset);
/* Get the DNSKEY rdataset */
result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey,
- dns_rdatatype_none, 0, &keyset, &sigset);
+ dns_rdatatype_none, 0, &keyset, &keysigs);
if (result == ISC_R_SUCCESS) {
ttl = keyset.ttl;
CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir,
- mctx, &keyset, &sigset,
+ mctx, &keyset,
+ &keysigs, &soasigs,
ISC_FALSE, ISC_FALSE,
&dnskeys));
} else if (result != ISC_R_NOTFOUND)
dns_db_closeversion(db, &ver, ISC_FALSE);
if (dns_rdataset_isassociated(&keyset))
dns_rdataset_disassociate(&keyset);
- if (dns_rdataset_isassociated(&sigset))
- dns_rdataset_disassociate(&sigset);
+ if (dns_rdataset_isassociated(&keysigs))
+ dns_rdataset_disassociate(&keysigs);
+ if (dns_rdataset_isassociated(&soasigs))
+ dns_rdataset_disassociate(&soasigs);
if (node != NULL)
dns_db_detachnode(db, &node);
if (db != NULL)