validator.c revision 8db70f36bee634ad850bc5ab60afab5c6123bc01
/*
* Copyright (C) 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <config.h>
#include <isc/assertions.h>
#include <dns/validator.h>
#include <dns/keytable.h>
#include <dns/keyvalues.h>
#include <dns/rdatatype.h>
#include <dns/rdataset.h>
#include <dns/resolver.h>
/*
* We don't use the SIG RR's _tostruct routine because it copies things.
*/
typedef struct dns_siginfo {
struct dns_validator {
/* Unlocked. */
unsigned int magic;
dns_view_t * view;
/* Locked by lock. */
unsigned int options;
unsigned int attributes;
dns_fetch_t * fetch;
isc_task_t * task;
void * arg;
unsigned int labels;
};
#define VALATTR_SHUTDOWN 0x01
#define VALATTR_NEGATIVE 0x02
const char *fmt, ...);
static void
isc_buffer_t b;
isc_region_t r;
isc_buffer_remaining(&b, &r);
}
static void
/*
* Caller must be holding the lock.
*/
}
}
static void
if (result != ISC_R_SUCCESS) {
/* No matching key */
goto free_event;
}
else
if (result != DNS_R_WAIT) {
goto free_event;
}
} else
"fetch_callback_validator: got %s",
/* free stuff from the event */
sizeof(dns_rdataset_t));
}
static void
/* No null key */
"found a keyset, no null key");
if (result != DNS_R_WAIT)
} else {
"found a keyset with a null key");
else if (!dns_rdataset_isassociated(sigrdataset))
else {
NULL,
0,
val,
&val->keyvalidator);
if (result != ISC_R_SUCCESS)
/*
* don't free these, since they'll be
* freed in nullkeyvalidated.
*/
}
}
{
/* No keys */
"no keys found");
if (result != DNS_R_WAIT)
} else
"fetch_callback_nullkey: got %s",
/* free stuff from the event */
sizeof(dns_rdataset_t));
sizeof(dns_rdataset_t));
}
static void
if (result != ISC_R_SUCCESS) {
/* No matching key */
goto free_event;
}
else
if (result != DNS_R_WAIT) {
goto free_event;
}
} else
"keyvalidated: got %s",
/* free stuff from the event */
sizeof(dns_rdataset_t));
}
static void
"proved that name is in an unsecure domain");
} else {
if (result != DNS_R_WAIT)
}
/* free stuff from the event */
sizeof(dns_rdataset_t));
}
/*
* Try to find a null zone key among those in 'rdataset'. If found, build
* a dst_key_t for it and point val->key at it.
*/
static inline isc_boolean_t
isc_buffer_t b;
if (result != ISC_R_SUCCESS)
return (ISC_FALSE);
/*
* conversion.
*/
if (result != ISC_R_SUCCESS)
continue;
if (dst_key_isnullkey(key))
}
return (found);
}
/*
* Try to find a key that could have signed 'siginfo' among those
* in 'rdataset'. If found, build a dst_key_t for it and point
* val->key at it.
*
* XXX does not handle key tag collisions.
*/
static inline isc_result_t
{
isc_buffer_t b;
char ntext[1024];
if (result != ISC_R_SUCCESS)
return (result);
do {
/*
* We keep one byte of ntext in reserve so
* we're sure we can NUL terminate.
*/
if (result != ISC_R_SUCCESS)
return (result);
/*
* NUL-terminate the character string.
*/
isc_buffer_putuint8(&b, 0);
if (result != ISC_R_SUCCESS)
return (result);
{
/*
* This is the key we're looking for.
*/
return (ISC_R_SUCCESS);
}
} while (result == ISC_R_SUCCESS);
if (result == ISC_R_NOMORE)
return (result);
}
static inline isc_result_t
int order;
/*
* Is the key used for the signature a security root?
*/
if (result == ISC_R_NOTFOUND) {
/*
* Is it a trusted key that is not a security root?
*/
if (result == ISC_R_SUCCESS) {
/*
* The key is trusted.
*/
return (ISC_R_SUCCESS);
} else if (result != ISC_R_NOTFOUND)
return (result);
} else if (result == ISC_R_SUCCESS) {
/*
* The key is a security root.
*/
return (ISC_R_SUCCESS);
} else
return (result);
/*
* The signature was not made with a security root or trusted key.
*/
/*
* Is the key name appropriate for this signature?
*/
/*
* We don't want a KEY RR to authenticate
* itself, so we ignore the signature if it
* was not made by an ancestor of the KEY.
*/
return (DNS_R_CONTINUE);
} else if (namereln != dns_namereln_subdomain &&
namereln != dns_namereln_equal) {
/*
* The key name is not at the same level
* as 'rdataset', nor is it closer to the
* DNS root.
*/
return (DNS_R_CONTINUE);
}
/*
* Do we know about this key?
*/
&rdataset, &sigrdataset);
if (result == ISC_R_SUCCESS) {
/*
* We have an rrset for the given keyname.
*/
/*
* We know the key but haven't validated it yet.
*/
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
if (fsigrdataset == NULL) {
sizeof *frdataset);
return (ISC_R_NOMEMORY);
}
NULL,
0,
val,
&val->keyvalidator);
if (result != ISC_R_SUCCESS)
return (result);
return (DNS_R_WAIT);
} else {
/*
* XXXRTH What should we do if this is an untrusted
* rdataset?
*/
/*
* See if we've got the key used in the signature.
*/
if (result != ISC_R_SUCCESS) {
/*
* Either the key we're looking for is not
* in the rrset, or something bad happened.
* Give up.
*/
}
}
} else if (result == ISC_R_NOTFOUND) {
/*
* We don't know anything about this key.
*/
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
if (fsigrdataset == NULL) {
sizeof *frdataset);
return (ISC_R_NOMEMORY);
}
val,
if (result != ISC_R_SUCCESS)
return (result);
return (DNS_R_WAIT);
} else if (result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET ||
result == DNS_R_NXDOMAIN ||
result == DNS_R_NXRRSET) {
/*
* This key doesn't exist.
*/
}
return (result);
}
static inline isc_result_t
/*
* Caller must be holding the validator lock.
*/
if (resume) {
/* We alraedy have a sigrdataset. */
} else {
}
for (;
result == ISC_R_SUCCESS;
{
return (ISC_R_NOMEMORY);
/*
* At this point we could check that the signature algorithm
* was known and "sufficiently good". For now, any algorithm
* is acceptable.
*/
if (!resume) {
if (result == DNS_R_CONTINUE)
continue; /* Try the next SIG RR. */
if (result != ISC_R_SUCCESS)
return (result);
}
if (result == ISC_R_SUCCESS) {
"marking as secure");
return (result);
}
else
"verify failure: %s",
}
if (result == ISC_R_NOMORE)
return (result);
}
static inline isc_result_t
int order;
isc_region_t r;
if (!resume) {
if (result != ISC_R_SUCCESS)
} else
for (;
result == ISC_R_SUCCESS;
{
{
continue;
return (DNS_R_FORMERR);
sigrdataset != NULL;
link))
{
if (sigrdataset->type ==
&&
sigrdataset->covers ==
break;
}
if (sigrdataset != NULL)
break;
}
continue;
}
if (order == 0) {
"invalid type %d",
continue;
}
"type should not be present");
continue;
}
} else if (order > 0) {
dns_rdata_toregion(&rdata, &r);
dns_name_fromregion(&nextname, &r);
if (order >= 0) {
&nextname))
{
"next name is not greater");
continue;
}
}
} else {
"nxt owner name is not less");
continue;
}
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
"no relevant NXT found");
return (result);
}
static inline isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
if (!resume)
else
for (;
{
else {
if (result != ISC_R_SUCCESS)
return (result);
}
&rdataset, &sigrdataset);
if (result == ISC_R_SUCCESS) {
if (!dns_rdataset_isassociated(&sigrdataset))
return (ISC_R_FAILURE);
"found keyset, looking for null key");
continue;
return (ISC_R_SUCCESS);
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
if (fsigrdataset == NULL) {
sizeof *frdataset);
return (ISC_R_NOMEMORY);
}
sizeof *frdataset);
sizeof *fsigrdataset);
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS) {
sizeof *frdataset);
sizeof *fsigrdataset);
return (ISC_R_NOMEMORY);
}
NULL,
0,
val,
&val->keyvalidator);
return (DNS_R_WAIT);
} else if (result == ISC_R_NOTFOUND) {
sizeof *frdataset);
return (ISC_R_NOMEMORY);
sizeof *fsigrdataset);
if (fsigrdataset == NULL) {
sizeof *frdataset);
return (ISC_R_NOMEMORY);
}
val,
if (result != ISC_R_SUCCESS)
return (result);
return (DNS_R_WAIT);
} else if (result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET ||
result == DNS_R_NXDOMAIN ||
result == DNS_R_NXRRSET)
{
continue;
} else
return (result);
}
return (ISC_R_FAILURE); /* Didn't find a null key */
}
static void
/*
* This looks like a simple validation. We say "looks like"
* because we don't know if wildcards are involved yet so it
* could still get complicated.
*/
/*
* This is either an unsecure subdomain or a response from
* a broken server.
*/
{
/*
* This is a nonexistence validation.
*/
} else {
/* This shouldn't happen */
INSIST(0);
}
if (result != DNS_R_WAIT)
}
{
return (ISC_R_NOMEMORY);
event = (dns_validatorevent_t *)
sizeof (dns_validatorevent_t));
goto cleanup_val;
}
if (result != ISC_R_SUCCESS)
goto cleanup_event;
val->attributes = 0;
*validatorp = val;
return (ISC_R_SUCCESS);
return (result);
}
void
}
}
static void
}
void
val = *validatorp;
if (want_destroy)
*validatorp = NULL;
}
static void
{
char msgbuf[2048];
{
char namebuf[1024];
char typebuf[256];
isc_buffer_t b;
isc_region_t r;
!= ISC_R_SUCCESS)
{
isc_buffer_clear(&b);
isc_buffer_putstr(&b, "<bad type>");
}
isc_buffer_used(&b, &r);
"validating %s %.*s: %s", namebuf,
} else {
}
}
static void
{
}