dnssec.c revision d312bc5d81cff8fc156b62c970334b52227ee854
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
6bb1560124ce99fe50b9847ce29fcaed52564900Automatic Updater * Copyright (C) 1999-2003 Internet Software Consortium.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Permission to use, copy, modify, and/or distribute this software for any
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * purpose with or without fee is hereby granted, provided that the above
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * copyright notice and this permission notice appear in all copies.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * PERFORMANCE OF THIS SOFTWARE.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * $Id: dnssec.c,v 1.114 2009/11/24 03:42:32 each Exp $
e24ccb512c110d181e01f977196e518b0e72e451Mark Andrews#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
e24ccb512c110d181e01f977196e518b0e72e451Mark Andrews#define RETERR(x) do { \
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Huntrdata_compare_wrapper(const void *rdata1, const void *rdata2);
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Huntrdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Make qsort happy.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Huntrdata_compare_wrapper(const void *rdata1, const void *rdata2) {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt return (dns_rdata_compare((const dns_rdata_t *)rdata1,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Sort the rdataset into an array.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Huntrdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt int i = 0, n;
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * Put them in the array.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Sort the array.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Huntdns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Huntdigest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt dns_name_toregion(dns_fixedname_name(&fname), &r);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Huntdns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt unsigned int sigsize;
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Is the key allowed to sign data?
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * The actual contents of sig.signature are not important yet, since
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * they're not used in digest_sig().
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the SIG rdata.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt dns_name_toregion(dns_fixedname_name(&fnewname), &r);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Create an envelope for each rdata: <name|type|class|ttl>.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt for (i = 0; i < nrdatas; i++) {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Skip duplicates.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the envelope.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the length of the rdata.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the rdata.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Huntdns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (isc_serial_lt(sig.timeexpire, sig.timesigned))
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Is SIG temporally valid?
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * NS, SOA and DNSSKEY records are signed by their owner.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * DS records are signed by the parent.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt /* FALLTHROUGH */
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Is the key allowed to sign data?
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the SIG rdata (not including the signature).
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * If the name is an expanded wildcard, use the wildcard name.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt dns_name_toregion(dns_fixedname_name(&fnewname), &r);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Create an envelope for each rdata: <name|type|class|ttl>.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt for (i = 0; i < nrdatas; i++) {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Skip duplicates.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the envelope.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the rdata length.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Digest the rdata.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Huntdns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_stdtime_t now, publish, active, revoke, inactive, delete;
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt /* Is this an old-style key? */
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dst_key_getprivateformat(key, &major, &minor);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Smart signing started with key format 1.3; prior to that, all
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * keys are assumed active
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
f766024a27c891a107a1f57013d8a460fb172b19Evan Hunt result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if ((inactset && inactive <= now) || (delset && delete <= now))
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt if (revset && revoke <= now && pubset && publish <= now)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
f766024a27c891a107a1f57013d8a460fb172b19Evan Huntdns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt unsigned int *nkeys)
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt unsigned int count = 0;
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt while (result == ISC_R_SUCCESS && count < maxkeys) {
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt /* Corrupted .key file? */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * If the key was revoked and the private file
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * doesn't exist, maybe it was revoked internally
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * by named. Try loading the unrevoked version.
bbedadf76ab670b01887fb9b41097120ea4fdf14Evan Hunt * If a key is marked inactive, skip it
bbedadf76ab670b01887fb9b41097120ea4fdf14Evan Hunt if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
bbedadf76ab670b01887fb9b41097120ea4fdf14Evan Hunt /* We should never get here. */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Huntdns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt unsigned int *nkeys)
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrewsdns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
c6f4972c745f8903aba6dcca41f17a44c473db66Mark Andrews unsigned int sigsize;
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * Digest the fields of the SIG - we can cheat and use
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * dns_rdata_fromstruct. Since siglen is 0, the digested data
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt * is identical to dns format.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
goto failure;
return (ISC_R_SUCCESS);
if (signeedsfree)
return (result);
return (DNS_R_UNEXPECTEDTSIG);
goto failure;
goto failure;
goto failure;
goto failure;
goto failure;
goto failure;
return (ISC_R_SUCCESS);
if (signeedsfree)
return (result);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
isc_buffer_t b;
unsigned int len;
if (dir_open)
return (result);
static isc_result_t
return (result);
goto skip;
goto skip;
if (public) {
goto skip;
goto skip;
goto skip;
skip:
return (result);
static isc_result_t
isc_buffer_t b;
isc_region_t r;
return (result);
isc_buffer_usedregion(&b, &r);
dns_rdatatype_dnskey, &r);
return (ISC_R_SUCCESS);
static isc_result_t
void (*report)(const char *, ...))
return (result);
static isc_result_t
void (*report)(const char *, ...))
&tuple));
return (result);
ISC_TRUE)) {
} else if (key_revoked &&
return (result);