+2712. [func] New 'auto-dnssec' zone option allows zone signing
+ to be fully automated in zones configured for
+ dynamic DNS. 'auto-dnssec allow;' permits a zone
+ to be signed by creating keys for it in the
+ key-directory and using 'rndc sign <zone>'.
+ 'auto-dnssec maintain;' allows that too, plus it
+ also keeps the zone's DNSSEC keys up to date
+ according to their timing metadata. [RT #19943]
+
2711. [port] win32: Add the bin/pkcs11 tools into the full
build. [RT #20372]
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-dsfromkey.c,v 1.15 2009/10/05 17:30:49 fdupont Exp $ */
+/* $Id: dnssec-dsfromkey.c,v 1.16 2009/10/12 20:48:10 each Exp $ */
/*! \file */
filename, isc_result_totext(result));
if (verbose > 2) {
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fprintf(stderr, "%s: %s\n", program, keystr);
}
isc_result_t result;
dst_key_t *key = NULL;
isc_buffer_t buf;
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
isc_buffer_init(&buf, rdata->data, rdata->length);
isc_buffer_add(&buf, rdata->length);
if (result != ISC_R_SUCCESS)
return;
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fprintf(stderr, "%s: %s\n", program, keystr);
dst_key_free(&key);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-keyfromlabel.c,v 1.20 2009/10/06 23:22:51 each Exp $ */
+/* $Id: dnssec-keyfromlabel.c,v 1.21 2009/10/12 20:48:10 each Exp $ */
/*! \file */
if (ret != ISC_R_SUCCESS) {
char namestr[DNS_NAME_FORMATSIZE];
- char algstr[ALG_FORMATSIZE];
+ char algstr[DNS_SECALG_FORMATSIZE];
dns_name_format(name, namestr, sizeof(namestr));
- alg_format(alg, algstr, sizeof(algstr));
+ dns_secalg_format(alg, algstr, sizeof(algstr));
fatal("failed to get key %s/%s: %s\n",
namestr, algstr, isc_result_totext(ret));
/* NOTREACHED */
ret = dst_key_tofile(key, options, directory);
if (ret != ISC_R_SUCCESS) {
- char keystr[KEY_FORMATSIZE];
- key_format(key, keystr, sizeof(keystr));
+ char keystr[DST_KEY_FORMATSIZE];
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("failed to write key %s: %s\n", keystr,
isc_result_totext(ret));
}
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-keygen.c,v 1.100 2009/10/06 22:58:45 each Exp $ */
+/* $Id: dnssec-keygen.c,v 1.101 2009/10/12 20:48:10 each Exp $ */
/*! \file */
if (ret != ISC_R_SUCCESS) {
char namestr[DNS_NAME_FORMATSIZE];
- char algstr[ALG_FORMATSIZE];
+ char algstr[DNS_SECALG_FORMATSIZE];
dns_name_format(name, namestr, sizeof(namestr));
- alg_format(alg, algstr, sizeof(algstr));
+ dns_secalg_format(alg, algstr, sizeof(algstr));
fatal("failed to generate key %s/%s: %s\n",
namestr, algstr, isc_result_totext(ret));
/* NOTREACHED */
ret = dst_key_tofile(key, options, directory);
if (ret != ISC_R_SUCCESS) {
- char keystr[KEY_FORMATSIZE];
- key_format(key, keystr, sizeof(keystr));
+ char keystr[DST_KEY_FORMATSIZE];
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("failed to write key %s: %s\n", keystr,
isc_result_totext(ret));
}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-revoke.c,v 1.15 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dnssec-revoke.c,v 1.16 2009/10/12 20:48:10 each Exp $ */
/*! \file */
#endif
char *filename = NULL, *dir = NULL;
char newname[1024], oldname[1024];
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
char *endp;
int ch;
isc_entropy_t *ectx = NULL;
filename, isc_result_totext(result));
if (verbose > 2) {
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fprintf(stderr, "%s: %s\n", program, keystr);
}
result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
dir);
if (result != ISC_R_SUCCESS) {
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("Failed to write key %s: %s", keystr,
isc_result_totext(result));
}
unlink(oldname);
}
} else {
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("Key %s is already revoked", keystr);
}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-settime.c,v 1.16 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dnssec-settime.c,v 1.17 2009/10/12 20:48:10 each Exp $ */
/*! \file */
#endif
char *filename = NULL, *directory = NULL;
char newname[1024];
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
char *endp, *p;
int ch;
isc_entropy_t *ectx = NULL;
if (!dst_key_isprivate(key))
fatal("%s is not a private key", filename);
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
/* Is this an old-style key? */
dst_key_getprivateformat(key, &major, &minor);
result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
directory);
if (result != ISC_R_SUCCESS) {
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("Failed to write key %s: %s", keystr,
isc_result_totext(result));
}
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-signzone.c,v 1.243 2009/10/10 01:47:59 each Exp $ */
+/* $Id: dnssec-signzone.c,v 1.244 2009/10/12 20:48:10 each Exp $ */
/*! \file */
static isc_boolean_t update_chain = ISC_FALSE;
static isc_boolean_t set_keyttl = ISC_FALSE;
static dns_ttl_t keyttl;
-static isc_boolean_t smartsign = ISC_FALSE;
#define INCSTAT(counter) \
if (printstats) { \
{
isc_result_t result;
isc_stdtime_t jendtime;
- char keystr[KEY_FORMATSIZE];
+ char keystr[DST_KEY_FORMATSIZE];
dns_rdata_t trdata = DNS_RDATA_INIT;
unsigned char array[BUFSIZE];
isc_buffer_t b;
dns_difftuple_t *tuple;
- key_format(key, keystr, sizeof(keystr));
+ dst_key_format(key, keystr, sizeof(keystr));
vbprintf(1, "\t%s %s\n", logmsg, keystr);
jendtime = (jitter != 0) ? isc_random_jitter(endtime, jitter) : endtime;
mctx, &b, &trdata);
isc_entropy_stopcallbacksources(ectx);
if (result != ISC_R_SUCCESS) {
- char keystr[KEY_FORMATSIZE];
- key_format(key, keystr, sizeof(keystr));
+ char keystr[DST_KEY_FORMATSIZE];
+ dst_key_format(key, keystr, sizeof(keystr));
fatal("dnskey '%s' failed to sign data: %s",
keystr, isc_result_totext(result));
}
for (i = 0; i < 256; i++)
if ((ksk_algorithms[i] != 0) &&
(set_algorithms[i] == 0)) {
- alg_format(i, algbuf, sizeof(algbuf));
+ dns_secalg_format(i, algbuf, sizeof(algbuf));
fprintf(stderr, "Missing %s signature for "
"%s %s\n", algbuf, namebuf, typebuf);
bad_algorithms[i] = 1;
if (ksk_algorithms[i] != 0)
#endif
{
- alg_format(i, algbuf, sizeof(algbuf));
+ dns_secalg_format(i, algbuf, sizeof(algbuf));
fprintf(stderr, " %s", algbuf);
}
}
if ((ksk_algorithms[i] != 0) ==
(zsk_algorithms[i] != 0))
continue;
- alg_format(i, algbuf, sizeof(algbuf));
+ dns_secalg_format(i, algbuf, sizeof(algbuf));
fprintf(stderr, "Missing %s for algorithm %s\n",
(ksk_algorithms[i] != 0)
? "ZSK"
if (first)
fprintf(stderr, "The zone is not fully signed "
"for the following algorithms:");
- alg_format(i, algbuf, sizeof(algbuf));
+ dns_secalg_format(i, algbuf, sizeof(algbuf));
fprintf(stderr, " %s", algbuf);
first = ISC_FALSE;
}
(zsk_algorithms[i] != 0) ||
(standby_zsk[i] != 0) ||
(revoked_zsk[i] != 0)) {
- alg_format(i, algbuf, sizeof(algbuf));
+ dns_secalg_format(i, algbuf, sizeof(algbuf));
fprintf(stderr, "Algorithm: %s: KSKs: "
"%u active, %u stand-by, %u revoked\n",
algbuf, ksk_algorithms[i],
* private keys from disk.
*/
static void
-loadzonekeys(dns_db_t *db) {
+loadzonekeys(isc_boolean_t preserve_keys, isc_boolean_t load_public) {
dns_dbnode_t *node;
dns_dbversion_t *currentversion;
isc_result_t result;
- dst_key_t *keys[20];
- unsigned int nkeys, i;
dns_rdataset_t rdataset;
currentversion = NULL;
- dns_db_currentversion(db, ¤tversion);
+ dns_db_currentversion(gdb, ¤tversion);
node = NULL;
- result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
+ result = dns_db_findnode(gdb, gorigin, ISC_FALSE, &node);
if (result != ISC_R_SUCCESS)
fatal("failed to find the zone's origin: %s",
isc_result_totext(result));
/* Preserve the TTL of the DNSKEY RRset, if any */
dns_rdataset_init(&rdataset);
- result = dns_db_findrdataset(db, node, currentversion,
+ result = dns_db_findrdataset(gdb, node, currentversion,
dns_rdatatype_dnskey, 0, 0,
&rdataset, NULL);
- if (result == ISC_R_SUCCESS) {
- if (set_keyttl && keyttl != rdataset.ttl) {
- fprintf(stderr, "User-specified TTL (%d) conflicts "
- "with existing DNSKEY RRset TTL.\n",
- keyttl);
- fprintf(stderr, "Imported keys will use the RRSet "
- "TTL (%d) instead.\n",
- rdataset.ttl);
- }
- keyttl = rdataset.ttl;
- if (dns_rdataset_isassociated(&rdataset))
- dns_rdataset_disassociate(&rdataset);
- }
-
- /* Load keys corresponding to the existing DNSKEY RRset */
- result = dns_dnssec_findzonekeys2(db, currentversion, node, gorigin,
- directory, mctx, 20, keys, &nkeys);
- if (result == ISC_R_NOTFOUND) {
- result = ISC_R_SUCCESS;
- goto cleanup;
- }
-
if (result != ISC_R_SUCCESS)
- fatal("failed to find the zone keys: %s",
- isc_result_totext(result));
-
- for (i = 0; i < nkeys; i++) {
- dns_dnsseckey_t *key = NULL;
+ goto cleanup;
- dns_dnsseckey_create(mctx, &keys[i], &key);
- if (key->legacy || !smartsign) {
- key->force_publish = ISC_TRUE;
- key->force_sign = dst_key_isprivate(key->key);
- }
- key->source = dns_keysource_zoneapex;
- ISC_LIST_APPEND(keylist, key, link);
+ if (set_keyttl && keyttl != rdataset.ttl) {
+ fprintf(stderr, "User-specified TTL (%d) conflicts "
+ "with existing DNSKEY RRset TTL.\n",
+ keyttl);
+ fprintf(stderr, "Imported keys will use the RRSet "
+ "TTL (%d) instead.\n",
+ rdataset.ttl);
}
+ keyttl = rdataset.ttl;
- cleanup:
- dns_db_detachnode(db, &node);
- dns_db_closeversion(db, ¤tversion, ISC_FALSE);
-}
-
-/*%
- * Finds all public zone keys in the zone.
- */
-static void
-loadzonepubkeys(dns_db_t *db) {
- dns_dbversion_t *currentversion = NULL;
- dns_dbnode_t *node = NULL;
- dns_rdataset_t rdataset;
- dns_rdata_t rdata = DNS_RDATA_INIT;
- dst_key_t *pubkey;
- isc_result_t result;
-
- dns_db_currentversion(db, ¤tversion);
-
- result = dns_db_findnode(db, gorigin, ISC_FALSE, &node);
+ /* Load keys corresponding to the existing DNSKEY RRset */
+ result = dns_dnssec_keylistfromrdataset(gorigin, directory, mctx,
+ &rdataset, NULL, preserve_keys,
+ load_public, &keylist);
if (result != ISC_R_SUCCESS)
- fatal("failed to find the zone's origin: %s",
+ fatal("failed to load the zone keys: %s",
isc_result_totext(result));
- dns_rdataset_init(&rdataset);
- result = dns_db_findrdataset(db, node, currentversion,
- dns_rdatatype_dnskey, 0, 0, &rdataset,
- NULL);
- if (result != ISC_R_SUCCESS) {
- vbprintf(2, "failed to find keys at the zone apex: %s",
- isc_result_totext(result));
- goto cleanup;
- }
-
- result = dns_rdataset_first(&rdataset);
- check_result(result, "dns_rdataset_first");
- while (result == ISC_R_SUCCESS) {
- dns_dnsseckey_t *key = NULL;
- pubkey = NULL;
- dns_rdata_reset(&rdata);
- dns_rdataset_current(&rdataset, &rdata);
- result = dns_dnssec_keyfromrdata(gorigin, &rdata, mctx,
- &pubkey);
- if (result != ISC_R_SUCCESS)
- goto next;
- if (!dst_key_iszonekey(pubkey)) {
- dst_key_free(&pubkey);
- goto next;
- }
-
- /* Skip 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(pubkey) &&
- dst_key_alg(dkey) == dst_key_alg(pubkey) &&
- dns_name_equal(dst_key_name(dkey), gorigin))
- break;
- }
- if (key == NULL) {
- dns_dnsseckey_create(mctx, &pubkey, &key);
- if (key->legacy)
- key->force_publish = ISC_TRUE;
- key->force_sign = ISC_FALSE;
- key->hint_sign = ISC_FALSE;
- ISC_LIST_APPEND(keylist, key, link);
- } else {
- dst_key_free(&pubkey);
- }
- next:
- result = dns_rdataset_next(&rdataset);
- }
-
cleanup:
if (dns_rdataset_isassociated(&rdataset))
dns_rdataset_disassociate(&rdataset);
- if (node != NULL)
- dns_db_detachnode(db, &node);
- if (currentversion != NULL)
- dns_db_closeversion(db, ¤tversion, ISC_FALSE);
+ dns_db_detachnode(gdb, &node);
+ dns_db_closeversion(gdb, ¤tversion, ISC_FALSE);
}
-static isc_result_t
-make_dnskey(dst_key_t *key, dns_rdata_t *target) {
- isc_result_t result;
- unsigned char data[DST_KEY_MAXSIZE];
- isc_buffer_t b;
- isc_region_t r;
-
- isc_buffer_init(&b, data, sizeof(data));
- result = dst_key_todns(key, &b);
- check_result(result, "dst_key_todns");
-
- dns_rdata_reset(target);
- isc_buffer_usedregion(&b, &r);
- dns_rdata_fromregion(target, dst_key_class(key),
- dns_rdatatype_dnskey, &r);
- return (ISC_R_SUCCESS);
+static void
+report(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
}
static void
isc_result_t result;
dns_dbversion_t *ver = NULL;
dns_diff_t del, add;
- dns_difftuple_t *tuple = NULL;
- dns_rdata_t dnskey = DNS_RDATA_INIT;
dns_dnsseckeylist_t matchkeys;
- dns_dnsseckey_t *key1, *key2;
char name[DNS_NAME_FORMATSIZE];
- char alg[80];
-
- dns_name_format(gorigin, name, sizeof(name));
+ /*
+ * Find keys that match this zone in the key repository.
+ */
ISC_LIST_INIT(matchkeys);
result = dns_dnssec_findmatchingkeys(gorigin, directory,
mctx, &matchkeys);
dns_diff_init(mctx, &add);
/*
- * For each key in matchkeys, see if it has a match in keylist.
- * - If not, and if the metadata says it should be published:
- * add it to keylist and to the DNSKEY set
- * - If so, and if the metadata says it should be removed:
- * remove it from keylist and from the DNSKEY set
- * - Otherwise, make sure keylist has up-to-date metadata
- */
-
- key1 = ISC_LIST_HEAD(matchkeys);
- while (key1 != NULL) {
- isc_boolean_t key_revoked = ISC_FALSE;
- for (key2 = ISC_LIST_HEAD(keylist);
- key2 != NULL;
- key2 = ISC_LIST_NEXT(key2, link)) {
- if (dst_key_pubcompare(key1->key, key2->key,
- ISC_TRUE)) {
- key_revoked = ISC_TF(dst_key_flags(key1->key) !=
- dst_key_flags(key2->key));
- break;
- }
- }
-
- /*
- * No matching key found in keylist, so move the key
- * we found into keylist
- */
- if (key2 == NULL) {
- dns_dnsseckey_t *next;
-
- /* move key from matchkeys to keylist */
- next = ISC_LIST_NEXT(key1, link);
- ISC_LIST_UNLINK(matchkeys, key1, link);
- ISC_LIST_APPEND(keylist, key1, link);
-
- key1 = next;
- continue;
- }
-
- /* Match found: remove it or update it as needed */
- if (key1->hint_remove) {
- ISC_LIST_UNLINK(keylist, key2, link);
- dns_dnsseckey_destroy(mctx, &key2);
-
- make_dnskey(key1->key, &dnskey);
- alg_format(dst_key_alg(key1->key), alg, sizeof(alg));
- fprintf(stderr, "Removing expired key %d/%s from "
- "DNSKEY RRset.\n",
- dst_key_id(key1->key), alg);
-
- result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
- gorigin, keyttl,
- &dnskey, &tuple);
- check_result(result, "dns_difftuple_create");
- dns_diff_append(&del, &tuple);
- } else if (key_revoked &&
- (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
- dns_dnsseckey_t *next;
-
- /*
- * A key in the DNSKEY set has been revoked in the
- * key repository. We need to remove the old
- * version and pull in the new one.
- */
- make_dnskey(key2->key, &dnskey);
- alg_format(dst_key_alg(key2->key), alg, sizeof(alg));
- fprintf(stderr, "Replacing revoked key %d/%s in "
- "DNSKEY RRset.\n",
- dst_key_id(key2->key), alg);
-
- result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
- gorigin, keyttl,
- &dnskey, &tuple);
- check_result(result, "dns_difftuple_create");
- dns_diff_append(&del, &tuple);
-
- ISC_LIST_UNLINK(keylist, key2, link);
- dns_dnsseckey_destroy(mctx, &key2);
-
- next = ISC_LIST_NEXT(key1, link);
- ISC_LIST_UNLINK(matchkeys, key1, link);
- ISC_LIST_APPEND(keylist, key1, link);
-
- /*
- * XXX: The revoke flag is only defined for trust
- * anchors. Setting the flag on a non-KSK is legal,
- * but not defined in any RFC. It seems reasonable
- * to treat it the same as a KSK: keep it in the
- * zone and sign the DNSKEY set with it, but not
- * sign other records with it.
- */
- if (iszsk(key1))
- key1->ksk = ISC_TRUE;
-
- key1 = next;
- continue;
- } else {
- key2->hint_publish = key1->hint_publish;
- key2->hint_sign = key1->hint_sign;
- }
-
- key1 = ISC_LIST_NEXT(key1, link);
- }
-
- /*
- * If a key was not in the zone already and needs to be published,
- * add it now.
+ * Update keylist with information from from the key repository.
*/
- for (key1 = ISC_LIST_HEAD(keylist);
- key1 != NULL;
- key1 = ISC_LIST_NEXT(key1, link)) {
- if (key1->source == dns_keysource_zoneapex)
- continue;
-
- if (key1->hint_publish || key1->force_publish) {
- make_dnskey(key1->key, &dnskey);
-
- alg_format(dst_key_alg(key1->key), alg, sizeof(alg));
- fprintf(stderr, "Fetching %s %d/%s from key %s\n",
- isksk(key1) ?
- (iszsk(key1) ? "KSK/ZSK" : "KSK") :
- "ZSK",
- dst_key_id(key1->key), alg,
- key1->source == dns_keysource_user ?
- "file" :
- "repository");
-
- if (key1->prepublish && keyttl > key1->prepublish) {
- char keystr[KEY_FORMATSIZE];
- key_format(key1->key, keystr, sizeof(keystr));
- fatal("Key %s is scheduled to\n"
- "become active in %d seconds. "
- "This is less than the DNSKEY TTL\n"
- "value of %d seconds. Reduce "
- "the TTL, or change the activation\n"
- "date of the key using "
- "'dnssec-settime -A'.",
- keystr, key1->prepublish, keyttl);
- }
-
- /* add key to the zone */
- result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
- gorigin, keyttl,
- &dnskey, &tuple);
- check_result(result, "dns_difftuple_create");
- dns_diff_append(&add, &tuple);
- } else {
- vbprintf(1, "%s %d/%s: not published.\n",
- isksk(key1) ?
- (iszsk(key1) ? "KSK/ZSK" : "KSK") :
- "ZSK",
- dst_key_id(key1->key), alg);
- }
- }
+ dns_dnssec_updatekeys(&keylist, &matchkeys, NULL, gorigin, keyttl,
+ &add, &del, ignore_kskflag, mctx, report);
- /* free matchkeys */
- while (!ISC_LIST_EMPTY(matchkeys)) {
- key1 = ISC_LIST_HEAD(matchkeys);
- ISC_LIST_UNLINK(matchkeys, key1, link);
- dns_dnsseckey_destroy(mctx, &key1);
- }
+ dns_name_format(gorigin, name, sizeof(name));
result = dns_diff_applysilently(&del, db, ver);
if (result != ISC_R_SUCCESS)
isc_buffer_t b;
int len;
hashlist_t hashlist;
+ isc_boolean_t smartsign = ISC_FALSE;
isc_boolean_t make_keyset = ISC_FALSE;
isc_boolean_t set_salt = ISC_FALSE;
isc_boolean_t set_optout = ISC_FALSE;
ISC_LIST_INIT(keylist);
isc_rwlock_init(&keylist_lock, 0, 0);
- if (argc == 0)
- loadzonekeys(gdb);
+ loadzonekeys(!smartsign, ISC_FALSE);
- for (i = 0; i < argc; i++) {
+ for (i = 0; i < ndskeys; i++) {
dst_key_t *newkey = NULL;
- result = dst_key_fromnamedfile(argv[i], directory,
+ 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", argv[i],
+ 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", argv[i]);
+ 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)) {
- 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]);
+ 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);
- 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);
+ 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;
}
- if (argc != 0)
- loadzonepubkeys(gdb);
-
- for (i = 0; i < ndskeys; i++) {
+ for (i = 0; i < argc; i++) {
dst_key_t *newkey = NULL;
- result = dst_key_fromnamedfile(dskeyfile[i], directory,
+ 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", dskeyfile[i],
+ 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", dskeyfile[i]);
+ 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)) {
- 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))
+ 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(&key->key);
- key->key = newkey;
+ dst_key_free(&newkey);
}
- key->force_publish = ISC_TRUE;
- key->force_sign = ISC_TRUE;
- key->source = dns_keysource_user;
- key->ksk = ISC_TRUE;
}
+ if (argc != 0)
+ loadzonekeys(!smartsign, ISC_TRUE);
+
/*
* If we're doing smart signing, look in the key repository for
* key files with metadata, and merge them with the keylist
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: dnssec-signzone.docbook,v 1.40 2009/10/10 01:47:59 each Exp $ -->
+<!-- $Id: dnssec-signzone.docbook,v 1.41 2009/10/12 20:48:10 each Exp $ -->
<refentry id="man.dnssec-signzone">
<refentryinfo>
<date>June 05, 2009</date>
<para>
The following command signs the <userinput>example.com</userinput>
zone with the DSA key generated by <command>dnssec-keygen</command>
- (Kexample.com.+003+17247). The zone's keys must be in the master
- file (<filename>db.example.com</filename>). This invocation looks
- for <filename>keyset</filename> files, in the current directory,
- so that DS records can be generated from them (<command>-g</command>).
+ (Kexample.com.+003+17247). Because the <command>-S</command> option
+ is not being used, the zone's keys must be in the master file
+ (<filename>db.example.com</filename>). This invocation looks
+ for <filename>dsset</filename> files, in the current directory,
+ so that DS records can be imported from them (<command>-g</command>).
</para>
<programlisting>% dnssec-signzone -g -o example.com db.example.com \
Kexample.com.+003+17247
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssectool.c,v 1.54 2009/10/03 18:03:54 each Exp $ */
+/* $Id: dnssectool.c,v 1.55 2009/10/12 20:48:11 each Exp $ */
/*! \file */
r.base[r.length] = 0;
}
-void
-alg_format(const dns_secalg_t alg, char *cp, unsigned int size) {
- isc_buffer_t b;
- isc_region_t r;
- isc_result_t result;
-
- isc_buffer_init(&b, cp, size - 1);
- result = dns_secalg_totext(alg, &b);
- check_result(result, "dns_secalg_totext()");
- isc_buffer_usedregion(&b, &r);
- r.base[r.length] = 0;
-}
-
void
sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
char namestr[DNS_NAME_FORMATSIZE];
char algstr[DNS_NAME_FORMATSIZE];
dns_name_format(&sig->signer, namestr, sizeof(namestr));
- alg_format(sig->algorithm, algstr, sizeof(algstr));
+ dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
}
-void
-key_format(const dst_key_t *key, char *cp, unsigned int size) {
- char namestr[DNS_NAME_FORMATSIZE];
- char algstr[DNS_NAME_FORMATSIZE];
-
- dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
- alg_format((dns_secalg_t) dst_key_alg(key), algstr, sizeof(algstr));
- snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
-}
-
void
setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) {
isc_result_t result;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssectool.h,v 1.26 2009/09/29 15:06:06 fdupont Exp $ */
+/* $Id: dnssectool.h,v 1.27 2009/10/12 20:48:11 each Exp $ */
#ifndef DNSSECTOOL_H
#define DNSSECTOOL_H 1
type_format(const dns_rdatatype_t type, char *cp, unsigned int size);
#define TYPE_FORMATSIZE 20
-void
-alg_format(const dns_secalg_t alg, char *cp, unsigned int size);
-#define ALG_FORMATSIZE 20
-
void
sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size);
-#define SIG_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535"))
-
-void
-key_format(const dst_key_t *key, char *cp, unsigned int size);
-#define KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + ALG_FORMATSIZE + sizeof("65535"))
+#define SIG_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + sizeof("65535"))
void
setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: control.c,v 1.35 2009/07/02 23:47:26 tbox Exp $ */
+/* $Id: control.c,v 1.36 2009/10/12 20:48:11 each Exp $ */
/*! \file */
result = ns_server_notifycommand(ns_g_server, command, text);
} else if (command_compare(command, NS_COMMAND_VALIDATION)) {
result = ns_server_validation(ns_g_server, command);
+ } else if (command_compare(command, NS_COMMAND_SIGN)) {
+ result = ns_server_sign(ns_g_server, command);
} else {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: control.h,v 1.25 2007/06/19 23:46:59 tbox Exp $ */
+/* $Id: control.h,v 1.26 2009/10/12 20:48:11 each Exp $ */
#ifndef NAMED_CONTROL_H
#define NAMED_CONTROL_H 1
#define NS_COMMAND_NULL "null"
#define NS_COMMAND_NOTIFY "notify"
#define NS_COMMAND_VALIDATION "validation"
+#define NS_COMMAND_SIGN "sign"
isc_result_t
ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.h,v 1.101 2009/07/14 22:54:56 each Exp $ */
+/* $Id: server.h,v 1.102 2009/10/12 20:48:11 each Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args,
isc_buffer_t *text);
+/*%
+ * Update a zone's DNSKEY set from the key repository, and re-sign the
+ * zone if there were any changes.
+ */
+isc_result_t
+ns_server_sign(ns_server_t *server, char *args);
+
/*%
* Dump the current recursive queries.
*/
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.c,v 1.550 2009/10/05 17:30:49 fdupont Exp $ */
+/* $Id: server.c,v 1.551 2009/10/12 20:48:11 each Exp $ */
/*! \file */
return (ISC_R_SUCCESS);
}
+/*
+ * Act on a "sign" command from the command channel.
+ */
+isc_result_t
+ns_server_sign(ns_server_t *server, char *args) {
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ dns_zonetype_t type;
+ isc_uint16_t keyopts;
+
+ result = zone_from_args(server, args, &zone);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ if (zone == NULL)
+ return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
+
+ type = dns_zone_gettype(zone);
+ if (type != dns_zone_master) {
+ dns_zone_detach(&zone);
+ return (DNS_R_NOTMASTER);
+ }
+
+ keyopts = dns_zone_getkeyopts(zone);
+ if ((keyopts & DNS_ZONEKEY_ALLOW) != 0)
+ result = dns_zone_rekey(zone);
+ else
+ result = ISC_R_NOPERM;
+
+ dns_zone_detach(&zone);
+ return (result);
+}
+
/*
* Act on a "freeze" or "thaw" command from the command channel.
*/
type = dns_zone_gettype(zone);
if (type != dns_zone_master) {
dns_zone_detach(&zone);
- return (ISC_R_NOTFOUND);
+ return (DNS_R_NOTMASTER);
}
frozen = dns_zone_getupdatedisabled(zone);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zoneconf.c,v 1.156 2009/10/10 01:47:59 each Exp $ */
+/* $Id: zoneconf.c,v 1.157 2009/10/12 20:48:11 each Exp $ */
/*% */
*/
static isc_result_t
configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
- const char *zname) {
+ const char *zname)
+{
const cfg_obj_t *updatepolicy = NULL;
const cfg_listelt_t *element, *element2;
dns_ssutable_t *table = NULL;
dns_zone_clearforwardacl));
}
-
/*%
* Primary master functionality.
*/
if (ztype == dns_zone_master) {
+ isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
+ isc_boolean_t create = ISC_FALSE;
+
obj = NULL;
result = ns_config_get(maps, "check-wildcard", &obj);
if (result == ISC_R_SUCCESS)
INSIST(obj != NULL);
dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
cfg_obj_asboolean(obj));
+
+ obj = NULL;
+ result = cfg_map_get(zoptions, "auto-dnssec", &obj);
+ if (result == ISC_R_SUCCESS) {
+ const char *arg = cfg_obj_asstring(obj);
+ if (strcasecmp(arg, "allow") == 0)
+ allow = ISC_TRUE;
+ else if (strcasecmp(arg, "maintain") == 0)
+ allow = maint = ISC_TRUE;
+ else if (strcasecmp(arg, "create") == 0)
+ allow = maint = create = ISC_TRUE;
+ else if (strcasecmp(arg, "off") == 0)
+ ;
+ else
+ INSIST(0);
+ dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
+ dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
+ dns_zone_setkeyopt(zone, DNS_ZONEKEY_CREATE, create);
+ }
}
/*
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.432 2009/10/10 01:47:59 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.433 2009/10/12 20:48:11 each Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
</varlistentry>
<varlistentry>
+ <term><userinput>sign <replaceable>zone</replaceable>
+ <optional><replaceable>class</replaceable>
+ <optional><replaceable>view</replaceable></optional></optional></userinput></term>
+ <listitem>
+ <para>
+ Fetch all DNSSEC keys for the given zone
+ from the key directory (see
+ <command>key-directory</command> in
+ <xref linkend="options"/>), and merge them
+ into the zone's DNSKEY RRset. If the DNSKEY RRset
+ is changed as a result of this, then the zone is
+ automatically re-signed with the new key set.
+ </para>
+ <para>
+ This command requires that the
+ <command>auto-dnssec</command> zone option to be set
+ to <literal>allow</literal>,
+ <literal>maintain</literal>, or
+ <literal>create</literal>, and also requires
+ the zone to be configured to allow dynamic DNS.
+ See <xref linkend="dynamic_update_policies"/> for
+ more details.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><userinput>freeze
<optional><replaceable>zone</replaceable>
<optional><replaceable>class</replaceable>
<optional> min-retry-time <replaceable>number</replaceable> ; </optional>
<optional> max-retry-time <replaceable>number</replaceable> ; </optional>
<optional> key-directory <replaceable>path_name</replaceable>; </optional>
+ <optional> auto-dnssec <constant>allow</constant>|<constant>maintain</constant>|<constant>create</constant>|<constant>off</constant>; </optional>
<optional> zero-no-soa-ttl <replaceable>yes_or_no</replaceable> ; </optional>
};
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>auto-dnssec</command></term>
+ <listitem>
+ <para>
+ Zones configured for dynamic DNS may also use this
+ option to allow varying levels of autonatic DNSSEC key
+ management. There are four possible settings:
+ </para>
+ <para>
+ <command>auto-dnssec allow;</command> permits
+ keys to be updated and the zone re-signed whenever the
+ user issues the command <command>rndc sign</command>.
+ </para>
+ <para>
+ <command>auto-dnssec maintain;</command> includes the
+ above, but also automatically adjusts the zone's DNSSEC
+ keys on schedule, according to the keys' timing metadata
+ (see <xref linkend="man.dnssec-keygen"/> and
+ <xref linkend="man.dnssec-settime"/>).
+ </para>
+ <para>
+ <command>auto-dnssec create;</command> includes the
+ above, but also allows <command>named</command>
+ to create new keys in the key repository when needed.
+ (NOTE: This option is not yet implemented; the syntax is
+ being reserved for future use.)
+ </para>
+ <para>
+ The default setting is <command>auto-dnssec off</command>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><command>multi-master</command></term>
<listitem>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: check.c,v 1.110 2009/10/10 01:48:00 each Exp $ */
+/* $Id: check.c,v 1.111 2009/10/12 20:48:11 each Exp $ */
/*! \file */
{ "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
{ "update-check-ksk", MASTERZONE },
{ "dnskey-ksk-only", MASTERZONE },
+ { "auto-dnssec", MASTERZONE },
{ "try-tcp-refresh", SLAVEZONE },
};
* Master zones can't have both "allow-update" and "update-policy".
*/
if (ztype == MASTERZONE) {
- isc_result_t res1, res2;
+ isc_result_t res1, res2, res3;
+ const char *arg;
+ isc_boolean_t ddns;
+
obj = NULL;
res1 = cfg_map_get(zoptions, "allow-update", &obj);
obj = NULL;
} else if (res2 == ISC_R_SUCCESS &&
check_update_policy(obj, logctx) != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
+ ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
+
+ obj = NULL;
+ arg = "off";
+ res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
+ if (res3 == ISC_R_SUCCESS)
+ arg = cfg_obj_asstring(obj);
+ if (strcasecmp(arg, "off") != 0 && !ddns) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "'auto-dnssec %s;' requires "
+ "dynamic DNS to be configured in the zone",
+ arg);
+ result = ISC_R_FAILURE;
+ }
+ if (strcasecmp(arg, "create") == 0) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "'auto-dnssec create;' is not "
+ "yet implemented");
+ result = ISC_R_FAILURE;
+ }
+
obj = NULL;
res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
if (res1 == ISC_R_SUCCESS) {
*/
/*
- * $Id: dnssec.c,v 1.102 2009/09/14 18:45:45 each Exp $
+ * $Id: dnssec.c,v 1.103 2009/10/12 20:48:11 each Exp $
*/
/*! \file */
#include <isc/util.h>
#include <dns/db.h>
+#include <dns/diff.h>
#include <dns/dnssec.h>
#include <dns/fixedname.h>
#include <dns/keyvalues.h>
dk->hint_publish = ISC_FALSE;
dk->hint_sign = ISC_FALSE;
dk->hint_remove = ISC_FALSE;
+ dk->first_sign = ISC_FALSE;
+ dk->is_active = ISC_FALSE;
dk->prepublish = 0;
dk->source = dns_keysource_unknown;
dk->index = 0;
dst_key_free(&dstkey);
return (result);
}
+
+/*%
+ * Add 'newkey' to 'keylist' if it's not already there.
+ *
+ * If 'savekeys' is ISC_TRUE, then we need to preserve all
+ * the keys in the keyset, regardless of whether they have
+ * metadata indicating they should be deactivated or removed.
+ */
+static void
+addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
+ isc_boolean_t savekeys, isc_mem_t *mctx)
+{
+ dns_dnsseckey_t *key;
+
+ /* Skip 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),
+ dst_key_name(*newkey)))
+ break;
+ }
+
+ if (key != NULL) {
+ /*
+ * Found a match. If the old key was only public and the
+ * new key is private, replace the old one; otherwise
+ * we're done.
+ */
+ if (dst_key_isprivate(key->key)) {
+ dst_key_free(newkey);
+ } else if (dst_key_isprivate(*newkey)) {
+ dst_key_free(&key->key);
+ key->key = *newkey;
+ }
+
+ return;
+ }
+
+ dns_dnsseckey_create(mctx, newkey, &key);
+ if (key->legacy || savekeys) {
+ key->force_publish = ISC_TRUE;
+ key->force_sign = dst_key_isprivate(key->key);
+ }
+ key->source = dns_keysource_zoneapex;
+ ISC_LIST_APPEND(*keylist, key, link);
+ *newkey = NULL;
+}
+
+/*%
+ * 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_dnsseckeylist_t *keylist)
+{
+ dns_rdataset_t keys, sigs;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dst_key_t *pubkey, *privkey;
+ dns_dnsseckey_t *key;
+ isc_result_t result;
+
+ 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)
+ continue;
+
+ /* Corrupted .key file? */
+ if (!dns_name_equal(origin, dst_key_name(pubkey)))
+ continue;
+
+ if (public) {
+ addkey(keylist, &pubkey, savekeys, mctx);
+ continue;
+ }
+
+ result = dst_key_fromfile(dst_key_name(pubkey),
+ dst_key_id(pubkey),
+ dst_key_alg(pubkey),
+ DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
+ directory, mctx, &privkey);
+ if (result == ISC_R_FILENOTFOUND) {
+ addkey(keylist, &pubkey, savekeys, mctx);
+ continue;
+ }
+ RETERR(result);
+
+ if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0) {
+ /* We should never get here. */
+ dst_key_free(&pubkey);
+ dst_key_free(&privkey);
+ continue;
+ }
+
+ addkey(keylist, &privkey, savekeys, mctx);
+
+ dst_key_free(&pubkey);
+ }
+ 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);
+
+ /*
+ * 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);
+
+ 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 (result == ISC_R_NOMORE)
+ 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)
+ dst_key_free(&privkey);
+ return (result);
+}
+
+
+static isc_result_t
+make_dnskey(dst_key_t *key, dns_rdata_t *target) {
+ isc_result_t result;
+ unsigned char data[DST_KEY_MAXSIZE];
+ isc_buffer_t b;
+ isc_region_t r;
+
+ isc_buffer_init(&b, data, sizeof(data));
+ result = dst_key_todns(key, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdata_reset(target);
+ isc_buffer_usedregion(&b, &r);
+ dns_rdata_fromregion(target, dst_key_class(key),
+ dns_rdatatype_dnskey, &r);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+publish_key(dns_diff_t *add, dns_dnsseckey_t *key, dns_name_t *origin,
+ dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
+ void (*report)(const char *, ...))
+{
+ isc_result_t result;
+ dns_difftuple_t *tuple = NULL;
+ dns_rdata_t dnskey = DNS_RDATA_INIT;
+ char alg[80];
+
+ dns_rdata_reset(&dnskey);
+ RETERR(make_dnskey(key->key, &dnskey));
+
+ dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
+ report("Fetching %s %d/%s from key %s\n",
+ key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK",
+ dst_key_id(key->key), alg,
+ key->source == dns_keysource_user ? "file" : "repository");
+
+ if (key->prepublish && ttl > key->prepublish) {
+ char keystr[DST_KEY_FORMATSIZE];
+ isc_stdtime_t now;
+
+ dst_key_format(key->key, keystr, sizeof(keystr));
+ report("Key %s: Delaying activation to match the DNSKEY TTL.",
+ keystr, ttl);
+
+ isc_stdtime_get(&now);
+ dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
+ }
+
+ /* publish key */
+ RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
+ &dnskey, &tuple));
+ dns_diff_append(add, &tuple);
+ result = ISC_R_SUCCESS;
+
+ failure:
+ return (result);
+}
+
+static isc_result_t
+remove_key(dns_diff_t *del, dns_dnsseckey_t *key, dns_name_t *origin,
+ dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
+ void (*report)(const char *, ...))
+{
+ isc_result_t result;
+ dns_difftuple_t *tuple = NULL;
+ dns_rdata_t dnskey = DNS_RDATA_INIT;
+ char alg[80];
+
+ dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
+ report("Removing %s key %d/%s from DNSKEY RRset.\n",
+ reason, dst_key_id(key->key), alg);
+
+ RETERR(make_dnskey(key->key, &dnskey));
+ RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
+ &tuple));
+ dns_diff_append(del, &tuple);
+ result = ISC_R_SUCCESS;
+
+ failure:
+ return (result);
+}
+
+/*
+ * Update 'keys' with information from 'newkeys'.
+ *
+ * If 'removed' is not NULL, any keys that are being removed from
+ * the zone will be added to the list for post-removal processing.
+ */
+isc_result_t
+dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
+ dns_dnsseckeylist_t *removed, dns_name_t *origin,
+ dns_ttl_t ttl, dns_diff_t *add, dns_diff_t *del,
+ isc_boolean_t allzsk, isc_mem_t *mctx,
+ void (*report)(const char *, ...))
+{
+ isc_result_t result;
+ dns_dnsseckey_t *key1, *key2;
+
+ key1 = ISC_LIST_HEAD(*newkeys);
+ while (key1 != NULL) {
+ isc_boolean_t key_revoked = ISC_FALSE;
+ for (key2 = ISC_LIST_HEAD(*keys);
+ key2 != NULL;
+ key2 = ISC_LIST_NEXT(key2, link)) {
+ if (dst_key_pubcompare(key1->key, key2->key,
+ ISC_TRUE)) {
+ int r1, r2;
+ r1 = dst_key_flags(key1->key) &
+ DNS_KEYFLAG_REVOKE;
+ r2 = dst_key_flags(key2->key) &
+ DNS_KEYFLAG_REVOKE;
+ key_revoked = ISC_TF(r1 != r2);
+ break;
+ }
+ }
+
+ /* No match found in keys; add the new key. */
+ if (key2 == NULL) {
+ dns_dnsseckey_t *next;
+
+ next = ISC_LIST_NEXT(key1, link);
+ ISC_LIST_UNLINK(*newkeys, key1, link);
+ ISC_LIST_APPEND(*keys, key1, link);
+
+ if (key1->source != dns_keysource_zoneapex &&
+ (key1->hint_publish || key1->force_publish)) {
+ RETERR(publish_key(add, key1, origin, ttl,
+ mctx, allzsk, report));
+ if (key1->hint_sign || key1->force_sign)
+ key1->first_sign = ISC_TRUE;
+ }
+
+ key1 = next;
+ continue;
+ }
+
+ /* Match found: remove or update it as needed */
+ if (key1->hint_remove) {
+ RETERR(remove_key(del, key2, origin, ttl, mctx,
+ "expired", report));
+ ISC_LIST_UNLINK(*keys, key2, link);
+ if (removed != NULL)
+ ISC_LIST_APPEND(*removed, key2, link);
+ else
+ 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.
+ * We need to remove the old version and pull
+ * in the new one.
+ */
+ RETERR(remove_key(del, key2, origin, ttl, mctx,
+ "revoked", report));
+ ISC_LIST_UNLINK(*keys, key2, link);
+ if (removed != NULL)
+ ISC_LIST_APPEND(*removed, key2, link);
+ else
+ dns_dnsseckey_destroy(mctx, &key2);
+
+ 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);
+
+ /*
+ * XXX: The revoke flag is only defined for trust
+ * anchors. Setting the flag on a non-KSK is legal,
+ * but not defined in any RFC. It seems reasonable
+ * to treat it the same as a KSK: keep it in the
+ * zone, sign the DNSKEY set with it, but not
+ * 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 */
+ while (!ISC_LIST_EMPTY(*newkeys)) {
+ key1 = ISC_LIST_HEAD(*newkeys);
+ ISC_LIST_UNLINK(*newkeys, key1, link);
+ dns_dnsseckey_destroy(mctx, &key1);
+ }
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ return (result);
+}
/*
* Principal Author: Brian Wellington
- * $Id: dst_api.c,v 1.40 2009/10/12 09:03:06 marka Exp $
+ * $Id: dst_api.c,v 1.41 2009/10/12 20:48:12 each Exp $
*/
/*! \file */
return (ISC_FALSE);
/* Zero out flags. */
buf1[0] = buf1[1] = 0;
+ if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
+ isc_buffer_subtract(&b1, 2);
isc_buffer_init(&b2, buf2, sizeof(buf2));
result = dst_key_todns(key2, &b2);
return (ISC_FALSE);
/* Zero out flags. */
buf2[0] = buf2[1] = 0;
+ if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
+ isc_buffer_subtract(&b2, 2);
isc_buffer_usedregion(&b1, &r1);
/* Remove extended flags. */
return (ISC_R_SUCCESS);
}
+/*%
+ * Set the flags on a key, then recompute the key ID
+ */
+isc_result_t
+dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
+ REQUIRE(VALID_KEY(key));
+ key->key_flags = flags;
+ return (computeid(key));
+}
+
+void
+dst_key_format(dst_key_t *key, char *cp, unsigned int size) {
+ char namestr[DNS_NAME_FORMATSIZE];
+ char algstr[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
+ dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr,
+ sizeof(algstr));
+ snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
+}
+
/***
*** Static methods
***/
return (ret);
}
-/*%
- * Set the flags on a key, then recompute the key ID
- */
-isc_result_t
-dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
- REQUIRE(VALID_KEY(key));
- key->key_flags = flags;
- return (computeid(key));
-}
-
static isc_boolean_t
issymmetric(const dst_key_t *key) {
REQUIRE(dst_initialized == ISC_TRUE);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec.h,v 1.36 2009/09/02 06:29:01 each Exp $ */
+/* $Id: dnssec.h,v 1.37 2009/10/12 20:48:12 each Exp $ */
#ifndef DNS_DNSSEC_H
#define DNS_DNSSEC_H 1
#include <isc/lang.h>
#include <isc/stdtime.h>
+#include <dns/diff.h>
#include <dns/types.h>
#include <dst/dst.h>
isc_boolean_t hint_sign; /*% metadata says to sign with this key */
isc_boolean_t force_sign; /*% sign with key regardless of metadata */
isc_boolean_t hint_remove; /*% metadata says *don't* publish */
+ isc_boolean_t is_active; /*% key is already active */
+ isc_boolean_t first_sign; /*% key is newly becoming active */
unsigned int prepublish; /*% how long until active? */
dns_keysource_t source; /*% how the key was found */
isc_boolean_t ksk; /*% this is a key-signing key */
*\li On error, keylist is unchanged
*/
+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_dnsseckeylist_t *keylist);
+/*%<
+ * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
+ * Omit duplicates. If 'public' is ISC_FALSE, search 'directory' for
+ * 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.
+ */
+
+isc_result_t
+dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
+ dns_dnsseckeylist_t *removed, dns_name_t *origin,
+ dns_ttl_t ttl, dns_diff_t *add, dns_diff_t *del,
+ isc_boolean_t allzsk, isc_mem_t *mctx,
+ void (*report)(const char *, ...));
+/*%<
+ * Update the list of keys in 'keys' with new key information in 'newkeys'.
+ *
+ * For each key in 'newkeys', see if it has a match in 'keys'.
+ * - If not, and if the metadata says the key should be published:
+ * add it to 'keys', and place a dns_difftuple into 'add' so
+ * the key can be added to the DNSKEY set. If the metadata says it
+ * should be active, set the first_sign flag.
+ * - If so, and if the metadata says it should be removed:
+ * remove it from 'keys', and place a dns_difftuple into 'del' so
+ * the key can be removed from the DNSKEY set. if 'removed' is non-NULL,
+ * copy the key into that list; otherwise destroy it.
+ * - Otherwise, make sure keys has current metadata.
+ *
+ * If 'allzsk' is true, we are allowing KSK-flagged keys to be used as
+ * ZSKs.
+ *
+ * 'ttl' is the TTL of the DNSKEY RRset; if it is longer than the
+ * time until a new key will be activated, then we have to delay the
+ * key's activation.
+ *
+ * 'report' points to a function for reporting status.
+ *
+ * On completion, any remaining keys in 'newkeys' are freed.
+ */
ISC_LANG_ENDDECLS
#endif /* DNS_DNSSEC_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.h,v 1.116 2008/09/25 04:02:39 tbox Exp $ */
+/* $Id: result.h,v 1.117 2009/10/12 20:48:12 each Exp $ */
#ifndef DNS_RESULT_H
#define DNS_RESULT_H 1
#define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102)
#define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103)
#define DNS_R_INVALIDNSEC3 (ISC_RESULTCLASS_DNS + 104)
+#define DNS_R_NOTMASTER (ISC_RESULTCLASS_DNS + 105)
-#define DNS_R_NRESULTS 105 /*%< Number of results */
+#define DNS_R_NRESULTS 106 /*%< Number of results */
/*
* DNS wire format rcodes.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: secalg.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: secalg.h,v 1.20 2009/10/12 20:48:12 each Exp $ */
#ifndef DNS_SECALG_H
#define DNS_SECALG_H 1
*\li ISC_R_NOSPACE target buffer is too small
*/
+#define DNS_SECALG_FORMATSIZE 20
+void
+dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size);
+/*%<
+ * Wrapper for dns_secalg_totext(), writing text into 'cp'
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_SECALG_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.h,v 1.169 2009/10/10 01:48:00 each Exp $ */
+/* $Id: zone.h,v 1.170 2009/10/12 20:48:12 each Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
#define DNS_ZONEOPT_NOTIFYFORWARD 0x80000000U /* forward notify to master */
#endif /* NOMINUM_PUBLIC */
+/*
+ * Zone key maintenance options
+ */
+#define DNS_ZONEKEY_ALLOW 0x00000001U /*%< fetch keys on command */
+#define DNS_ZONEKEY_MAINTAIN 0x00000002U /*%< publish/sign on schedule */
+#define DNS_ZONEKEY_CREATE 0x00000004U /*%< make keys when needed */
+
#ifndef DNS_ZONE_MINREFRESH
#define DNS_ZONE_MINREFRESH 300 /*%< 5 minutes */
#endif
*\li 'zone' to be a valid zone.
*/
+void
+dns_zone_setkeyopt(dns_zone_t *zone, unsigned int option, isc_boolean_t value);
+/*%<
+ * Set key options on ('value' == ISC_TRUE) or off ('value' ==
+ * #ISC_FALSE).
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
+unsigned int
+dns_zone_getkeyopts(dns_zone_t *zone);
+/*%<
+ * Returns the current zone key options.
+ *
+ * Require:
+ *\li 'zone' to be a valid zone.
+ */
+
void
dns_zone_setminrefreshtime(dns_zone_t *zone, isc_uint32_t val);
/*%<
* will not be permanent.
*/
+isc_result_t
+dns_zone_rekey(dns_zone_t *zone);
+/*%<
+ * Update the zone's DNSKEY set from the key repository.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_ZONE_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dst.h,v 1.21 2009/10/09 06:09:21 each Exp $ */
+/* $Id: dst.h,v 1.22 2009/10/12 20:48:12 each Exp $ */
#ifndef DST_DST_H
#define DST_DST_H 1
#include <isc/stdtime.h>
#include <dns/types.h>
+#include <dns/name.h>
+#include <dns/secalg.h>
#include <dst/gssapi.h>
*\li ISC_TRUE
* \li ISC_FALSE
*/
+
isc_boolean_t
dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2);
/*%<
* "key" is a valid key.
*/
+#define DST_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + 7)
+
+void
+dst_key_format(dst_key_t *key, char *cp, unsigned int size);
+/*%<
+ * Write the uniquely identifying information about the key (name,
+ * algorithm, key ID) into a string 'cp' of size 'size'.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DST_DST_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rcode.c,v 1.9 2008/12/16 05:04:47 marka Exp $ */
+/* $Id: rcode.c,v 1.10 2009/10/12 20:48:12 each Exp $ */
#include <config.h>
#include <ctype.h>
return (dns_mnemonic_totext(secalg, target, secalgs));
}
+void
+dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
+ isc_buffer_t b;
+ isc_region_t r;
+ isc_result_t result;
+
+ REQUIRE(cp != NULL && size > 0);
+ isc_buffer_init(&b, cp, size - 1);
+ result = dns_secalg_totext(alg, &b);
+ isc_buffer_usedregion(&b, &r);
+ r.base[r.length] = 0;
+ if (result != ISC_R_SUCCESS)
+ r.base[0] = 0;
+}
+
isc_result_t
dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
unsigned int value;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.c,v 1.127 2009/03/01 23:47:25 tbox Exp $ */
+/* $Id: result.c,v 1.128 2009/10/12 20:48:12 each Exp $ */
/*! \file */
"MX is an address", /*%< 102 DNS_R_MXISADDRESS */
"duplicate query", /*%< 103 DNS_R_DUPLICATE */
"invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */
+ "not master", /*%< 105 DNS_R_NOTMASTER */
};
static const char *rcode_text[DNS_R_NRCODERESULTS] = {
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.515 2009/10/10 23:47:58 tbox Exp $ */
+/* $Id: zone.c,v 1.516 2009/10/12 20:48:12 each Exp $ */
/*! \file */
isc_time_t keywarntime;
isc_time_t signingtime;
isc_time_t nsec3chaintime;
- isc_time_t refreshkeytime; /* Used by key zones */
+ isc_time_t refreshkeytime;
isc_uint32_t refreshkeycount;
isc_uint32_t refresh;
isc_uint32_t retry;
isc_uint32_t signatures;
isc_uint32_t nodes;
dns_rdatatype_t privatetype;
+
+ /*%
+ * Autosigning/key-maintenance options
+ */
+ isc_uint32_t keyopts;
};
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
#define DNS_ZONEFLG_THAW 0x08000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
+#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
/* Flags for zone_load() */
#define DNS_ZONELOADFLAG_NOSTAT 0x00000001U /* Do not stat() master files */
static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver,
dns_dbnode_t *node, dns_name_t *name,
dns_diff_t *diff);
+static isc_result_t zone_rekey(dns_zone_t *zone);
#define ENTER zone_debuglog(zone, me, 1, "enter")
zone->type = dns_zone_none;
zone->flags = 0;
zone->options = 0;
+ zone->keyopts = 0;
zone->db_argc = 0;
zone->db_argv = NULL;
isc_time_settoepoch(&zone->expiretime);
dns_db_detachnode(db, &node);
if (version != NULL)
dns_db_closeversion(db, &version, ISC_FALSE);
-
}
static void
if (zone->type == dns_zone_master)
zone_check_dnskeys(zone, db);
+ /*
+ * Schedule DNSSEC key refresh.
+ */
+ if (zone->type == dns_zone_master &&
+ DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN))
+ zone->refreshkeytime = now;
+
#if 0
/* destroy notification example. */
{
return (zone->options);
}
+void
+dns_zone_setkeyopt(dns_zone_t *zone, unsigned int keyopt, isc_boolean_t value)
+{
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ LOCK_ZONE(zone);
+ if (value)
+ zone->keyopts |= keyopt;
+ else
+ zone->keyopts &= ~keyopt;
+ UNLOCK_ZONE(zone);
+}
+
+unsigned int
+dns_zone_getkeyopts(dns_zone_t *zone) {
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (zone->keyopts);
+}
+
isc_result_t
dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
REQUIRE(DNS_ZONE_VALID(zone));
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING))
zone_refreshkeys(zone);
break;
+ case dns_zone_master:
+ if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN) &&
+ !isc_time_isepoch(&zone->refreshkeytime) &&
+ isc_time_compare(&now, &zone->refreshkeytime) >= 0)
+ dns_zone_rekey(zone);
default:
break;
}
isc_time_compare(&zone->dumptime, &next) < 0)
next = zone->dumptime;
}
+ if (DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN) &&
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESHING)) {
+ if (isc_time_isepoch(&next) ||
+ (!isc_time_isepoch(&zone->refreshkeytime) &&
+ isc_time_compare(&zone->refreshkeytime, &next) < 0))
+ next = zone->refreshkeytime;
+ }
if (!isc_time_isepoch(&zone->resigntime)) {
if (isc_time_isepoch(&next) ||
isc_time_compare(&zone->resigntime, &next) < 0)
}
return (result);
}
+
+static void
+logmsg(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
+ ISC_LOG_DEBUG(1), format, args);
+ va_end(args);
+}
+
+static void
+clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) {
+ dns_dnsseckey_t *key;
+ while (!ISC_LIST_EMPTY(*list)) {
+ key = ISC_LIST_HEAD(*list);
+ ISC_LIST_UNLINK(*list, key, link);
+ dns_dnsseckey_destroy(mctx, &key);
+ }
+}
+
+static isc_result_t
+next_keyevent(dst_key_t *key, isc_stdtime_t *timep) {
+ isc_result_t result;
+ isc_stdtime_t now, then = 0, event;
+ int i;
+
+ isc_stdtime_get(&now);
+
+ for (i = 0; i <= DST_MAX_TIMES; i++) {
+ result = dst_key_gettime(key, i, &event);
+ if (result == ISC_R_SUCCESS && event > now &&
+ (then == 0 || event < then))
+ then = event;
+ }
+
+ if (then != 0) {
+ *timep = then;
+ return (ISC_R_SUCCESS);
+ }
+
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+zone_rekey(dns_zone_t *zone) {
+ isc_result_t result;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *ver = NULL;
+ dns_rdataset_t soaset, keyset, sigset;
+ dns_dnsseckeylist_t dnskeys, keys, oldkeys;
+ dns_dnsseckey_t *key;
+ dns_diff_t add, del;
+ isc_boolean_t commit = ISC_FALSE;
+ dns_ttl_t ttl = 3600;
+ const char *dir;
+ isc_mem_t *mctx;
+ isc_stdtime_t now;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ISC_LIST_INIT(dnskeys);
+ ISC_LIST_INIT(keys);
+ ISC_LIST_INIT(oldkeys);
+ dns_rdataset_init(&soaset);
+ dns_rdataset_init(&keyset);
+ dns_rdataset_init(&sigset);
+ dir = dns_zone_getkeydirectory(zone);
+ mctx = zone->mctx;
+ dns_diff_init(mctx, &add);
+ dns_diff_init(mctx, &del);
+ isc_stdtime_get(&now);
+
+ CHECK(dns_zone_getdb(zone, &db));
+ CHECK(dns_db_newversion(db, &ver));
+ CHECK(dns_db_getoriginnode(db, &node));
+
+ /* Get the SOA record's TTL */
+ CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_soa,
+ dns_rdatatype_none, 0, &soaset, NULL));
+ 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);
+ if (result == ISC_R_SUCCESS) {
+ ttl = keyset.ttl;
+ CHECK(dns_dnssec_keylistfromrdataset(&zone->origin, dir,
+ mctx, &keyset, &sigset,
+ ISC_FALSE, ISC_FALSE,
+ &dnskeys));
+ } else if (result != ISC_R_NOTFOUND)
+ goto failure;
+
+ result = dns_dnssec_findmatchingkeys(&zone->origin, dir, mctx, &keys);
+ if (result == ISC_R_SUCCESS) {
+ isc_boolean_t check_ksk;
+ check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+
+ CHECK(dns_dnssec_updatekeys(&dnskeys, &keys, &oldkeys,
+ &zone->origin, ttl, &add, &del,
+ ISC_TF(!check_ksk), mctx, logmsg));
+ if (!ISC_LIST_EMPTY(del.tuples)) {
+ commit = ISC_TRUE;
+ dns_diff_apply(&del, db, ver);
+ result = increment_soa_serial(db, ver, &del, mctx);
+ if (result == ISC_R_SUCCESS)
+ zone_journal(zone, &del, "zone_rekey");
+ }
+ if (!ISC_LIST_EMPTY(add.tuples)) {
+ commit = ISC_TRUE;
+ dns_diff_apply(&add, db, ver);
+ result = increment_soa_serial(db, ver, &add, mctx);
+ if (result == ISC_R_SUCCESS)
+ zone_journal(zone, &add, "zone_rekey");
+
+ }
+ }
+
+ dns_db_closeversion(db, &ver, commit);
+
+ if (commit) {
+ for (key = ISC_LIST_HEAD(oldkeys);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ zone_signwithkey(zone, dst_key_alg(key->key),
+ dst_key_id(key->key), ISC_TRUE);
+ }
+
+ for (key = ISC_LIST_HEAD(dnskeys);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ if (key->first_sign) {
+ zone_signwithkey(zone, dst_key_alg(key->key),
+ dst_key_id(key->key),
+ ISC_FALSE);
+ key->is_active = ISC_TRUE;
+ key->first_sign = ISC_FALSE;
+ }
+ }
+ }
+
+ isc_time_settoepoch(&zone->refreshkeytime);
+ for (key = ISC_LIST_HEAD(dnskeys);
+ key != NULL;
+ key = ISC_LIST_NEXT(key, link)) {
+ isc_stdtime_t then;
+ isc_time_t timenow, timethen;
+
+ /*
+ * If we are doing automatic key maintenace and the
+ * key metadata indicates there is a key change event
+ * scheduled in the future, set the key refresh timer.
+ */
+ if (!DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN))
+ break;
+
+ result = next_keyevent(key->key, &then);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ isc_time_set(&timethen, then, 0);
+ if (isc_time_isepoch(&zone->refreshkeytime) ||
+ isc_time_compare(&timethen, &zone->refreshkeytime) < 0) {
+ zone->refreshkeytime = timethen;
+ zone_settimer(zone, &timenow);
+ }
+ }
+
+ result = ISC_R_SUCCESS;
+
+ failure:
+ dns_diff_clear(&add);
+ dns_diff_clear(&del);
+
+ clear_keylist(&dnskeys, mctx);
+ clear_keylist(&keys, mctx);
+ clear_keylist(&oldkeys, mctx);
+
+ if (ver != NULL)
+ 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 (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (db != NULL)
+ dns_db_detach(&db);
+ return (result);
+}
+
+isc_result_t
+dns_zone_rekey(dns_zone_t *zone) {
+ isc_result_t result;
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESHING);
+ result = zone_rekey(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING);
+ UNLOCK_ZONE(zone);
+ return (result);
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.107 2009/10/10 01:48:00 each Exp $ */
+/* $Id: namedconf.c,v 1.108 2009/10/12 20:48:12 each Exp $ */
/*! \file */
&cfg_rep_list, &cfg_type_sockaddr
};
+static const char *autodnssec_enums[] = { "allow", "maintain", "create",
+ "off", NULL };
+static cfg_type_t cfg_type_autodnssec = {
+ "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &autodnssec_enums
+};
+
static cfg_type_t cfg_type_rrsetorder = {
"rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
&cfg_rep_list, &cfg_type_rrsetorderingelement
*/
{ "check-names", &cfg_type_checkmode, 0 },
{ "ixfr-from-differences", &cfg_type_boolean, 0 },
+ { "auto-dnssec", &cfg_type_autodnssec, 0 },
{ NULL, NULL, 0 }
};