signer.c revision 7a152bdae33caae47eb48a291eb0ccb346ce7934
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Copyright (C) 1999, 2000 Internet Software Consortium.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Permission to use, copy, modify, and distribute this software for any
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * purpose with or without fee is hereby granted, provided that the above
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * copyright notice and this permission notice appear in all copies.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence/*#define USE_ZONESTATUS*/
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencetypedef struct signer_key_struct signer_key_t;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencetypedef struct signer_array_struct signer_array_t;
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrencestatic isc_stdtime_t starttime = 0, endtime = 0, now;
ae4cbb69eef32ced103fe4561e8d2031ee4c3497David Lawrencestatic inline void
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencestatic inline void
0293ad13207aa29bd5844cdc87d085ffc009d749David Lawrencecheck_result(isc_result_t result, char *message) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence fprintf(stderr, "%s: %s: %s\n", PROGRAM, message,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence/* Not thread-safe! */
657ce0b9d84fbd66514df53d61a087e8f1161187Michael Graff result = dns_name_totext(name, ISC_FALSE, &b);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence return (char *) r.base;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence/* Not thread-safe! */
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence check_result(result, "dns_rdatatype_totext()");
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence return (char *) r.base;
4bcaefbcd3ced942139fdc830e007c6ea2b8d2feDavid Lawrence/* Not thread-safe! */
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence return (char *) r.base;
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafssonstatic inline void
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafssonset_bit(unsigned char *array, unsigned int index, unsigned int bit) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrencesignwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson result = dns_dnssec_sign(name, rdataset, key, &starttime, &endtime,
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson fatal("key '%s/%s/%d' failed to sign data: %s",
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson dst_key_name(key), algtostr(dst_key_alg(key)),
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson dst_key_id(key), isc_result_totext(result));
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson result = dns_dnssec_verify(name, rdataset, key,
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson vbprintf(3, "\tsignature failed to verify\n");
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson isc_buffer_init(&b, origin, sizeof(origin));
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson result = dns_name_totext(dns_db_origin(db), ISC_FALSE, &b);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson check_result(result, "dns_name_totext()");
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson return (ISC_TF(strcasecmp(dst_key_name(key->key), origin) == 0 &&
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson (dst_key_flags(key->key) & DNS_KEYFLAG_OWNERMASK) ==
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson * Finds the key that generated a SIG, if possible. First look at the keys
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * that we've loaded already, and then see if there's a key on disk.
2b556032fd78aff37e80e755044b944a017245cdDavid Lawrence strcasecmp(keyname, dst_key_name(key->key)) == 0)
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley result = dst_key_fromfile(keyname, sig->keyid, sig->algorithm,
7c0876aa42e6abaa8779bcb83962ccf20a9f4da3Bob Halley result = dst_key_fromfile(keyname, sig->keyid, sig->algorithm,
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * Check to see if we expect to find a key at this name. If we see a SIG
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * and can't find the signing key that we expect to find, we drop the sig.
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence * I'm not sure if this is completely correct, but it seems to work.
a505a3f6e09218bebac020fc49105b2e6cd9e25cBob Halleyexpecttofindkey(dns_name_t *name, dns_db_t *db, dns_dbversion_t *version) {
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence result = dns_db_find(db, name, version, dns_rdatatype_key, options,
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halley 0, NULL, dns_fixedname_name(&fname), NULL, NULL);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence fatal("failure looking for '%s KEY' in database: %s",
facb97777a972f6c8035ca3e762a6a9248c12897Bob Halleysetverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
a829555ed724caa56b1ff7716d7eda2266491eafBob Halley result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence trdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); \
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence tdata = isc_mem_get(mctx, sizeof(signer_array_t)); \
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence isc_buffer_init(&b, tdata->array, sizeof(tdata->array));
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff * Signs a set. Goes through contortions to decide if each SIG should
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff * be dropped or retained, and then determines if any new SIGs need to
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graff * be generated.
882350d11c90de9de6fc1cead25690c8114b0b95Michael Graffsignset(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley isc_boolean_t notsigned = ISC_TRUE, nosigs = ISC_FALSE;
1443aa0adf4d262abdf2721a5239acd4812cdc06Bob Halley isc_boolean_t wassignedby[256], nowsignedby[256];
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley for (i = 0; i < 256; i++)
694c897b20f06f8a5349fd9ac5df93947f6f5a2aBob Halley result = dns_db_findrdataset(db, node, version, dns_rdatatype_sig,
7c0876aa42e6abaa8779bcb83962ccf20a9f4da3Bob Halley fatal("failed while looking for '%s SIG %s': %s",
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley vbprintf(1, "%s/%s:\n", nametostr(name), typetostr(set->type));
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence isc_boolean_t keep = ISC_FALSE, resign = ISC_FALSE;
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence dns_rdataset_current(&oldsigset, &oldsigrdata);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson result = dns_rdata_tostruct(&oldsigrdata, &sig, mctx);
ea31416b4fcdf23732355a8002f93f29e3b3d2dbAndreas Gustafsson expired = ISC_TF(now + cycle > sig.timeexpire);
1922518d7f7b5e3e77b8e1c92569c98268b9c192Andreas Gustafsson /* sig is dropped and not replaced */
9cda9dc86efa0dde8f906759c4e3279da028b5f4Bob Halley "invalid validity period\n",
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley /* sig is dropped and not replaced */
35c842e05dc6382ce1d9161a658d3ff4b2c3d4c9Bob Halley "private key not found\n",
4c5faa6bcf41d8ba253b872a04105a2fcc88c07bMichael Graff "key not found\n",
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence "\tsig by %s/%s/%d retained\n",
8671e8306b3f18abf0e19c2fb9d49205962e7ab7David Lawrence "\tsig by %s/%s/%d dropped - "
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews "failed to verify");
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews "\tsig by %s/%s/%d retained\n",
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews "\tsig by %s/%s/%d "
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews "dropped - %s\n",
40f24178432de09181bc603cc90110546a0ddca2Mark Andrews "failed to verify");
b21d8bac45b614c39a106c9ee8137589328ea075Andreas Gustafsson vbprintf(1, "\tresigning with key %s/%s/%d\n",
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews check_result(result, "dns_db_dns_rdataset_first()/next()");
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews for (i = 0; i < 256; i++)
6182613ef54ebb8369d951ffa4431c49b75cec51Mark Andrews if (wassignedby[i] != 0) {
c7620c99f1139b77f14678e21a44f7c8c4236a7bMark Andrews (notsigned || (wassignedby[alg] && !nowsignedby[alg])))
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence ISC_LIST_APPEND(siglist.rdata, trdata, link);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson result = dns_rdatalist_tordataset(&siglist, &sigset);
ca485ab26fffa241a3eac1899b2d2012dd1fdb73Andreas Gustafsson check_result(result, "dns_rdatalist_tordataset");
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence result = dns_db_addrdataset(db, node, version, 0, &sigset,
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley else if (!nosigs) {
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley * If this is compiled in, running a signed set through the
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley * signer with no private keys causes DNS_R_BADDB to occur
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley * later. This is bad.
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley result = dns_db_deleterdataset(db, node, version,
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley fatal("File is currently signed but no private keys were "
64e41159a919b0711321fe688ca5da4f4d1b7d80Bob Halley "found. This won't work.");
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence dns_rdata_t *next = ISC_LIST_NEXT(trdata, link);
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence isc_mem_put(mctx, trdata, sizeof(dns_rdata_t));
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence signer_array_t *next = ISC_LIST_NEXT(tdata, link);
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence isc_mem_put(mctx, tdata, sizeof(signer_array_t));
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence/* Determine if a KEY set contains a null key */
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence result = dns_dnssec_keyfromrdata(dns_rootname,
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence fatal("could not convert KEY into internal format");
0fde58a7673f28fcc08eb8f597581247a4c2db20Bob Halley * Looks for signatures of the zone keys by the parent, and imports them
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrenceimportparentsig(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence isc_buffer_init(&b, filename, sizeof(filename) - 10);
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence result = dns_name_totext(name, ISC_FALSE, &b);
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence strcpy((char *)r.base + r.length, "signedkey");
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db),
7bb707a34778fc4bd9624d6c5de95675424ea59fDavid Lawrence result = dns_db_load(newdb, (char *)filename);
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
8a9b755d32a4f6ace792ac3fd17c968cf96d2487David Lawrence if (dns_rdataset_count(set) != dns_rdataset_count(&newset))
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence check_result(result, "dns_rdataset_first()");
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(set)) {
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley vbprintf(2, "found the parent's signature of our zone key\n");
1bb509f58b57f1d9ef413762fb9e3dd2bcaf7ed4Mark Andrews result = dns_db_addrdataset(db, node, version, 0, &sigset, 0, NULL);
51a659eb711eb6a17891675d3de6b8085a766ab2Mark Andrews * Looks for our signatures of child keys. If present, inform the caller,
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley * who will set the zone status (KEY) bit in the NXT record.
5c00d1c90030a311d2700970fa7cffc8f828a48cBob Halley isc_buffer_init(&b, filename, sizeof(filename) - 10);
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence strcpy((char *)r.base + r.length, "signedkey");
df3c4c7988b9bae7d121a8ac9ed17a23366a948dDavid Lawrence result = dns_db_create(mctx, "rbt", name, ISC_FALSE, dns_db_class(db),
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley result = dns_db_findnode(newdb, name, ISC_FALSE, &newnode);
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley result = dns_db_findrdataset(newdb, newnode, NULL, dns_rdatatype_key,
51917258dbb23cfe6069ae1cf2b7fc5aefc1e0c2Bob Halley for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigset)) {
6d5dcd0dc9bdbd679282b1ffc47987d24c3a1346Bob Halley result = dns_rdata_tostruct(&sigrdata, &sig, mctx);
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * Signs all records at a name. This mostly just signs each set individually,
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * but also adds the SIG bit to any NXTs generated earlier, deals with
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley * parent/child KEY signatures, and handles other exceptional cases.
65c4736d9c0ebc6d9b1d991593b55566909da9cdBrian Wellingtonsignname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
c68fa795a1c87fd5d0386e0503dc5666490ac77fMichael Graff static int warnwild = 0;
860728724ad298f60d5c6e7485d37c3b2b1ad632David Lawrence fprintf(stderr, "%s: warning: BIND 9 doesn't "
860728724ad298f60d5c6e7485d37c3b2b1ad632David Lawrence "handle wildcards in secure zones\n", PROGRAM);
44aae046c38e796e581110b7ecdf4478167d684dBob Halley fprintf(stderr, "%s: warning: wildcard name seen: %s\n",
12ccbb032ec1b5f6b93aac923f2645a19fc90c75David Lawrence result = dns_db_findrdataset(db, node, version,
44aae046c38e796e581110b7ecdf4478167d684dBob Halley /* Is this a delegation point? */
a5d43b72413db3edd6b36a58f9bdf2cf6ff692f2Bob Halley result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
goto skip;
goto skip;
if (isdelegation) {
case dns_rdatatype_nxt:
#ifndef USE_ZONESTATUS
case dns_rdatatype_key:
goto skip;
goto skip;
unsigned char *nxt_bits;
isc_buffer_t b;
#ifdef USE_ZONESTATUS
0, 0, &keyset,
NULL);
goto alreadyhavenullkey;
isc_buffer_usedregion(&b, &r);
dns_rdatatype_key, &r);
link);
result =
&keyset);
NULL);
skip:
static inline isc_boolean_t
if (!active)
if (!active) {
dns_rdatatype_nxt, 0);
return (active);
static inline isc_result_t
if (!active) {
return (result);
static inline isc_result_t
return (ISC_R_SUCCESS);
return (result);
lastcut);
if (!atorigin) {
0, &rdsiter);
sizeof(dns_name_t));
int len;
unsigned int nkeys, i;
for (i = 0; i < nkeys; i++) {
static isc_stdtime_t
usage() {
exit(0);
== ISC_R_SUCCESS);
int i, ch;
char *endp;
int loglevel;
switch (ch) {
usage();
switch (verbose) {
usage();
if (argc == 0) {
for (i = 0; i < argc; i++) {
int alg;
isc_buffer_t b;
usage();