#include <isc/string.h>
#include <isc/tid.h>
#include <isc/util.h>
+#include <isc/work.h>
#include <dns/client.h>
#include <dns/db.h>
* validator_start -> proveunsecure
*
* \li When called with no rdataset or sigrdataset:
- * validator_start -> validate_nx-> proveunsecure
+ * validator_start -> validate_nx -> proveunsecure
*
* validator_start: determine what type of validation to do.
* validate_answer: attempt to perform a positive validation.
#define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?')
#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
-#define VALATTR_CANCELED 0x0002 /*%< Canceled. */
-#define VALATTR_TRIEDVERIFY \
- 0x0004 /*%< We have found a key and \
- * have attempted a verify. */
-#define VALATTR_COMPLETE 0x0008 /*%< Completion event sent. */
-#define VALATTR_INSECURITY 0x0010 /*%< Attempting proveunsecure. */
-
-/*!
- * NSEC proofs to be looked for.
- */
-#define VALATTR_NEEDNOQNAME 0x00000100
-#define VALATTR_NEEDNOWILDCARD 0x00000200
-#define VALATTR_NEEDNODATA 0x00000400
+enum valattr {
+ VALATTR_CANCELED = 1 << 1, /*%< Canceled. */
+ VALATTR_TRIEDVERIFY = 1 << 2, /*%< We have found a key and have
+ attempted a verify. */
+ VALATTR_COMPLETE = 1 << 3, /*%< Completion event sent. */
+ VALATTR_INSECURITY = 1 << 4, /*%< Attempting proveunsecure. */
+ VALATTR_MAXVALIDATIONS = 1 << 5, /*%< Max validations quota */
+ VALATTR_MAXVALIDATIONFAILS = 1 << 6, /*%< Max validation fails quota */
+
+ /*!
+ * NSEC proofs to be looked for.
+ */
+ VALATTR_NEEDNOQNAME = 1 << 8,
+ VALATTR_NEEDNOWILDCARD = 1 << 9,
+ VALATTR_NEEDNODATA = 1 << 10,
-/*!
- * NSEC proofs that have been found.
- */
-#define VALATTR_FOUNDNOQNAME 0x00001000
-#define VALATTR_FOUNDNOWILDCARD 0x00002000
-#define VALATTR_FOUNDNODATA 0x00004000
-#define VALATTR_FOUNDCLOSEST 0x00008000
-#define VALATTR_FOUNDOPTOUT 0x00010000
-#define VALATTR_FOUNDUNKNOWN 0x00020000
+ /*!
+ * NSEC proofs that have been found.
+ */
+ VALATTR_FOUNDNOQNAME = 1 << 12,
+ VALATTR_FOUNDNOWILDCARD = 1 << 13,
+ VALATTR_FOUNDNODATA = 1 << 14,
+ VALATTR_FOUNDCLOSEST = 1 << 15,
+ VALATTR_FOUNDOPTOUT = 1 << 16,
+ VALATTR_FOUNDUNKNOWN = 1 << 17,
+};
#define NEEDNODATA(val) ((val->attributes & VALATTR_NEEDNODATA) != 0)
#define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0)
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+#define MAXVALIDATIONS(r) (((r)->attributes & VALATTR_MAXVALIDATIONS) != 0)
+#define MAXVALIDATIONFAILS(r) \
+ (((r)->attributes & VALATTR_MAXVALIDATIONFAILS) != 0)
+
static void
destroy_validator(dns_validator_t *val);
static isc_result_t
select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset);
+static void
+resume_answer(void *arg);
+static void
+validate_async_done(dns_validator_t *val, isc_result_t result);
static isc_result_t
-validate_answer(dns_validator_t *val, bool resume);
+validate_async_run(dns_validator_t *val, isc_job_cb cb);
-static isc_result_t
-validate_dnskey(dns_validator_t *val);
+static void
+validate_dnskey(void *arg);
+static void
+validate_dnskey_dsset_done(dns_validator_t *val, isc_result_t result);
static isc_result_t
validate_nx(dns_validator_t *val, bool resume);
val->secure = true;
}
-static void
-validator_done_cb(void *arg) {
- dns_validator_t *val = arg;
- val->cb(val);
- dns_validator_detach(&val);
-}
-
/*
* Validator 'val' is finished; send the completion event to the loop
* that called dns_validator_create(), with result `result`.
- *
- * Caller must be holding the validator lock.
*/
static void
validator_done(dns_validator_t *val, isc_result_t result) {
val->attributes |= VALATTR_COMPLETE;
val->result = result;
- dns_validator_ref(val);
- isc_async_run(val->loop, validator_done_cb, val);
+ isc_async_run(val->loop, val->cb, val);
}
/*%
return (found);
}
+static void
+resume_answer_with_key(void *arg) {
+ dns_validator_t *val = arg;
+ dns_rdataset_t *rdataset = &val->frdataset;
+
+ isc_result_t result = select_signing_key(val, rdataset);
+ if (result == ISC_R_SUCCESS) {
+ val->keyset = &val->frdataset;
+ }
+}
+
+static void
+resume_answer_with_key_done(void *arg) {
+ dns_validator_t *val = arg;
+
+ resume_answer(val);
+}
+
/*%
* We have been asked to look for a key.
* If found, resume the validation process.
dns_rdataset_t *rdataset = &val->frdataset;
isc_result_t eresult = resp->result;
isc_result_t result;
- isc_result_t saved_result;
- dns_fetch_t *fetch = NULL;
INSIST(resp->type == FETCHDONE);
if (dns_rdataset_isassociated(&val->fsigrdataset)) {
dns_rdataset_disassociate(&val->fsigrdataset);
}
- isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_dnskey");
- fetch = val->fetch;
- val->fetch = NULL;
+ dns_resolver_destroyfetch(&val->fetch);
+
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- } else if (eresult == ISC_R_SUCCESS || eresult == DNS_R_NCACHENXRRSET) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ switch (eresult) {
+ case ISC_R_SUCCESS:
+ case DNS_R_NCACHENXRRSET:
/*
* We have an answer to our DNSKEY query. Either the DNSKEY
* RRset or a NODATA response.
if (eresult == ISC_R_SUCCESS &&
rdataset->trust >= dns_trust_secure)
{
- result = select_signing_key(val, rdataset);
- if (result == ISC_R_SUCCESS) {
- val->keyset = &val->frdataset;
- }
- }
- result = validate_answer(val, true);
- if (result == DNS_R_NOVALIDSIG &&
- (val->attributes & VALATTR_TRIEDVERIFY) == 0)
- {
- saved_result = result;
- validator_log(val, ISC_LOG_DEBUG(3),
- "falling back to insecurity proof");
- result = proveunsecure(val, false, false);
- if (result == DNS_R_NOTINSECURE) {
- result = saved_result;
- }
- }
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
+ isc_work_enqueue(val->loop, resume_answer_with_key,
+ resume_answer, val);
+ result = DNS_R_WAIT;
+ } else {
+ result = validate_async_run(val, resume_answer);
}
- } else {
+ break;
+ default:
validator_log(val, ISC_LOG_DEBUG(3),
"fetch_callback_dnskey: got %s",
isc_result_totext(eresult));
- if (eresult == ISC_R_CANCELED) {
- validator_done(val, eresult);
- } else {
- validator_done(val, DNS_R_BROKENCHAIN);
- }
- }
-
- if (fetch != NULL) {
- dns_resolver_destroyfetch(&fetch);
+ result = DNS_R_BROKENCHAIN;
}
+cleanup:
+ isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
+ validate_async_done(val, result);
dns_validator_detach(&val);
}
dns_rdataset_t *rdataset = &val->frdataset;
isc_result_t eresult = resp->result;
isc_result_t result;
- dns_fetch_t *fetch = NULL;
bool trustchain;
INSIST(resp->type == FETCHDONE);
}
validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_ds");
- fetch = val->fetch;
- val->fetch = NULL;
+ dns_resolver_destroyfetch(&val->fetch);
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- goto done;
+ result = ISC_R_CANCELED;
+ goto cleanup;
}
- switch (eresult) {
- case DNS_R_NXDOMAIN:
- case DNS_R_NCACHENXDOMAIN:
- /*
- * These results only make sense if we're attempting
- * an insecurity proof, not when walking a chain of trust.
- */
- if (trustchain) {
- goto unexpected;
- }
-
- FALLTHROUGH;
- case ISC_R_SUCCESS:
- if (trustchain) {
+ if (trustchain) {
+ switch (eresult) {
+ case ISC_R_SUCCESS:
/*
* We looked for a DS record as part of
* following a key chain upwards; resume following
"dsset with trust %s",
dns_trust_totext(rdataset->trust));
val->dsset = &val->frdataset;
- result = validate_dnskey(val);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
- } else {
- /*
- * There is a DS which may or may not be a zone cut.
- * In either case we are still in a secure zone,
- * so keep looking for the break in the chain
- * of trust.
- */
- result = proveunsecure(val, (eresult == ISC_R_SUCCESS),
- true);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
- }
- break;
- case DNS_R_CNAME:
- case DNS_R_NXRRSET:
- case DNS_R_NCACHENXRRSET:
- case DNS_R_SERVFAIL: /* RFC 1034 parent? */
- if (trustchain) {
+ result = validate_async_run(val, validate_dnskey);
+ break;
+ case DNS_R_CNAME:
+ case DNS_R_NXRRSET:
+ case DNS_R_NCACHENXRRSET:
+ case DNS_R_SERVFAIL: /* RFC 1034 parent? */
/*
* Failed to find a DS while following the
* chain of trust; now we need to prove insecurity.
"falling back to insecurity proof (%s)",
isc_result_totext(eresult));
result = proveunsecure(val, false, false);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
- } else if (eresult == DNS_R_SERVFAIL) {
- goto unexpected;
- } else if (eresult != DNS_R_CNAME &&
- isdelegation(resp->foundname, &val->frdataset,
- eresult))
- {
+ break;
+ default:
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "fetch_callback_ds: got %s",
+ isc_result_totext(eresult));
+ result = DNS_R_BROKENCHAIN;
+ break;
+ }
+ } else {
+ switch (eresult) {
+ case DNS_R_NXDOMAIN:
+ case DNS_R_NCACHENXDOMAIN:
/*
- * Failed to find a DS while trying to prove
- * insecurity. If this is a zone cut, that
- * means we're insecure.
+ * These results only make sense if we're attempting
+ * an insecurity proof, not when walking a chain of
+ * trust.
*/
- result = markanswer(val, "fetch_callback_ds",
- "no DS and this is a delegation");
- validator_done(val, result);
- } else {
+
+ result = proveunsecure(val, false, true);
+ break;
+ case ISC_R_SUCCESS:
+ /*
+ * There is a DS which may or may not be a zone cut.
+ * In either case we are still in a secure zone,
+ * so keep looking for the break in the chain
+ * of trust.
+ */
+ result = proveunsecure(val, true, true);
+ break;
+ case DNS_R_NXRRSET:
+ case DNS_R_NCACHENXRRSET:
+ if (isdelegation(resp->foundname, &val->frdataset,
+ eresult))
+ {
+ /*
+ * Failed to find a DS while trying to prove
+ * insecurity. If this is a zone cut, that
+ * means we're insecure.
+ */
+ result = markanswer(
+ val, "fetch_callback_ds",
+ "no DS and this is a delegation");
+ break;
+ }
+ FALLTHROUGH;
+ case DNS_R_CNAME:
/*
* Not a zone cut, so we have to keep looking for
* the break point in the chain of trust.
*/
result = proveunsecure(val, false, true);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
- }
- break;
-
- default:
- unexpected:
- validator_log(val, ISC_LOG_DEBUG(3),
- "fetch_callback_ds: got %s",
- isc_result_totext(eresult));
- if (eresult == ISC_R_CANCELED) {
- validator_done(val, eresult);
- } else {
- validator_done(val, DNS_R_BROKENCHAIN);
+ break;
+ default:
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "fetch_callback_ds: got %s",
+ isc_result_totext(eresult));
+ result = DNS_R_BROKENCHAIN;
}
}
-done:
+cleanup:
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
-
- if (fetch != NULL) {
- dns_resolver_destroyfetch(&fetch);
- }
-
+ validate_async_done(val, result);
dns_validator_detach(&val);
}
validator_callback_dnskey(void *arg) {
dns_validator_t *subvalidator = (dns_validator_t *)arg;
dns_validator_t *val = subvalidator->parent;
- isc_result_t result;
- isc_result_t eresult = subvalidator->result;
- isc_result_t saved_result;
+ isc_result_t result = subvalidator->result;
val->subvalidator = NULL;
- subvalidator->parent = NULL;
- validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_dnskey");
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- } else if (eresult == ISC_R_SUCCESS) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_dnskey");
+ if (result == ISC_R_SUCCESS) {
validator_log(val, ISC_LOG_DEBUG(3), "keyset with trust %s",
dns_trust_totext(val->frdataset.trust));
/*
* Only extract the dst key if the keyset is secure.
*/
if (val->frdataset.trust >= dns_trust_secure) {
- (void)select_signing_key(val, &val->frdataset);
- }
- result = validate_answer(val, true);
- if (result == DNS_R_NOVALIDSIG &&
- (val->attributes & VALATTR_TRIEDVERIFY) == 0)
- {
- saved_result = result;
- validator_log(val, ISC_LOG_DEBUG(3),
- "falling back to insecurity proof");
- result = proveunsecure(val, false, false);
- if (result == DNS_R_NOTINSECURE) {
- result = saved_result;
- }
- }
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
+ isc_work_enqueue(val->loop, resume_answer_with_key,
+ resume_answer_with_key_done, val);
+ result = DNS_R_WAIT;
+ } else {
+ result = validate_async_run(val, resume_answer);
}
} else {
- if (eresult != DNS_R_BROKENCHAIN) {
+ if (result != DNS_R_BROKENCHAIN) {
expire_rdatasets(val);
}
validator_log(val, ISC_LOG_DEBUG(3),
"validator_callback_dnskey: got %s",
- isc_result_totext(eresult));
- validator_done(val, DNS_R_BROKENCHAIN);
+ isc_result_totext(result));
+ result = DNS_R_BROKENCHAIN;
}
+cleanup:
+ dns_validator_detach(&subvalidator->parent);
dns_validator_destroy(&subvalidator);
- dns_validator_detach(&val);
+ validate_async_done(val, result);
}
/*%
isc_result_t eresult = subvalidator->result;
val->subvalidator = NULL;
- subvalidator->parent = NULL;
- validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_ds");
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- } else if (eresult == ISC_R_SUCCESS) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_ds");
+ if (eresult == ISC_R_SUCCESS) {
bool have_dsset;
dns_name_t *name;
validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s",
} else if ((val->attributes & VALATTR_INSECURITY) != 0) {
result = proveunsecure(val, have_dsset, true);
} else {
- result = validate_dnskey(val);
- }
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
+ result = validate_async_run(val, validate_dnskey);
}
} else {
if (eresult != DNS_R_BROKENCHAIN) {
validator_log(val, ISC_LOG_DEBUG(3),
"validator_callback_ds: got %s",
isc_result_totext(eresult));
- validator_done(val, DNS_R_BROKENCHAIN);
+ result = DNS_R_BROKENCHAIN;
}
+cleanup:
+ dns_validator_detach(&subvalidator->parent);
dns_validator_destroy(&subvalidator);
- dns_validator_detach(&val);
+ validate_async_done(val, result);
}
/*%
val->subvalidator = NULL;
- validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_cname");
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- } else if (eresult == ISC_R_SUCCESS) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_cname");
+ if (eresult == ISC_R_SUCCESS) {
validator_log(val, ISC_LOG_DEBUG(3), "cname with trust %s",
dns_trust_totext(val->frdataset.trust));
result = proveunsecure(val, false, true);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
} else {
if (eresult != DNS_R_BROKENCHAIN) {
expire_rdatasets(val);
validator_log(val, ISC_LOG_DEBUG(3),
"validator_callback_cname: got %s",
isc_result_totext(eresult));
- validator_done(val, DNS_R_BROKENCHAIN);
+ result = DNS_R_BROKENCHAIN;
}
+cleanup:
+ dns_validator_detach(&subvalidator->parent);
dns_validator_destroy(&subvalidator);
- dns_validator_detach(&val);
+ validate_async_done(val, result);
}
/*%
dns_validator_t *subvalidator = (dns_validator_t *)arg;
dns_validator_t *val = subvalidator->parent;
dns_rdataset_t *rdataset = subvalidator->rdataset;
- isc_result_t result = subvalidator->result;
+ isc_result_t result;
+ isc_result_t eresult = subvalidator->result;
bool exists, data;
val->subvalidator = NULL;
- validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_nsec");
if (CANCELED(val)) {
- validator_done(val, ISC_R_CANCELED);
- } else if (result != ISC_R_SUCCESS) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "validator_callback_nsec: got %s",
- isc_result_totext(result));
- if (result == DNS_R_BROKENCHAIN) {
- val->authfail++;
- }
- if (result == ISC_R_CANCELED) {
- validator_done(val, result);
- } else {
- result = validate_nx(val, true);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
- }
- } else {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_nsec");
+ if (eresult == ISC_R_SUCCESS) {
dns_name_t **proofs = val->proofs;
dns_name_t *wild = dns_fixedname_name(&val->wild);
}
result = validate_nx(val, true);
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
+ } else {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "validator_callback_nsec: got %s",
+ isc_result_totext(eresult));
+ switch (eresult) {
+ case ISC_R_CANCELED:
+ case ISC_R_SHUTTINGDOWN:
+ result = eresult;
+ break;
+ case DNS_R_BROKENCHAIN:
+ val->authfail++;
+ FALLTHROUGH;
+ default:
+ result = validate_nx(val, true);
}
}
+cleanup:
+ dns_validator_detach(&subvalidator->parent);
dns_validator_destroy(&subvalidator);
- dns_validator_detach(&val);
+ validate_async_done(val, result);
}
/*%
validator_logcreate(val, name, type, caller, "fetch");
dns_validator_ref(val);
-
result = dns_resolver_createfetch(
val->view->resolver, name, type, NULL, NULL, NULL, NULL, 0,
fopts, 0, NULL, val->loop, callback, val, &val->frdataset,
(DNS_VALIDATOR_NOCDFLAG | DNS_VALIDATOR_NONTA));
validator_logcreate(val, name, type, caller, "validator");
- result = dns_validator_create(val->view, name, type, rdataset, sig,
- NULL, vopts, val->loop, cb, val,
- &val->subvalidator);
+ result = dns_validator_create(
+ val->view, name, type, rdataset, sig, NULL, vopts, val->loop,
+ cb, val, val->nvalidations, val->nfails, &val->subvalidator);
if (result == ISC_R_SUCCESS) {
dns_validator_attach(val, &val->subvalidator->parent);
val->subvalidator->depth = val->depth + 1;
isc_buffer_t b;
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_key_t *oldkey = val->key;
- bool foundold;
+ bool no_rdata = false;
if (oldkey == NULL) {
- foundold = true;
+ result = dns_rdataset_first(rdataset);
} else {
- foundold = false;
+ dst_key_free(&oldkey);
val->key = NULL;
+ result = dns_rdataset_next(rdataset);
}
-
- result = dns_rdataset_first(rdataset);
if (result != ISC_R_SUCCESS) {
- goto failure;
+ goto done;
}
+
do {
dns_rdataset_current(rdataset, &rdata);
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
INSIST(val->key == NULL);
- result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b,
- val->view->mctx, &val->key);
+ result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b,
+ val->view->mctx, no_rdata,
+ &val->key);
if (result == ISC_R_SUCCESS) {
if (siginfo->algorithm ==
(dns_secalg_t)dst_key_alg(val->key) &&
siginfo->keyid ==
(dns_keytag_t)dst_key_id(val->key) &&
+ (dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) ==
+ 0 &&
dst_key_iszonekey(val->key))
{
- if (foundold) {
- /*
- * This is the key we're looking for.
- */
- return (ISC_R_SUCCESS);
- } else if (dst_key_compare(oldkey, val->key)) {
- foundold = true;
- dst_key_free(&oldkey);
+ if (no_rdata) {
+ /* Retry with full key */
+ dns_rdata_reset(&rdata);
+ dst_key_free(&val->key);
+ no_rdata = false;
+ continue;
}
+ /* This is the key we're looking for. */
+ goto done;
}
dst_key_free(&val->key);
}
dns_rdata_reset(&rdata);
result = dns_rdataset_next(rdataset);
+ no_rdata = true;
} while (result == ISC_R_SUCCESS);
+done:
if (result == ISC_R_NOMORE) {
result = ISC_R_NOTFOUND;
}
-failure:
- if (oldkey != NULL) {
- dst_key_free(&oldkey);
- }
-
return (result);
}
validator_log(val, ISC_LOG_DEBUG(3),
"keyset with trust %s",
dns_trust_totext(val->frdataset.trust));
- result = select_signing_key(val, val->keyset);
- if (result != ISC_R_SUCCESS) {
- /*
- * Either the key we're looking for is not
- * in the rrset, or something bad happened.
- * Give up.
- */
- result = DNS_R_CONTINUE;
+
+ /*
+ * Cleanup before passing control to the offload thread
+ */
+ if (dns_rdataset_isassociated(&val->frdataset) &&
+ val->keyset != &val->frdataset)
+ {
+ dns_rdataset_disassociate(&val->frdataset);
+ }
+ if (dns_rdataset_isassociated(&val->fsigrdataset)) {
+ dns_rdataset_disassociate(&val->fsigrdataset);
}
+
+ isc_work_enqueue(val->loop, resume_answer_with_key,
+ resume_answer_with_key_done, val);
+ return (DNS_R_WAIT);
}
break;
return (dst_region_computeid(&r));
}
+static bool
+over_max_validations(dns_validator_t *val) {
+ if (val->nvalidations == NULL) {
+ return (false);
+ }
+ if (*val->nvalidations > 0) {
+ (*val->nvalidations)--;
+ return (false);
+ }
+
+ val->attributes |= VALATTR_MAXVALIDATIONS;
+ return (true);
+}
+
+static bool
+over_max_fails(dns_validator_t *val) {
+ if (val->nfails == NULL) {
+ return (false);
+ }
+ if (*val->nfails > 0) {
+ (*val->nfails)--;
+ return (false);
+ }
+
+ val->attributes |= VALATTR_MAXVALIDATIONFAILS;
+ return (true);
+}
+
/*%
* Is the DNSKEY rrset in val->rdataset self-signed?
*/
-static bool
+static isc_result_t
selfsigned_dnskey(dns_validator_t *val) {
dns_rdataset_t *rdataset = val->rdataset;
dns_rdataset_t *sigrdataset = val->sigrdataset;
dns_name_t *name = val->name;
isc_result_t result;
isc_mem_t *mctx = val->view->mctx;
- bool answer = false;
if (rdataset->type != dns_rdatatype_dnskey) {
- return (false);
+ return (DNS_R_NOKEYMATCH);
}
for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
* This will be verified later.
*/
if ((key.flags & DNS_KEYFLAG_REVOKE) == 0) {
- answer = true;
- continue;
+ return (ISC_R_SUCCESS);
}
result = dns_dnssec_keyfromrdata(name, &keyrdata, mctx,
if (DNS_TRUST_PENDING(rdataset->trust) &&
dns_view_istrusted(val->view, name, &key))
{
+ if (over_max_validations(val)) {
+ dst_key_free(&dstkey);
+ return (ISC_R_QUOTA);
+ }
result = dns_dnssec_verify(
name, rdataset, dstkey, true,
val->view->maxbits, mctx, &sigrdata,
* good.
*/
dns_view_untrust(val->view, name, &key);
+ } else if (over_max_fails(val)) {
+ dst_key_free(&dstkey);
+ return (ISC_R_QUOTA);
}
} else if (rdataset->trust >= dns_trust_secure) {
/*
}
}
- return (answer);
+ return (DNS_R_NOKEYMATCH);
}
/*%
val->attributes |= VALATTR_TRIEDVERIFY;
wild = dns_fixedname_initname(&fixed);
again:
+ if (over_max_validations(val)) {
+ return (ISC_R_QUOTA);
+ }
result = dns_dnssec_verify(val->name, val->rdataset, key, ignore,
val->view->maxbits, val->view->mctx, rdata,
wild);
}
result = ISC_R_SUCCESS;
}
+
+ if (result != ISC_R_SUCCESS && over_max_fails(val)) {
+ result = ISC_R_QUOTA;
+ }
return (result);
}
* for an event.
* \li Other return codes are possible and all indicate failure.
*/
-static isc_result_t
-validate_answer(dns_validator_t *val, bool resume) {
- isc_result_t result, vresult = DNS_R_NOVALIDSIG;
- dns_rdata_t rdata = DNS_RDATA_INIT;
+
+static void
+validate_answer_iter_next(void *arg);
+static void
+validate_answer_process(void *arg);
+static void
+validate_answer_iter_done(dns_validator_t *val, isc_result_t result);
+
+static void
+validate_answer_iter_start(dns_validator_t *val) {
+ isc_result_t result = ISC_R_SUCCESS;
/*
* Caller must be holding the validator lock.
*/
- if (resume) {
- /*
- * We already have a sigrdataset.
- */
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ if (val->resume) {
+ /* We already have a sigrdataset. */
result = ISC_R_SUCCESS;
validator_log(val, ISC_LOG_DEBUG(3), "resuming validate");
} else {
result = dns_rdataset_first(val->sigrdataset);
}
- for (; result == ISC_R_SUCCESS;
- result = dns_rdataset_next(val->sigrdataset))
- {
- dns_rdata_reset(&rdata);
- dns_rdataset_current(val->sigrdataset, &rdata);
- if (val->siginfo == NULL) {
- val->siginfo = isc_mem_get(val->view->mctx,
- sizeof(*val->siginfo));
- }
- result = dns_rdata_tostruct(&rdata, val->siginfo, NULL);
- if (result != ISC_R_SUCCESS) {
- return (result);
- }
+cleanup:
+ if (result != ISC_R_SUCCESS) {
+ validate_answer_iter_done(val, result);
+ return;
+ }
- /*
- * At this point we could check that the signature algorithm
- * was known and "sufficiently good".
- */
- if (!dns_resolver_algorithm_supported(val->view->resolver,
- val->name,
- val->siginfo->algorithm))
- {
- resume = false;
- continue;
- }
+ result = validate_async_run(val, validate_answer_process);
+ INSIST(result == DNS_R_WAIT);
+}
- if (!resume) {
- result = seek_dnskey(val);
- if (result == DNS_R_CONTINUE) {
- continue; /* Try the next SIG RR. */
- }
- if (result != ISC_R_SUCCESS) {
- return (result);
- }
- }
+static void
+validate_answer_iter_next(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result;
- /*
- * There isn't a secure DNSKEY for this signature so move
- * onto the next RRSIG.
- */
- if (val->key == NULL) {
- resume = false;
- continue;
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ val->resume = false;
+ result = dns_rdataset_next(val->sigrdataset);
+
+cleanup:
+ if (result != ISC_R_SUCCESS) {
+ validate_answer_iter_done(val, result);
+ return;
+ }
+
+ (void)validate_async_run(val, validate_answer_process);
+}
+
+static void
+validate_answer_finish(void *arg);
+
+static void
+validate_answer_signing_key(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result = ISC_R_NOTFOUND;
+
+ if (CANCELED(val)) {
+ val->result = ISC_R_CANCELED;
+ } else {
+ val->result = verify(val, val->key, &val->rdata,
+ val->siginfo->keyid);
+ }
+
+ switch (val->result) {
+ case ISC_R_CANCELED: /* Validation was canceled */
+ case ISC_R_SHUTTINGDOWN: /* Server shutting down */
+ case ISC_R_QUOTA: /* Validation fails quota reached */
+ case ISC_R_SUCCESS: /* We found our valid signature, we are done! */
+ if (val->key != NULL) {
+ dst_key_free(&val->key);
+ val->key = NULL;
}
- do {
- isc_result_t tresult;
- vresult = verify(val, val->key, &rdata,
- val->siginfo->keyid);
- if (vresult == ISC_R_SUCCESS) {
- break;
- }
+ break;
+ default:
+ /* Select next signing key */
+ result = select_signing_key(val, val->keyset);
+ break;
+ }
- tresult = select_signing_key(val, val->keyset);
- if (tresult != ISC_R_SUCCESS) {
- break;
- }
- } while (1);
- if (vresult != ISC_R_SUCCESS) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "failed to verify rdataset");
- } else {
- dns_rdataset_trimttl(val->rdataset, val->sigrdataset,
- val->siginfo, val->start,
- val->view->acceptexpired);
+ if (result == ISC_R_SUCCESS) {
+ INSIST(val->key != NULL);
+ } else {
+ INSIST(val->key == NULL);
+ }
+}
+
+static void
+validate_answer_signing_key_done(void *arg) {
+ dns_validator_t *val = arg;
+
+ if (CANCELED(val)) {
+ val->result = ISC_R_CANCELED;
+ } else if (val->key != NULL) {
+ /* Process with next key if we selected one */
+ isc_work_enqueue(val->loop, validate_answer_signing_key,
+ validate_answer_signing_key_done, val);
+ return;
+ }
+
+ validate_answer_finish(val);
+}
+
+static void
+validate_answer_process(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result;
+
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ dns_rdata_reset(&val->rdata);
+
+ dns_rdataset_current(val->sigrdataset, &val->rdata);
+ if (val->siginfo == NULL) {
+ val->siginfo = isc_mem_get(val->view->mctx,
+ sizeof(*val->siginfo));
+ }
+ result = dns_rdata_tostruct(&val->rdata, val->siginfo, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
+ /*
+ * At this point we could check that the signature algorithm
+ * was known and "sufficiently good".
+ */
+ if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
+ val->siginfo->algorithm))
+ {
+ goto next_key;
+ }
+
+ if (!val->resume) {
+ result = seek_dnskey(val);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ break;
+ case DNS_R_CONTINUE:
+ goto next_key;
+ case DNS_R_WAIT:
+ goto cleanup;
+ default:
+ goto cleanup;
}
+ }
+
+ /*
+ * There isn't a secure DNSKEY for this signature so move
+ * onto the next RRSIG.
+ */
+ if (val->key == NULL) {
+ val->resume = false;
+ goto next_key;
+ }
+
+ isc_work_enqueue(val->loop, validate_answer_signing_key,
+ validate_answer_signing_key_done, val);
+ return;
+
+next_key:
+ result = validate_async_run(val, validate_answer_iter_next);
+ goto cleanup;
+
+cleanup:
+ validate_async_done(val, result);
+}
+
+static void
+validate_answer_finish(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result = ISC_R_UNSET;
+
+ if (val->result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failed to verify rdataset: %s",
+ isc_result_totext(val->result));
+ } else {
+ dns_rdataset_trimttl(val->rdataset, val->sigrdataset,
+ val->siginfo, val->start,
+ val->view->acceptexpired);
+ }
- if (val->key != NULL) {
- dst_key_free(&val->key);
- }
- if (val->keyset != NULL) {
- dns_rdataset_disassociate(val->keyset);
- val->keyset = NULL;
- }
+ if (val->key != NULL) {
+ dst_key_free(&val->key);
val->key = NULL;
- if (NEEDNOQNAME(val)) {
- if (val->message == NULL) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "no message available "
- "for noqname proof");
- return (DNS_R_NOVALIDSIG);
- }
+ }
+ if (val->keyset != NULL) {
+ dns_rdataset_disassociate(val->keyset);
+ val->keyset = NULL;
+ }
+
+ switch (val->result) {
+ case ISC_R_CANCELED:
+ /* The validation was canceled */
+ validator_log(val, ISC_LOG_DEBUG(3), "validation was canceled");
+ validate_async_done(val, val->result);
+ return;
+ case ISC_R_SHUTTINGDOWN:
+ validator_log(val, ISC_LOG_DEBUG(3), "server is shutting down");
+ validate_async_done(val, val->result);
+ return;
+ case ISC_R_QUOTA:
+ if (MAXVALIDATIONS(val)) {
validator_log(val, ISC_LOG_DEBUG(3),
- "looking for noqname proof");
- return (validate_nx(val, false));
- } else if (vresult == ISC_R_SUCCESS) {
- marksecure(val);
+ "maximum number of validations exceeded");
+ } else if (MAXVALIDATIONFAILS(val)) {
validator_log(val, ISC_LOG_DEBUG(3),
- "marking as secure, "
- "noqname proof not needed");
- return (ISC_R_SUCCESS);
+ "maximum number of validation failures "
+ "exceeded");
} else {
+ validator_log(
+ val, ISC_LOG_DEBUG(3),
+ "unknown error: validation quota exceeded");
+ }
+ validate_async_done(val, val->result);
+ return;
+ default:
+ break;
+ }
+
+ if (NEEDNOQNAME(val)) {
+ if (val->message == NULL) {
validator_log(val, ISC_LOG_DEBUG(3),
- "verify failure: %s",
- isc_result_totext(result));
- resume = false;
+ "no message available for noqname proof");
+ validate_async_done(val, DNS_R_NOVALIDSIG);
+ return;
}
+
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "looking for noqname proof");
+ result = validate_nx(val, false);
+ validate_async_done(val, result);
+ return;
+ }
+
+ if (val->result == ISC_R_SUCCESS) {
+ marksecure(val);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "marking as secure, noqname proof not needed");
+ validate_async_done(val, val->result);
+ return;
}
+
+ validator_log(val, ISC_LOG_DEBUG(3), "verify failure: %s",
+ isc_result_totext(val->result));
+ (void)validate_async_run(val, validate_answer_iter_next);
+}
+
+static void
+validate_answer_iter_done(dns_validator_t *val, isc_result_t result) {
if (result != ISC_R_NOMORE) {
validator_log(val, ISC_LOG_DEBUG(3),
"failed to iterate signatures: %s",
isc_result_totext(result));
- return (result);
+ validate_async_done(val, result);
+ return;
}
validator_log(val, ISC_LOG_INFO, "no valid signature found");
- return (vresult);
+ validate_async_done(val, val->result);
+}
+
+static void
+resume_answer(void *arg) {
+ dns_validator_t *val = arg;
+ val->resume = true;
+ validate_answer_iter_start(val);
+}
+
+static void
+validate_answer(void *arg) {
+ dns_validator_t *val = arg;
+ val->resume = false;
+ validate_answer_iter_start(val);
+}
+
+static isc_result_t
+validate_async_run(dns_validator_t *val, isc_job_cb cb) {
+ isc_async_run(val->loop, cb, val);
+ return (DNS_R_WAIT);
+}
+
+static void
+validate_async_done(dns_validator_t *val, isc_result_t result) {
+ if (result == DNS_R_NOVALIDSIG &&
+ (val->attributes & VALATTR_TRIEDVERIFY) == 0)
+ {
+ isc_result_t saved_result = result;
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "falling back to insecurity proof");
+ result = proveunsecure(val, false, false);
+ if (result == DNS_R_NOTINSECURE) {
+ result = saved_result;
+ }
+ }
+
+ if (result != DNS_R_WAIT) {
+ /* We are still continuing */
+ validator_done(val, result);
+ dns_validator_detach(&val);
+ }
}
/*%
}
}
result = verify(val, dstkey, &rdata, sig.keyid);
- if (result == ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS || result == ISC_R_QUOTA) {
break;
}
}
return (DNS_R_CONTINUE);
}
-/*%
- * Attempts positive response validation of an RRset containing zone keys
- * (i.e. a DNSKEY rrset).
- *
- * Caller must be holding the validator lock.
- *
- * Returns:
- * \li ISC_R_SUCCESS Validation completed successfully
- * \li DNS_R_WAIT Validation has started but is waiting
- * for an event.
- * \li Other return codes are possible and all indicate failure.
- */
+static void
+validate_dnskey_dsset_done(dns_validator_t *val, isc_result_t result) {
+ if (result == ISC_R_SUCCESS) {
+ marksecure(val);
+ validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)");
+ } else if (result == ISC_R_NOMORE && !val->supported_algorithm) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/digest (DS)");
+ result = markanswer(val, "validate_dnskey (3)",
+ "no supported algorithm/digest (DS)");
+ } else {
+ validator_log(val, ISC_LOG_INFO,
+ "no valid signature found (DS)");
+ result = DNS_R_NOVALIDSIG;
+ }
+
+ if (val->dsset == &val->fdsset) {
+ val->dsset = NULL;
+ dns_rdataset_disassociate(&val->fdsset);
+ }
+
+ validate_async_done(val, result);
+}
+
static isc_result_t
-validate_dnskey(dns_validator_t *val) {
- isc_result_t result;
+validate_dnskey_dsset(dns_validator_t *val) {
dns_rdata_t dsrdata = DNS_RDATA_INIT;
dns_rdata_t keyrdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ dns_rdata_ds_t ds;
+
+ dns_rdata_reset(&dsrdata);
+ dns_rdataset_current(val->dsset, &dsrdata);
+ result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ if (ds.digest_type == DNS_DSDIGEST_SHA1 && val->digest_sha1 == false) {
+ return (DNS_R_BADALG);
+ }
+
+ if (!dns_resolver_ds_digest_supported(val->view->resolver, val->name,
+ ds.digest_type))
+ {
+ return (DNS_R_BADALG);
+ }
+
+ if (!dns_resolver_algorithm_supported(val->view->resolver, val->name,
+ ds.algorithm))
+ {
+ return (DNS_R_BADALG);
+ }
+
+ val->supported_algorithm = true;
+
+ /*
+ * Find the DNSKEY matching the DS...
+ */
+ result = dns_dnssec_matchdskey(val->name, &dsrdata, val->rdataset,
+ &keyrdata);
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3), "no DNSKEY matching DS");
+ return (DNS_R_NOKEYMATCH);
+ }
+
+ /*
+ * ... and check that it signed the DNSKEY RRset.
+ */
+ result = check_signer(val, &keyrdata, ds.key_tag, ds.algorithm);
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "no RRSIG matching DS key");
+
+ return (result);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+validate_dnskey_dsset_next(void *arg) {
+ dns_validator_t *val = arg;
+
+ if (CANCELED(val)) {
+ val->result = ISC_R_CANCELED;
+ } else {
+ val->result = dns_rdataset_next(val->dsset);
+ }
+
+ if (val->result == ISC_R_SUCCESS) {
+ /* continue async run */
+ val->result = validate_dnskey_dsset(val);
+ }
+}
+
+static void
+validate_dnskey_dsset_next_done(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result = val->result;
+
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ }
+
+ switch (result) {
+ case ISC_R_CANCELED:
+ case ISC_R_SHUTTINGDOWN:
+ /* Abort, abort, abort! */
+ break;
+ case ISC_R_SUCCESS:
+ case ISC_R_NOMORE:
+ /* We are done */
+ break;
+ default:
+ /* Continue validation until we have success or no more data */
+ isc_work_enqueue(val->loop, validate_dnskey_dsset_next,
+ validate_dnskey_dsset_next_done, val);
+ return;
+ }
+
+ validate_dnskey_dsset_done(val, result);
+ return;
+}
+
+static void
+validate_dnskey_dsset_first(dns_validator_t *val) {
+ isc_result_t result;
+
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ } else {
+ result = dns_rdataset_first(val->dsset);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ /* continue async run */
+ result = validate_dnskey_dsset(val);
+ if (result != ISC_R_SUCCESS) {
+ isc_work_enqueue(val->loop, validate_dnskey_dsset_next,
+ validate_dnskey_dsset_next_done, val);
+ return;
+ }
+ }
+
+ validate_dnskey_dsset_done(val, result);
+}
+
+static void
+validate_dnskey(void *arg) {
+ dns_validator_t *val = arg;
+ isc_result_t result = ISC_R_SUCCESS;
dns_keynode_t *keynode = NULL;
dns_rdata_ds_t ds;
- bool supported_algorithm;
- char digest_types[256];
+
+ if (CANCELED(val)) {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
/*
* If we don't already have a DS RRset, check to see if there's
* verification.
*/
- supported_algorithm = false;
+ val->supported_algorithm = false;
/*
* If DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present we
* practice means that we need to ignore DNS_DSDIGEST_SHA1 if a
* DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present.
*/
- memset(digest_types, 1, sizeof(digest_types));
+ val->digest_sha1 = true;
+ dns_rdata_t dsrdata = DNS_RDATA_INIT;
for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS;
result = dns_rdataset_next(val->dsset))
{
(ds.digest_type == DNS_DSDIGEST_SHA384 &&
ds.length == ISC_SHA384_DIGESTLENGTH))
{
- digest_types[DNS_DSDIGEST_SHA1] = 0;
- break;
- }
- }
-
- for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS;
- result = dns_rdataset_next(val->dsset))
- {
- dns_rdata_reset(&dsrdata);
- dns_rdataset_current(val->dsset, &dsrdata);
- result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
-
- if (digest_types[ds.digest_type] == 0) {
- continue;
- }
-
- if (!dns_resolver_ds_digest_supported(
- val->view->resolver, val->name, ds.digest_type))
- {
- continue;
- }
-
- if (!dns_resolver_algorithm_supported(val->view->resolver,
- val->name, ds.algorithm))
- {
- continue;
- }
-
- supported_algorithm = true;
-
- /*
- * Find the DNSKEY matching the DS...
- */
- result = dns_dnssec_matchdskey(val->name, &dsrdata,
- val->rdataset, &keyrdata);
- if (result != ISC_R_SUCCESS) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "no DNSKEY matching DS");
- continue;
- }
-
- /*
- * ... and check that it signed the DNSKEY RRset.
- */
- result = check_signer(val, &keyrdata, ds.key_tag, ds.algorithm);
- if (result == ISC_R_SUCCESS) {
+ val->digest_sha1 = false;
break;
}
- validator_log(val, ISC_LOG_DEBUG(3),
- "no RRSIG matching DS key");
}
- if (result == ISC_R_SUCCESS) {
- marksecure(val);
- validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)");
- } else if (result == ISC_R_NOMORE && !supported_algorithm) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "no supported algorithm/digest (DS)");
- result = markanswer(val, "validate_dnskey (3)",
- "no supported algorithm/digest (DS)");
- } else {
- validator_log(val, ISC_LOG_INFO,
- "no valid signature found (DS)");
- result = DNS_R_NOVALIDSIG;
- }
+ validate_dnskey_dsset_first(val);
+ return;
cleanup:
if (val->dsset == &val->fdsset) {
val->dsset = NULL;
dns_rdataset_disassociate(&val->fdsset);
}
-
- return (result);
+ validate_async_done(val, result);
}
/*%
return (DNS_R_BROKENCHAIN);
}
- validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) not found");
return (proveunsecure(val, false, false));
}
*/
if (val->frdataset.trust >= dns_trust_secure) {
if (!check_ds_algs(val, tname, &val->frdataset)) {
- validator_log(val, ISC_LOG_DEBUG(3),
- "no supported algorithm/"
- "digest (%s/DS)",
- namebuf);
+ validator_log(
+ val, ISC_LOG_DEBUG(3),
+ "no supported algorithm/digest (%s/DS)",
+ namebuf);
*resp = markanswer(val, "proveunsecure (5)",
"no supported "
"algorithm/digest (DS)");
isc_result_t result = ISC_R_FAILURE;
if (CANCELED(val)) {
- return;
+ result = ISC_R_CANCELED;
+ goto cleanup;
}
validator_log(val, ISC_LOG_DEBUG(3), "starting");
if (val->rdataset != NULL && val->sigrdataset != NULL) {
- isc_result_t saved_result;
-
/*
* This looks like a simple validation. We say "looks like"
* because it might end up requiring an insecurity proof.
INSIST(dns_rdataset_isassociated(val->rdataset));
INSIST(dns_rdataset_isassociated(val->sigrdataset));
- if (selfsigned_dnskey(val)) {
- result = validate_dnskey(val);
- } else {
- result = validate_answer(val, false);
- }
- if (result == DNS_R_NOVALIDSIG &&
- (val->attributes & VALATTR_TRIEDVERIFY) == 0)
- {
- saved_result = result;
- validator_log(val, ISC_LOG_DEBUG(3),
- "falling back to insecurity proof");
- result = proveunsecure(val, false, false);
- if (result == DNS_R_NOTINSECURE) {
- result = saved_result;
- }
+
+ result = selfsigned_dnskey(val);
+ switch (result) {
+ case ISC_R_QUOTA:
+ goto cleanup;
+ case ISC_R_SUCCESS:
+ result = validate_async_run(val, validate_dnskey);
+ break;
+ case DNS_R_NOKEYMATCH:
+ result = validate_async_run(val, validate_answer);
+ break;
+ default:
+ UNREACHABLE();
}
} else if (val->rdataset != NULL && val->rdataset->type != 0) {
/*
UNREACHABLE();
}
- if (result != DNS_R_WAIT) {
- validator_done(val, result);
- }
-
- dns_validator_detach(&val);
+cleanup:
+ validate_async_done(val, result);
}
isc_result_t
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
isc_loop_t *loop, isc_job_cb cb, void *arg,
+ uint32_t *nvalidations, uint32_t *nfails,
dns_validator_t **validatorp) {
isc_result_t result = ISC_R_FAILURE;
dns_validator_t *val = NULL;
}
val = isc_mem_get(view->mctx, sizeof(*val));
- *val = (dns_validator_t){ .tid = isc_tid(),
- .result = ISC_R_FAILURE,
- .rdataset = rdataset,
- .sigrdataset = sigrdataset,
- .name = name,
- .type = type,
- .options = options,
- .keytable = kt,
- .link = ISC_LINK_INITIALIZER,
- .loop = loop,
- .cb = cb,
- .arg = arg };
+ *val = (dns_validator_t){
+ .tid = isc_tid(),
+ .result = DNS_R_NOVALIDSIG,
+ .rdataset = rdataset,
+ .sigrdataset = sigrdataset,
+ .name = name,
+ .type = type,
+ .options = options,
+ .keytable = kt,
+ .link = ISC_LINK_INITIALIZER,
+ .loop = loop,
+ .cb = cb,
+ .arg = arg,
+ .rdata = DNS_RDATA_INIT,
+ .nvalidations = nvalidations,
+ .nfails = nfails,
+ };
isc_refcount_init(&val->references, 1);
dns_view_attach(view, &val->view);
if ((options & DNS_VALIDATOR_DEFER) == 0) {
dns_validator_ref(val);
- isc_async_run(val->loop, validator_start, val);
+ (void)validate_async_run(val, validator_start);
}
*validatorp = val;
}
void
-dns_validator_send(dns_validator_t *validator) {
- REQUIRE(VALID_VALIDATOR(validator));
- REQUIRE(validator->tid == isc_tid());
+dns_validator_send(dns_validator_t *val) {
+ REQUIRE(VALID_VALIDATOR(val));
+ REQUIRE(val->tid == isc_tid());
- INSIST((validator->options & DNS_VALIDATOR_DEFER) != 0);
- validator->options &= ~DNS_VALIDATOR_DEFER;
+ INSIST((val->options & DNS_VALIDATOR_DEFER) != 0);
+ val->options &= ~DNS_VALIDATOR_DEFER;
- dns_validator_ref(validator);
- isc_async_run(validator->loop, validator_start, validator);
+ dns_validator_ref(val);
+ (void)validate_async_run(val, validator_start);
}
void
validator->options &= ~DNS_VALIDATOR_DEFER;
validator_done(validator, ISC_R_CANCELED);
}
-
validator->attributes |= VALATTR_CANCELED;
}
}
if (val->keytable != NULL) {
dns_keytable_detach(&val->keytable);
}
- if (val->subvalidator != NULL) {
- dns_validator_destroy(&val->subvalidator);
- }
disassociate_rdatasets(val);
mctx = val->view->mctx;
if (val->siginfo != NULL) {