validator.c revision 115635379a2baf2100695018109ad39e0dac349d
699f790c49d03a9ef3c3234a72d272bb469203e8Evan Hunt * Copyright (C) 2000 Internet Software Consortium.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * We don't use the SIG RR's _tostruct routine because it copies things.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunttypedef struct dns_siginfo {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt /* Unlocked. */
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt unsigned int magic;
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt /* Locked by lock. */
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt unsigned int options;
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt unsigned int attributes;
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt unsigned int labels;
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0)
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntnullkeyvalidated(isc_task_t *task, isc_event_t *event);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntcontainsnullkey(dns_validator_t *val, dns_rdataset_t *rdataset);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntget_dst_key(dns_validator_t *val, dns_siginfo_t *siginfo,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntvalidate(dns_validator_t *val, isc_boolean_t resume);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntnxtvalidate(dns_validator_t *val, isc_boolean_t resume);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntproveunsecure(dns_validator_t *val, isc_boolean_t resume);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntvalidator_log(dns_validator_t *val, int level, const char *fmt, ...);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntrdata_to_siginfo(dns_rdata_t *rdata, dns_siginfo_t *siginfo) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->covers = (dns_rdatatype_t)isc_buffer_getuint16(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->algorithm = (dns_secalg_t)isc_buffer_getuint8(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->original_ttl = (dns_ttl_t)isc_buffer_getuint32(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->expiration = (isc_stdtime_t)isc_buffer_getuint32(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->inception = (isc_stdtime_t)isc_buffer_getuint32(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt siginfo->tag = (dns_keytag_t)isc_buffer_getuint16(&b);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_buffer_remainingregion(&b, &siginfo->signature);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntvalidator_done(dns_validator_t *val, isc_result_t result) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Caller must be holding the lock.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_task_sendanddetach(&task, (isc_event_t **)&val->event);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntfetch_callback_validator(isc_task_t *task, isc_event_t *event) {
acbb301e648b82fcc38b876a44403cf0fe539cc9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_validator");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = get_dst_key(val, val->siginfo, rdataset);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * No matching key.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "fetch_callback_validator: got %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Free stuff from the event.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntfetch_callback_nullkey(isc_task_t *task, isc_event_t *event) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_nullkey");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * No null key.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "found a keyset, no null key");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "found a keyset with a null key");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "insecurity proof succeeded");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt } else if (!dns_rdataset_isassociated(sigrdataset)) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "insecurity proof failed");
acbb301e648b82fcc38b876a44403cf0fe539cc9Evan Hunt * Don't free these, since they'll be
acbb301e648b82fcc38b876a44403cf0fe539cc9Evan Hunt * freed in nullkeyvalidated.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt } else if (devent->result == DNS_R_NCACHENXDOMAIN ||
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "no keys found");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "fetch_callback_nullkey: got %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Free stuff from the event.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntkeyvalidated(isc_task_t *task, isc_event_t *event) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in keyvalidated");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = get_dst_key(val, val->siginfo, rdataset);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * No matching key.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "keyvalidated: got %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * free stuff from the event.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_mem_put(val->view->mctx, devent->rdataset, sizeof(dns_rdataset_t));
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntauthvalidated(isc_task_t *task, isc_event_t *event) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in authvalidated");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "authvalidated: got %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "authvalidated looking for relevant nxt");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt order = dns_name_compare(val->event->name, devent->name);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "invalid type %d",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt if (dns_nxt_typepresent(&rdata, val->event->type)) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "type should not be present");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "nxt bitmask ok");
dbb012765c735ee0d82dedb116cdc7cf18957814Evan Hunt } else if (order > 0) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt order = dns_name_compare(val->event->name, &nextname);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "next name is not greater");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "nxt points to zone apex, ok");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "nxt range ok");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "nxt owner name is not less");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * free stuff from the event.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntnegauthvalidated(isc_task_t *task, isc_event_t *event) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in negauthvalidated");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "negauthvalidated: got %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_mem_put(val->view->mctx, rdataset, sizeof *rdataset);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof found");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * free stuff from the event.
dbb012765c735ee0d82dedb116cdc7cf18957814Evan Hunt isc_mem_put(val->view->mctx, rdataset, sizeof *rdataset);
dbb012765c735ee0d82dedb116cdc7cf18957814Evan Huntnullkeyvalidated(isc_task_t *task, isc_event_t *event) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt validator_log(val, ISC_LOG_DEBUG(3), "in nullkeyvalidated");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "proved that name is in an unsecure domain");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * free stuff from the event.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_mem_put(val->view->mctx, devent->rdataset, sizeof(dns_rdataset_t));
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt isc_mem_put(val->view->mctx, devent->name, sizeof(dns_name_t));
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Try to find a null zone key among those in 'rdataset'. If found, build
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * a dst_key_t for it and point val->key at it.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Huntcontainsnullkey(dns_validator_t *val, dns_rdataset_t *rdataset) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * The key name is unimportant, so we can avoid any name/text
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * conversion.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = dst_key_fromdns(dns_rootname, &b, val->view->mctx,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Try to find a key that could have signed 'siginfo' among those
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * in 'rdataset'. If found, build a dst_key_t for it and point
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * val->key at it.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * If val->key is non-NULL, this returns the next matching key.
dbb012765c735ee0d82dedb116cdc7cf18957814Evan Huntget_dst_key(dns_validator_t *val, dns_siginfo_t *siginfo,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = dst_key_fromdns(&siginfo->signer, &b, val->view->mctx,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * This is the key we're looking for.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt else if (dst_key_compare(oldkey, val->key) == ISC_TRUE)
1b255a0c4eaccf0feff70328a8c108a22abfbf3cEvan Huntget_key(dns_validator_t *val, dns_siginfo_t *siginfo) {
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Is the key name appropriate for this signature?
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt namereln = dns_name_fullcompare(event->name, &siginfo->signer,
dbb012765c735ee0d82dedb116cdc7cf18957814Evan Hunt * We don't want a KEY RR to authenticate
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * itself, so we ignore the signature if it
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * was not made by an ancestor of the KEY.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * The key name is not at the same level
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * as 'rdataset', nor is it closer to the
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Is the key used for the signature a security root?
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = dns_keytable_findkeynode(val->view->secroots,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * The key is a security root.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Do we know about this key?
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = dns_view_simplefind(val->view, &siginfo->signer,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * We have an rrset for the given keyname.
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * We know the key but haven't validated it yet.
1b255a0c4eaccf0feff70328a8c108a22abfbf3cEvan Hunt * Having a pending key with no signature means that
3249da26fc28297265d444a1f3647f1e6700a2a0Evan Hunt * something is broken.
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * The key is legitimately insecure. There's no
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * point in even attempting verification.
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * See if we've got the key used in the signature.
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * Either the key we're looking for is not
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * in the rrset, or something bad happened.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * We don't know anything about this key.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt frdataset = isc_mem_get(val->view->mctx, sizeof *frdataset);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt result = dns_resolver_createfetch(val->view->resolver,
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * This key doesn't exist.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * Attempts positive response validation.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * ISC_R_SUCCESS Validation completed successfully
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * DNS_R_WAIT Validation has started but is waiting
3249da26fc28297265d444a1f3647f1e6700a2a0Evan Hunt * for an event.
3249da26fc28297265d444a1f3647f1e6700a2a0Evan Hunt * Other return codes are possible and all indicate failure.
3249da26fc28297265d444a1f3647f1e6700a2a0Evan Huntvalidate(dns_validator_t *val, isc_boolean_t resume) {
3249da26fc28297265d444a1f3647f1e6700a2a0Evan Hunt * Caller must be holding the validator lock.
12bf5d4796505b4c20680531da96a31e6c2c1144Evan Hunt * We already have a sigrdataset.
1b255a0c4eaccf0feff70328a8c108a22abfbf3cEvan Hunt validator_log(val, ISC_LOG_DEBUG(3), "resuming validate");
80169c379dd4e0a6e164b7cac4bf5fa013c91138Mark Andrews * At this point we could check that the signature algorithm
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * was known and "sufficiently good". For now, any algorithm
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt * is acceptable.
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt continue; /* Try the next SIG RR. */
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "marking as answer");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "verify rdataset: %s",
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt } while (1);
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "failed to verify rdataset");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "marking as secure");
ba751492fcc4f161a18b983d4f018a1a52938cb9Evan Hunt "verify failure: %s",
return (DNS_R_NOVALIDSIG);
static inline isc_result_t
if (!resume) {
if (resume) {
link))
NULL, 0,
val,
return (result);
return (DNS_R_WAIT);
sizeof(dns_rdataset_t));
return (ISC_R_NOMEMORY);
val,
return (result);
return (DNS_R_WAIT);
return (DNS_R_NOVALIDNXT);
return (ISC_R_SUCCESS);
static inline isc_result_t
return (result);
if (!resume)
return (result);
return (DNS_R_NOTINSECURE);
return (ISC_R_SUCCESS);
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *frdataset);
sizeof *fsigrdataset);
return (ISC_R_NOMEMORY);
sizeof *frdataset);
sizeof *fsigrdataset);
sizeof *fname);
return (ISC_R_NOMEMORY);
NULL,
val,
return (DNS_R_WAIT);
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
sizeof *frdataset);
return (ISC_R_NOMEMORY);
return (result);
return (DNS_R_WAIT);
return (result);
INSIST(0);
return (ISC_R_NOMEMORY);
sizeof (dns_validatorevent_t));
goto cleanup_val;
goto cleanup_event;
return (ISC_R_SUCCESS);
return (result);
if (want_destroy)
isc_buffer_t b;
isc_region_t r;
!= ISC_R_SUCCESS)
isc_buffer_clear(&b);
isc_buffer_usedregion(&b, &r);