mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-05-28 04:02:33 -04:00
findkey state.
git-svn-id: file:///svn/unbound/trunk@528 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
568f0699dc
commit
9ddbb430ef
5 changed files with 249 additions and 12 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue