findkey state.

git-svn-id: file:///svn/unbound/trunk@528 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-08-16 15:06:40 +00:00
parent 568f0699dc
commit 9ddbb430ef
5 changed files with 249 additions and 12 deletions

View file

@ -10,6 +10,7 @@
dig ANY gives sometimes NS rrset in AN and NS section, and parser
removes the NS section duplicate. dig NS gives sometimes the NS
in the answer section, as referral.
- validator FINDKEY state.
15 August 2007: Wouter
- crypto calls to verify signatures.

View file

@ -595,6 +595,14 @@ dname_remove_label(uint8_t** dname, size_t* len)
*dname += lablen+1;
}
void
dname_remove_labels(uint8_t** dname, size_t* len, int n)
{
int i;
for(i=0; i<n; i++)
dname_remove_label(dname, len);
}
int
dname_signame_label_count(uint8_t* dname)
{

View file

@ -232,6 +232,16 @@ int dname_is_root(uint8_t* dname);
*/
void dname_remove_label(uint8_t** dname, size_t* len);
/**
* Snip off first N labels from a dname, returning the parent zone.
* @param dname: from what to strip off. uncompressed wireformat.
* @param len: length, adjusted to become less.
* @param n: number of labels to strip off (from the left).
* if 0, nothing happens.
* @return stripped off, or "." if input was ".".
*/
void dname_remove_labels(uint8_t** dname, size_t* len, int n);
/**
* Count labels for the RRSIG signature label field.
* Like a normal labelcount, but "*" wildcard and "." root are not counted.

View file

@ -134,6 +134,22 @@ dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx)
return f;
}
/**
* Get DNSKEY protocol value from rdata
* @param k: DNSKEY rrset.
* @param idx: which key.
*/
static int
dnskey_get_protocol(struct ub_packed_rrset_key* k, size_t idx)
{
uint8_t* rdata;
size_t len;
rrset_get_rdata(k, idx, &rdata, &len);
if(len < 2+4)
return 0;
return (int)rdata[2+2];
}
int
dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx)
{
@ -1271,7 +1287,13 @@ dnskey_verify_rrset_sig(struct module_env* env, struct val_env* ve,
if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
verbose(VERB_ALGO, "verify: dnskey without ZSK flag");
return sec_status_bogus; /* signer name invalid */
return sec_status_bogus;
}
if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) {
/* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
verbose(VERB_ALGO, "verify: dnskey has wrong key protocol");
return sec_status_bogus;
}
/* verify as many fields in rrsig as possible */

View file

@ -200,6 +200,39 @@ needs_validation(struct module_qstate* qstate, struct val_qstate* vq)
return 1;
}
/**
* Generate a request for DNS data.
*
* @param qstate: query state that is the parent.
* @param id: module id.
* @param name: what name to query for.
* @param namelen: length of name.
* @param qtype: query type.
* @param qclass: query class.
* @return false on alloc failure.
*/
static int
generate_request(struct module_qstate* qstate, int id, uint8_t* name,
size_t namelen, uint16_t qtype, uint16_t qclass)
{
struct module_qstate* newq;
struct query_info ask;
ask.qname = name;
ask.qname_len = namelen;
ask.qtype = qtype;
ask.qclass = qclass;
log_query_info(VERB_ALGO, "generate request", &ask);
if(!(*qstate->env->attach_sub)(qstate, &ask,
(uint16_t)(BIT_RD|BIT_CD), 0, &newq)){
log_err("Could not generate request: out of memory");
return 0;
}
/* ignore newq; validator does not need state created for that
* query, and its a 'normal' for iterator as well */
qstate->ext_state[id] = module_wait_subquery;
return 1;
}
/**
* Prime trust anchor for use.
* Generate and dispatch a priming query for the given trust anchor.
@ -215,15 +248,9 @@ static int
prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
int id, struct trust_anchor* toprime)
{
struct module_qstate* newq;
struct query_info ask;
ask.qname = toprime->name;
ask.qname_len = toprime->namelen;
ask.qtype = LDNS_RR_TYPE_DNSKEY;
ask.qclass = toprime->dclass;
log_query_info(VERB_ALGO, "priming trust anchor", &ask);
if(!(*qstate->env->attach_sub)(qstate, &ask,
(uint16_t)(BIT_RD|BIT_CD), 0, &newq)){
int ret = generate_request(qstate, id, toprime->name, toprime->namelen,
LDNS_RR_TYPE_DNSKEY, toprime->dclass);
if(!ret) {
log_err("Could not prime trust anchor: out of memory");
return 0;
}
@ -231,7 +258,6 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
* query, and its a 'normal' for iterator as well */
vq->wait_prime_ta = 1; /* to elicit PRIME_RESP_STATE processing
from the validator inform_super() routine */
qstate->ext_state[id] = module_wait_subquery;
return 1;
}
@ -311,6 +337,94 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
return 1;
}
/**
* Process the FINDKEY state. Generally this just calculates the next name
* to query and either issues a DS or a DNSKEY query. It will check to see
* if the correct key has already been reached, in which case it will
* advance the event to the next state.
*
* @param qstate: query state.
* @param vq: validator query state.
* @param id: module id.
* @return true if the event should be processed further on return, false if
* not.
*/
static int
processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
{
uint8_t* target_key_name, *current_key_name;
size_t target_key_len, current_key_len;
int strip_lab;
verbose(VERB_ALGO, "validator: FindKey");
/* We know that state.key_entry is not a null or bad key -- if it were,
* then previous processing should have directed this event to
* a different state. */
log_assert(vq->key_entry && !key_entry_isbad(vq->key_entry) &&
!key_entry_isnull(vq->key_entry));
target_key_name = vq->signer_name;
target_key_len = vq->signer_len;
if(!target_key_name) {
target_key_name = vq->qchase.qname;
target_key_len = vq->qchase.qname_len;
}
current_key_name = vq->key_entry->name;
current_key_len = vq->key_entry->namelen;
/* If our current key entry matches our target, then we are done. */
if(query_dname_compare(target_key_name, current_key_name) == 0) {
vq->state = VAL_VALIDATE_STATE;
return 1;
}
if(vq->empty_DS_name) {
current_key_name = vq->empty_DS_name;
current_key_len = vq->empty_DS_len;
}
log_nametypeclass(VERB_ALGO, "current keyname", current_key_name,
LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
log_nametypeclass(VERB_ALGO, "target keyname", target_key_name,
LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
/* assert we are walking down the DNS tree */
log_assert(dname_subdomain_c(target_key_name, current_key_name));
/* so this value is >= 0 */
strip_lab = dname_count_labels(target_key_name) -
dname_count_labels(current_key_name) - 1;
log_assert(strip_lab >= 0);
verbose(VERB_ALGO, "striplab %d", strip_lab);
dname_remove_labels(&target_key_name, &target_key_len, strip_lab);
log_nametypeclass(VERB_ALGO, "next keyname", target_key_name,
LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN);
/* The next step is either to query for the next DS, or to query
* for the next DNSKEY. */
if(!vq->ds_rrset || query_dname_compare(vq->ds_rrset->rk.dname,
target_key_name) != 0) {
if(!generate_request(qstate, id, target_key_name,
target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass)) {
log_err("mem error generating DS request");
qstate->ext_state[id] = module_error;
return 0;
}
return 0;
}
/* Otherwise, it is time to query for the DNSKEY */
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
vq->qchase.qclass)) {
log_err("mem error generating DNSKEY request");
qstate->ext_state[id] = module_error;
return 0;
}
return 0;
}
/**
* Handle validator state.
* If a method returns true, the next state is started. If false, then
@ -332,6 +446,14 @@ val_handle(struct module_qstate* qstate, struct val_qstate* vq,
case VAL_INIT_STATE:
cont = processInit(qstate, vq, ve, id);
break;
case VAL_FINDKEY_STATE:
cont = processFindKey(qstate, vq, id);
break;
case VAL_PRIME_RESP_STATE:
case VAL_FINDKEY_DS_RESP_STATE:
case VAL_FINDKEY_DNSKEY_RESP_STATE:
case VAL_VALIDATE_STATE:
case VAL_FINISHED_STATE:
default:
log_warn("validator: invalid state %d",
vq->state);
@ -493,6 +615,71 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta,
return kkey;
}
/**
* Process DS response. Called from inform_supers.
*
* @param qstate: query state that is validating and asked for a DS.
* @param vq: validator query state
* @param id: module id.
* @param rcode: rcode result value.
* @param msg: result message (if rcode is OK).
* @param qinfo: from the sub query state, query info.
*/
static void
process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo)
{
struct key_entry_key* dske = NULL;
/* TODO
if(!ds_response_to_ke(qstate, vq, id, rcode, msg, &dske)) {
@@@ */ if(0) {
log_err("malloc failure in DStoKE");
vq->key_entry = NULL; /* make it error */
vq->state = VAL_VALIDATE_STATE;
return;
}
if(dske == NULL) {
vq->empty_DS_name = qinfo->qname;
vq->empty_DS_len = qinfo->qname_len;
/* ds response indicated that we aren't on a delegation point.
* Keep the forState.state on FINDKEY. */
} else if(key_entry_isgood(dske)) {
/* TODO
vq->ds_rrset = key_entry_getrrset(dske);
*/
if(!vq->ds_rrset) {
log_err("malloc failure in process DS");
vq->key_entry = NULL; /* make it error */
vq->state = VAL_VALIDATE_STATE;
return;
}
/* Keep the forState.state on FINDKEY. */
} else {
/* NOTE: the reason for the DS to be not good (that is,
* either bad or null) should have been logged by
* dsResponseToKE. */
vq->key_entry = dske;
/* The FINDKEY phase has ended, so move on. */
vq->state = VAL_VALIDATE_STATE;
}
}
/**
* Process DNSKEY response. Called from inform_supers.
* Sets the key entry in the state.
*
* @param qstate: query state that is validating and asked for a DNSKEY.
* @param vq: validator query state
* @param id: module id.
* @param rcode: rcode result value.
* @param msg: result message (if rcode is OK).
*/
static void
process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg)
{
}
/**
* Process prime response
* Sets the key entry in the state.
@ -544,9 +731,18 @@ val_inform_super(struct module_qstate* qstate, int id,
qstate->return_msg);
return;
}
if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
process_ds_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo);
return;
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
process_dnskey_response(super, vq, id, qstate->return_rcode,
qstate->return_msg);
return;
}
log_err("internal error in validator: no inform_supers possible");
}
/** validator cleanup query state */
static void
val_clear(struct module_qstate* qstate, int id)