1238106Sdes/* 2238106Sdes * validator/validator.c - secure validator DNS query response module 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains a module that performs validation of DNS queries. 40238106Sdes * According to RFC 4034. 41238106Sdes */ 42238106Sdes#include "config.h" 43238106Sdes#include "validator/validator.h" 44238106Sdes#include "validator/val_anchor.h" 45238106Sdes#include "validator/val_kcache.h" 46238106Sdes#include "validator/val_kentry.h" 47238106Sdes#include "validator/val_utils.h" 48238106Sdes#include "validator/val_nsec.h" 49238106Sdes#include "validator/val_nsec3.h" 50238106Sdes#include "validator/val_neg.h" 51238106Sdes#include "validator/val_sigcrypt.h" 52238106Sdes#include "validator/autotrust.h" 53238106Sdes#include "services/cache/dns.h" 54238106Sdes#include "util/data/dname.h" 55238106Sdes#include "util/module.h" 56238106Sdes#include "util/log.h" 57238106Sdes#include "util/net_help.h" 58238106Sdes#include "util/regional.h" 59238106Sdes#include "util/config_file.h" 60238106Sdes#include "util/fptr_wlist.h" 61269257Sdes#include "ldns/rrdef.h" 62269257Sdes#include "ldns/wire2str.h" 63238106Sdes 64238106Sdes/* forward decl for cache response and normal super inform calls of a DS */ 65238106Sdesstatic void process_ds_response(struct module_qstate* qstate, 66238106Sdes struct val_qstate* vq, int id, int rcode, struct dns_msg* msg, 67238106Sdes struct query_info* qinfo, struct sock_list* origin); 68238106Sdes 69238106Sdes/** fill up nsec3 key iterations config entry */ 70238106Sdesstatic int 71238106Sdesfill_nsec3_iter(struct val_env* ve, char* s, int c) 72238106Sdes{ 73238106Sdes char* e; 74238106Sdes int i; 75238106Sdes free(ve->nsec3_keysize); 76238106Sdes free(ve->nsec3_maxiter); 77238106Sdes ve->nsec3_keysize = (size_t*)calloc(sizeof(size_t), (size_t)c); 78238106Sdes ve->nsec3_maxiter = (size_t*)calloc(sizeof(size_t), (size_t)c); 79238106Sdes if(!ve->nsec3_keysize || !ve->nsec3_maxiter) { 80238106Sdes log_err("out of memory"); 81238106Sdes return 0; 82238106Sdes } 83238106Sdes for(i=0; i<c; i++) { 84238106Sdes ve->nsec3_keysize[i] = (size_t)strtol(s, &e, 10); 85238106Sdes if(s == e) { 86238106Sdes log_err("cannot parse: %s", s); 87238106Sdes return 0; 88238106Sdes } 89238106Sdes s = e; 90238106Sdes ve->nsec3_maxiter[i] = (size_t)strtol(s, &e, 10); 91238106Sdes if(s == e) { 92238106Sdes log_err("cannot parse: %s", s); 93238106Sdes return 0; 94238106Sdes } 95238106Sdes s = e; 96238106Sdes if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) { 97238106Sdes log_err("nsec3 key iterations not ascending: %d %d", 98238106Sdes (int)ve->nsec3_keysize[i-1], 99238106Sdes (int)ve->nsec3_keysize[i]); 100238106Sdes return 0; 101238106Sdes } 102238106Sdes verbose(VERB_ALGO, "validator nsec3cfg keysz %d mxiter %d", 103238106Sdes (int)ve->nsec3_keysize[i], (int)ve->nsec3_maxiter[i]); 104238106Sdes } 105238106Sdes return 1; 106238106Sdes} 107238106Sdes 108238106Sdes/** apply config settings to validator */ 109238106Sdesstatic int 110238106Sdesval_apply_cfg(struct module_env* env, struct val_env* val_env, 111238106Sdes struct config_file* cfg) 112238106Sdes{ 113238106Sdes int c; 114238106Sdes val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl; 115238106Sdes val_env->clean_additional = cfg->val_clean_additional; 116238106Sdes val_env->permissive_mode = cfg->val_permissive_mode; 117238106Sdes if(!env->anchors) 118238106Sdes env->anchors = anchors_create(); 119238106Sdes if(!env->anchors) { 120238106Sdes log_err("out of memory"); 121238106Sdes return 0; 122238106Sdes } 123238106Sdes if(!val_env->kcache) 124238106Sdes val_env->kcache = key_cache_create(cfg); 125238106Sdes if(!val_env->kcache) { 126238106Sdes log_err("out of memory"); 127238106Sdes return 0; 128238106Sdes } 129238106Sdes env->key_cache = val_env->kcache; 130238106Sdes if(!anchors_apply_cfg(env->anchors, cfg)) { 131238106Sdes log_err("validator: error in trustanchors config"); 132238106Sdes return 0; 133238106Sdes } 134238106Sdes val_env->date_override = cfg->val_date_override; 135238106Sdes val_env->skew_min = cfg->val_sig_skew_min; 136238106Sdes val_env->skew_max = cfg->val_sig_skew_max; 137238106Sdes c = cfg_count_numbers(cfg->val_nsec3_key_iterations); 138238106Sdes if(c < 1 || (c&1)) { 139238106Sdes log_err("validator: unparseable or odd nsec3 key " 140238106Sdes "iterations: %s", cfg->val_nsec3_key_iterations); 141238106Sdes return 0; 142238106Sdes } 143238106Sdes val_env->nsec3_keyiter_count = c/2; 144238106Sdes if(!fill_nsec3_iter(val_env, cfg->val_nsec3_key_iterations, c/2)) { 145238106Sdes log_err("validator: cannot apply nsec3 key iterations"); 146238106Sdes return 0; 147238106Sdes } 148238106Sdes if(!val_env->neg_cache) 149238106Sdes val_env->neg_cache = val_neg_create(cfg, 150238106Sdes val_env->nsec3_maxiter[val_env->nsec3_keyiter_count-1]); 151238106Sdes if(!val_env->neg_cache) { 152238106Sdes log_err("out of memory"); 153238106Sdes return 0; 154238106Sdes } 155238106Sdes env->neg_cache = val_env->neg_cache; 156238106Sdes return 1; 157238106Sdes} 158238106Sdes 159238106Sdesint 160238106Sdesval_init(struct module_env* env, int id) 161238106Sdes{ 162238106Sdes struct val_env* val_env = (struct val_env*)calloc(1, 163238106Sdes sizeof(struct val_env)); 164238106Sdes if(!val_env) { 165238106Sdes log_err("malloc failure"); 166238106Sdes return 0; 167238106Sdes } 168238106Sdes env->modinfo[id] = (void*)val_env; 169238106Sdes env->need_to_validate = 1; 170238106Sdes val_env->permissive_mode = 0; 171238106Sdes lock_basic_init(&val_env->bogus_lock); 172238106Sdes lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus, 173238106Sdes sizeof(val_env->num_rrset_bogus)); 174238106Sdes if(!val_apply_cfg(env, val_env, env->cfg)) { 175238106Sdes log_err("validator: could not apply configuration settings."); 176238106Sdes return 0; 177238106Sdes } 178238106Sdes return 1; 179238106Sdes} 180238106Sdes 181238106Sdesvoid 182238106Sdesval_deinit(struct module_env* env, int id) 183238106Sdes{ 184238106Sdes struct val_env* val_env; 185238106Sdes if(!env || !env->modinfo[id]) 186238106Sdes return; 187238106Sdes val_env = (struct val_env*)env->modinfo[id]; 188238106Sdes lock_basic_destroy(&val_env->bogus_lock); 189238106Sdes anchors_delete(env->anchors); 190238106Sdes env->anchors = NULL; 191238106Sdes key_cache_delete(val_env->kcache); 192238106Sdes neg_cache_delete(val_env->neg_cache); 193238106Sdes free(val_env->nsec3_keysize); 194238106Sdes free(val_env->nsec3_maxiter); 195238106Sdes free(val_env); 196238106Sdes env->modinfo[id] = NULL; 197238106Sdes} 198238106Sdes 199238106Sdes/** fill in message structure */ 200238106Sdesstatic struct val_qstate* 201238106Sdesval_new_getmsg(struct module_qstate* qstate, struct val_qstate* vq) 202238106Sdes{ 203238106Sdes if(!qstate->return_msg || qstate->return_rcode != LDNS_RCODE_NOERROR) { 204238106Sdes /* create a message to verify */ 205238106Sdes verbose(VERB_ALGO, "constructing reply for validation"); 206238106Sdes vq->orig_msg = (struct dns_msg*)regional_alloc(qstate->region, 207238106Sdes sizeof(struct dns_msg)); 208238106Sdes if(!vq->orig_msg) 209238106Sdes return NULL; 210238106Sdes vq->orig_msg->qinfo = qstate->qinfo; 211238106Sdes vq->orig_msg->rep = (struct reply_info*)regional_alloc( 212238106Sdes qstate->region, sizeof(struct reply_info)); 213238106Sdes if(!vq->orig_msg->rep) 214238106Sdes return NULL; 215238106Sdes memset(vq->orig_msg->rep, 0, sizeof(struct reply_info)); 216238106Sdes vq->orig_msg->rep->flags = (uint16_t)(qstate->return_rcode&0xf) 217238106Sdes |BIT_QR|BIT_RA|(qstate->query_flags|(BIT_CD|BIT_RD)); 218238106Sdes vq->orig_msg->rep->qdcount = 1; 219238106Sdes } else { 220238106Sdes vq->orig_msg = qstate->return_msg; 221238106Sdes } 222238106Sdes vq->qchase = qstate->qinfo; 223238106Sdes /* chase reply will be an edited (sub)set of the orig msg rrset ptrs */ 224238106Sdes vq->chase_reply = regional_alloc_init(qstate->region, 225238106Sdes vq->orig_msg->rep, 226238106Sdes sizeof(struct reply_info) - sizeof(struct rrset_ref)); 227238106Sdes if(!vq->chase_reply) 228238106Sdes return NULL; 229238106Sdes vq->chase_reply->rrsets = regional_alloc_init(qstate->region, 230238106Sdes vq->orig_msg->rep->rrsets, sizeof(struct ub_packed_rrset_key*) 231238106Sdes * vq->orig_msg->rep->rrset_count); 232238106Sdes if(!vq->chase_reply->rrsets) 233238106Sdes return NULL; 234238106Sdes vq->rrset_skip = 0; 235238106Sdes return vq; 236238106Sdes} 237238106Sdes 238238106Sdes/** allocate new validator query state */ 239238106Sdesstatic struct val_qstate* 240238106Sdesval_new(struct module_qstate* qstate, int id) 241238106Sdes{ 242238106Sdes struct val_qstate* vq = (struct val_qstate*)regional_alloc( 243238106Sdes qstate->region, sizeof(*vq)); 244238106Sdes log_assert(!qstate->minfo[id]); 245238106Sdes if(!vq) 246238106Sdes return NULL; 247238106Sdes memset(vq, 0, sizeof(*vq)); 248238106Sdes qstate->minfo[id] = vq; 249238106Sdes vq->state = VAL_INIT_STATE; 250238106Sdes return val_new_getmsg(qstate, vq); 251238106Sdes} 252238106Sdes 253238106Sdes/** 254238106Sdes * Exit validation with an error status 255238106Sdes * 256238106Sdes * @param qstate: query state 257238106Sdes * @param id: validator id. 258238106Sdes * @return false, for use by caller to return to stop processing. 259238106Sdes */ 260238106Sdesstatic int 261238106Sdesval_error(struct module_qstate* qstate, int id) 262238106Sdes{ 263238106Sdes qstate->ext_state[id] = module_error; 264238106Sdes qstate->return_rcode = LDNS_RCODE_SERVFAIL; 265238106Sdes return 0; 266238106Sdes} 267238106Sdes 268238106Sdes/** 269238106Sdes * Check to see if a given response needs to go through the validation 270238106Sdes * process. Typical reasons for this routine to return false are: CD bit was 271238106Sdes * on in the original request, or the response is a kind of message that 272238106Sdes * is unvalidatable (i.e., SERVFAIL, REFUSED, etc.) 273238106Sdes * 274238106Sdes * @param qstate: query state. 275238106Sdes * @param ret_rc: rcode for this message (if noerror - examine ret_msg). 276238106Sdes * @param ret_msg: return msg, can be NULL; look at rcode instead. 277238106Sdes * @return true if the response could use validation (although this does not 278238106Sdes * mean we can actually validate this response). 279238106Sdes */ 280238106Sdesstatic int 281238106Sdesneeds_validation(struct module_qstate* qstate, int ret_rc, 282238106Sdes struct dns_msg* ret_msg) 283238106Sdes{ 284238106Sdes int rcode; 285238106Sdes 286238106Sdes /* If the CD bit is on in the original request, then we don't bother to 287238106Sdes * validate anything.*/ 288238106Sdes if(qstate->query_flags & BIT_CD) { 289238106Sdes verbose(VERB_ALGO, "not validating response due to CD bit"); 290238106Sdes return 0; 291238106Sdes } 292238106Sdes 293238106Sdes if(ret_rc != LDNS_RCODE_NOERROR || !ret_msg) 294238106Sdes rcode = ret_rc; 295238106Sdes else rcode = (int)FLAGS_GET_RCODE(ret_msg->rep->flags); 296238106Sdes 297238106Sdes if(rcode != LDNS_RCODE_NOERROR && rcode != LDNS_RCODE_NXDOMAIN) { 298269257Sdes if(verbosity >= VERB_ALGO) { 299269257Sdes char rc[16]; 300269257Sdes rc[0]=0; 301269257Sdes (void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc)); 302269257Sdes verbose(VERB_ALGO, "cannot validate non-answer, rcode %s", rc); 303269257Sdes } 304238106Sdes return 0; 305238106Sdes } 306238106Sdes 307238106Sdes /* cannot validate positive RRSIG response. (negatives can) */ 308238106Sdes if(qstate->qinfo.qtype == LDNS_RR_TYPE_RRSIG && 309238106Sdes rcode == LDNS_RCODE_NOERROR && ret_msg && 310238106Sdes ret_msg->rep->an_numrrsets > 0) { 311238106Sdes verbose(VERB_ALGO, "cannot validate RRSIG, no sigs on sigs."); 312238106Sdes return 0; 313238106Sdes } 314238106Sdes return 1; 315238106Sdes} 316238106Sdes 317238106Sdes/** 318238106Sdes * Check to see if the response has already been validated. 319238106Sdes * @param ret_msg: return msg, can be NULL 320238106Sdes * @return true if the response has already been validated 321238106Sdes */ 322238106Sdesstatic int 323238106Sdesalready_validated(struct dns_msg* ret_msg) 324238106Sdes{ 325238106Sdes /* validate unchecked, and re-validate bogus messages */ 326238106Sdes if (ret_msg && ret_msg->rep->security > sec_status_bogus) 327238106Sdes { 328238106Sdes verbose(VERB_ALGO, "response has already been validated: %s", 329238106Sdes sec_status_to_string(ret_msg->rep->security)); 330238106Sdes return 1; 331238106Sdes } 332238106Sdes return 0; 333238106Sdes} 334238106Sdes 335238106Sdes/** 336238106Sdes * Generate a request for DNS data. 337238106Sdes * 338238106Sdes * @param qstate: query state that is the parent. 339238106Sdes * @param id: module id. 340238106Sdes * @param name: what name to query for. 341238106Sdes * @param namelen: length of name. 342238106Sdes * @param qtype: query type. 343238106Sdes * @param qclass: query class. 344238106Sdes * @param flags: additional flags, such as the CD bit (BIT_CD), or 0. 345238106Sdes * @return false on alloc failure. 346238106Sdes */ 347238106Sdesstatic int 348238106Sdesgenerate_request(struct module_qstate* qstate, int id, uint8_t* name, 349238106Sdes size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags) 350238106Sdes{ 351238106Sdes struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id]; 352238106Sdes struct module_qstate* newq; 353238106Sdes struct query_info ask; 354238106Sdes ask.qname = name; 355238106Sdes ask.qname_len = namelen; 356238106Sdes ask.qtype = qtype; 357238106Sdes ask.qclass = qclass; 358238106Sdes log_query_info(VERB_ALGO, "generate request", &ask); 359238106Sdes fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); 360238106Sdes if(!(*qstate->env->attach_sub)(qstate, &ask, 361238106Sdes (uint16_t)(BIT_RD|flags), 0, &newq)){ 362238106Sdes log_err("Could not generate request: out of memory"); 363238106Sdes return 0; 364238106Sdes } 365238106Sdes /* newq; validator does not need state created for that 366238106Sdes * query, and its a 'normal' for iterator as well */ 367238106Sdes if(newq) { 368238106Sdes /* add our blacklist to the query blacklist */ 369238106Sdes sock_list_merge(&newq->blacklist, newq->region, 370238106Sdes vq->chain_blacklist); 371238106Sdes } 372238106Sdes qstate->ext_state[id] = module_wait_subquery; 373238106Sdes return 1; 374238106Sdes} 375238106Sdes 376238106Sdes/** 377238106Sdes * Prime trust anchor for use. 378238106Sdes * Generate and dispatch a priming query for the given trust anchor. 379238106Sdes * The trust anchor can be DNSKEY or DS and does not have to be signed. 380238106Sdes * 381238106Sdes * @param qstate: query state. 382238106Sdes * @param vq: validator query state. 383238106Sdes * @param id: module id. 384238106Sdes * @param toprime: what to prime. 385238106Sdes * @return false on a processing error. 386238106Sdes */ 387238106Sdesstatic int 388238106Sdesprime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq, 389238106Sdes int id, struct trust_anchor* toprime) 390238106Sdes{ 391238106Sdes int ret = generate_request(qstate, id, toprime->name, toprime->namelen, 392238106Sdes LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD); 393238106Sdes if(!ret) { 394238106Sdes log_err("Could not prime trust anchor: out of memory"); 395238106Sdes return 0; 396238106Sdes } 397238106Sdes /* ignore newq; validator does not need state created for that 398238106Sdes * query, and its a 'normal' for iterator as well */ 399238106Sdes vq->wait_prime_ta = 1; /* to elicit PRIME_RESP_STATE processing 400238106Sdes from the validator inform_super() routine */ 401238106Sdes /* store trust anchor name for later lookup when prime returns */ 402238106Sdes vq->trust_anchor_name = regional_alloc_init(qstate->region, 403238106Sdes toprime->name, toprime->namelen); 404238106Sdes vq->trust_anchor_len = toprime->namelen; 405238106Sdes vq->trust_anchor_labs = toprime->namelabs; 406238106Sdes if(!vq->trust_anchor_name) { 407238106Sdes log_err("Could not prime trust anchor: out of memory"); 408238106Sdes return 0; 409238106Sdes } 410238106Sdes return 1; 411238106Sdes} 412238106Sdes 413238106Sdes/** 414238106Sdes * Validate if the ANSWER and AUTHORITY sections contain valid rrsets. 415238106Sdes * They must be validly signed with the given key. 416238106Sdes * Tries to validate ADDITIONAL rrsets as well, but only to check them. 417238106Sdes * Allows unsigned CNAME after a DNAME that expands the DNAME. 418238106Sdes * 419238106Sdes * Note that by the time this method is called, the process of finding the 420238106Sdes * trusted DNSKEY rrset that signs this response must already have been 421238106Sdes * completed. 422238106Sdes * 423238106Sdes * @param qstate: query state. 424238106Sdes * @param env: module env for verify. 425238106Sdes * @param ve: validator env for verify. 426238106Sdes * @param qchase: query that was made. 427238106Sdes * @param chase_reply: answer to validate. 428238106Sdes * @param key_entry: the key entry, which is trusted, and which matches 429238106Sdes * the signer of the answer. The key entry isgood(). 430238106Sdes * @return false if any of the rrsets in the an or ns sections of the message 431238106Sdes * fail to verify. The message is then set to bogus. 432238106Sdes */ 433238106Sdesstatic int 434238106Sdesvalidate_msg_signatures(struct module_qstate* qstate, struct module_env* env, 435238106Sdes struct val_env* ve, struct query_info* qchase, 436238106Sdes struct reply_info* chase_reply, struct key_entry_key* key_entry) 437238106Sdes{ 438238106Sdes uint8_t* sname; 439238106Sdes size_t i, slen; 440238106Sdes struct ub_packed_rrset_key* s; 441238106Sdes enum sec_status sec; 442238106Sdes int dname_seen = 0; 443238106Sdes char* reason = NULL; 444238106Sdes 445238106Sdes /* validate the ANSWER section */ 446238106Sdes for(i=0; i<chase_reply->an_numrrsets; i++) { 447238106Sdes s = chase_reply->rrsets[i]; 448238106Sdes /* Skip the CNAME following a (validated) DNAME. 449238106Sdes * Because of the normalization routines in the iterator, 450238106Sdes * there will always be an unsigned CNAME following a DNAME 451238106Sdes * (unless qtype=DNAME). */ 452238106Sdes if(dname_seen && ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) { 453238106Sdes dname_seen = 0; 454238106Sdes /* CNAME was synthesized by our own iterator */ 455238106Sdes /* since the DNAME verified, mark the CNAME as secure */ 456238106Sdes ((struct packed_rrset_data*)s->entry.data)->security = 457238106Sdes sec_status_secure; 458238106Sdes ((struct packed_rrset_data*)s->entry.data)->trust = 459238106Sdes rrset_trust_validated; 460238106Sdes continue; 461238106Sdes } 462238106Sdes 463238106Sdes /* Verify the answer rrset */ 464238106Sdes sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason); 465238106Sdes /* If the (answer) rrset failed to validate, then this 466238106Sdes * message is BAD. */ 467238106Sdes if(sec != sec_status_secure) { 468238106Sdes log_nametypeclass(VERB_QUERY, "validator: response " 469238106Sdes "has failed ANSWER rrset:", s->rk.dname, 470238106Sdes ntohs(s->rk.type), ntohs(s->rk.rrset_class)); 471238106Sdes errinf(qstate, reason); 472238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) 473238106Sdes errinf(qstate, "for CNAME"); 474238106Sdes else if(ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) 475238106Sdes errinf(qstate, "for DNAME"); 476238106Sdes errinf_origin(qstate, qstate->reply_origin); 477238106Sdes chase_reply->security = sec_status_bogus; 478238106Sdes return 0; 479238106Sdes } 480238106Sdes 481238106Sdes /* Notice a DNAME that should be followed by an unsigned 482238106Sdes * CNAME. */ 483238106Sdes if(qchase->qtype != LDNS_RR_TYPE_DNAME && 484238106Sdes ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) { 485238106Sdes dname_seen = 1; 486238106Sdes } 487238106Sdes } 488238106Sdes 489238106Sdes /* validate the AUTHORITY section */ 490238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 491238106Sdes chase_reply->ns_numrrsets; i++) { 492238106Sdes s = chase_reply->rrsets[i]; 493238106Sdes sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason); 494238106Sdes /* If anything in the authority section fails to be secure, 495238106Sdes * we have a bad message. */ 496238106Sdes if(sec != sec_status_secure) { 497238106Sdes log_nametypeclass(VERB_QUERY, "validator: response " 498238106Sdes "has failed AUTHORITY rrset:", s->rk.dname, 499238106Sdes ntohs(s->rk.type), ntohs(s->rk.rrset_class)); 500238106Sdes errinf(qstate, reason); 501238106Sdes errinf_rrset(qstate, s); 502238106Sdes errinf_origin(qstate, qstate->reply_origin); 503238106Sdes chase_reply->security = sec_status_bogus; 504238106Sdes return 0; 505238106Sdes } 506238106Sdes } 507238106Sdes 508238106Sdes /* attempt to validate the ADDITIONAL section rrsets */ 509238106Sdes if(!ve->clean_additional) 510238106Sdes return 1; 511238106Sdes for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets; 512238106Sdes i<chase_reply->rrset_count; i++) { 513238106Sdes s = chase_reply->rrsets[i]; 514238106Sdes /* only validate rrs that have signatures with the key */ 515238106Sdes /* leave others unchecked, those get removed later on too */ 516238106Sdes val_find_rrset_signer(s, &sname, &slen); 517238106Sdes if(sname && query_dname_compare(sname, key_entry->name)==0) 518238106Sdes (void)val_verify_rrset_entry(env, ve, s, key_entry, 519238106Sdes &reason); 520238106Sdes /* the additional section can fail to be secure, 521238106Sdes * it is optional, check signature in case we need 522238106Sdes * to clean the additional section later. */ 523238106Sdes } 524238106Sdes 525238106Sdes return 1; 526238106Sdes} 527238106Sdes 528238106Sdes/** 529238106Sdes * Detect wrong truncated response (say from BIND 9.6.1 that is forwarding 530238106Sdes * and saw the NS record without signatures from a referral). 531238106Sdes * The positive response has a mangled authority section. 532238106Sdes * Remove that authority section and the additional section. 533238106Sdes * @param rep: reply 534238106Sdes * @return true if a wrongly truncated response. 535238106Sdes */ 536238106Sdesstatic int 537238106Sdesdetect_wrongly_truncated(struct reply_info* rep) 538238106Sdes{ 539238106Sdes size_t i; 540238106Sdes /* only NS in authority, and it is bogus */ 541238106Sdes if(rep->ns_numrrsets != 1 || rep->an_numrrsets == 0) 542238106Sdes return 0; 543238106Sdes if(ntohs(rep->rrsets[ rep->an_numrrsets ]->rk.type) != LDNS_RR_TYPE_NS) 544238106Sdes return 0; 545238106Sdes if(((struct packed_rrset_data*)rep->rrsets[ rep->an_numrrsets ] 546238106Sdes ->entry.data)->security == sec_status_secure) 547238106Sdes return 0; 548238106Sdes /* answer section is present and secure */ 549238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 550238106Sdes if(((struct packed_rrset_data*)rep->rrsets[ i ] 551238106Sdes ->entry.data)->security != sec_status_secure) 552238106Sdes return 0; 553238106Sdes } 554238106Sdes verbose(VERB_ALGO, "truncating to minimal response"); 555238106Sdes return 1; 556238106Sdes} 557238106Sdes 558238106Sdes 559238106Sdes/** 560238106Sdes * Given a "positive" response -- a response that contains an answer to the 561238106Sdes * question, and no CNAME chain, validate this response. 562238106Sdes * 563238106Sdes * The answer and authority RRsets must already be verified as secure. 564238106Sdes * 565238106Sdes * @param env: module env for verify. 566238106Sdes * @param ve: validator env for verify. 567238106Sdes * @param qchase: query that was made. 568238106Sdes * @param chase_reply: answer to that query to validate. 569238106Sdes * @param kkey: the key entry, which is trusted, and which matches 570238106Sdes * the signer of the answer. The key entry isgood(). 571238106Sdes */ 572238106Sdesstatic void 573238106Sdesvalidate_positive_response(struct module_env* env, struct val_env* ve, 574238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 575238106Sdes struct key_entry_key* kkey) 576238106Sdes{ 577238106Sdes uint8_t* wc = NULL; 578238106Sdes int wc_NSEC_ok = 0; 579238106Sdes int nsec3s_seen = 0; 580238106Sdes size_t i; 581238106Sdes struct ub_packed_rrset_key* s; 582238106Sdes 583238106Sdes /* validate the ANSWER section - this will be the answer itself */ 584238106Sdes for(i=0; i<chase_reply->an_numrrsets; i++) { 585238106Sdes s = chase_reply->rrsets[i]; 586238106Sdes 587238106Sdes /* Check to see if the rrset is the result of a wildcard 588238106Sdes * expansion. If so, an additional check will need to be 589238106Sdes * made in the authority section. */ 590238106Sdes if(!val_rrset_wildcard(s, &wc)) { 591238106Sdes log_nametypeclass(VERB_QUERY, "Positive response has " 592238106Sdes "inconsistent wildcard sigs:", s->rk.dname, 593238106Sdes ntohs(s->rk.type), ntohs(s->rk.rrset_class)); 594238106Sdes chase_reply->security = sec_status_bogus; 595238106Sdes return; 596238106Sdes } 597238106Sdes } 598238106Sdes 599238106Sdes /* validate the AUTHORITY section as well - this will generally be 600238106Sdes * the NS rrset (which could be missing, no problem) */ 601238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 602238106Sdes chase_reply->ns_numrrsets; i++) { 603238106Sdes s = chase_reply->rrsets[i]; 604238106Sdes 605238106Sdes /* If this is a positive wildcard response, and we have a 606238106Sdes * (just verified) NSEC record, try to use it to 1) prove 607238106Sdes * that qname doesn't exist and 2) that the correct wildcard 608238106Sdes * was used. */ 609238106Sdes if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 610238106Sdes if(val_nsec_proves_positive_wildcard(s, qchase, wc)) { 611238106Sdes wc_NSEC_ok = 1; 612238106Sdes } 613238106Sdes /* if not, continue looking for proof */ 614238106Sdes } 615238106Sdes 616238106Sdes /* Otherwise, if this is a positive wildcard response and 617238106Sdes * we have NSEC3 records */ 618238106Sdes if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { 619238106Sdes nsec3s_seen = 1; 620238106Sdes } 621238106Sdes } 622238106Sdes 623238106Sdes /* If this was a positive wildcard response that we haven't already 624238106Sdes * proven, and we have NSEC3 records, try to prove it using the NSEC3 625238106Sdes * records. */ 626238106Sdes if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { 627238106Sdes enum sec_status sec = nsec3_prove_wildcard(env, ve, 628238106Sdes chase_reply->rrsets+chase_reply->an_numrrsets, 629238106Sdes chase_reply->ns_numrrsets, qchase, kkey, wc); 630238106Sdes if(sec == sec_status_insecure) { 631238106Sdes verbose(VERB_ALGO, "Positive wildcard response is " 632238106Sdes "insecure"); 633238106Sdes chase_reply->security = sec_status_insecure; 634238106Sdes return; 635238106Sdes } else if(sec == sec_status_secure) 636238106Sdes wc_NSEC_ok = 1; 637238106Sdes } 638238106Sdes 639238106Sdes /* If after all this, we still haven't proven the positive wildcard 640238106Sdes * response, fail. */ 641238106Sdes if(wc != NULL && !wc_NSEC_ok) { 642238106Sdes verbose(VERB_QUERY, "positive response was wildcard " 643238106Sdes "expansion and did not prove original data " 644238106Sdes "did not exist"); 645238106Sdes chase_reply->security = sec_status_bogus; 646238106Sdes return; 647238106Sdes } 648238106Sdes 649238106Sdes verbose(VERB_ALGO, "Successfully validated positive response"); 650238106Sdes chase_reply->security = sec_status_secure; 651238106Sdes} 652238106Sdes 653238106Sdes/** 654238106Sdes * Validate a NOERROR/NODATA signed response -- a response that has a 655238106Sdes * NOERROR Rcode but no ANSWER section RRsets. This consists of making 656238106Sdes * certain that the authority section NSEC/NSEC3s proves that the qname 657238106Sdes * does exist and the qtype doesn't. 658238106Sdes * 659238106Sdes * The answer and authority RRsets must already be verified as secure. 660238106Sdes * 661238106Sdes * @param env: module env for verify. 662238106Sdes * @param ve: validator env for verify. 663238106Sdes * @param qchase: query that was made. 664238106Sdes * @param chase_reply: answer to that query to validate. 665238106Sdes * @param kkey: the key entry, which is trusted, and which matches 666238106Sdes * the signer of the answer. The key entry isgood(). 667238106Sdes */ 668238106Sdesstatic void 669238106Sdesvalidate_nodata_response(struct module_env* env, struct val_env* ve, 670238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 671238106Sdes struct key_entry_key* kkey) 672238106Sdes{ 673238106Sdes /* Since we are here, there must be nothing in the ANSWER section to 674238106Sdes * validate. */ 675238106Sdes /* (Note: CNAME/DNAME responses will not directly get here -- 676238106Sdes * instead, they are chased down into indiviual CNAME validations, 677238106Sdes * and at the end of the cname chain a POSITIVE, or CNAME_NOANSWER 678238106Sdes * validation.) */ 679238106Sdes 680238106Sdes /* validate the AUTHORITY section */ 681238106Sdes int has_valid_nsec = 0; /* If true, then the NODATA has been proven.*/ 682238106Sdes uint8_t* ce = NULL; /* for wildcard nodata responses. This is the 683238106Sdes proven closest encloser. */ 684238106Sdes uint8_t* wc = NULL; /* for wildcard nodata responses. wildcard nsec */ 685238106Sdes int nsec3s_seen = 0; /* nsec3s seen */ 686238106Sdes struct ub_packed_rrset_key* s; 687238106Sdes size_t i; 688238106Sdes 689238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 690238106Sdes chase_reply->ns_numrrsets; i++) { 691238106Sdes s = chase_reply->rrsets[i]; 692238106Sdes /* If we encounter an NSEC record, try to use it to prove 693238106Sdes * NODATA. 694238106Sdes * This needs to handle the ENT NODATA case. */ 695238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 696238106Sdes if(nsec_proves_nodata(s, qchase, &wc)) { 697238106Sdes has_valid_nsec = 1; 698238106Sdes /* sets wc-encloser if wildcard applicable */ 699238106Sdes } 700238106Sdes if(val_nsec_proves_name_error(s, qchase->qname)) { 701238106Sdes ce = nsec_closest_encloser(qchase->qname, s); 702238106Sdes } 703238106Sdes if(val_nsec_proves_insecuredelegation(s, qchase)) { 704238106Sdes verbose(VERB_ALGO, "delegation is insecure"); 705238106Sdes chase_reply->security = sec_status_insecure; 706238106Sdes return; 707238106Sdes } 708238106Sdes } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { 709238106Sdes nsec3s_seen = 1; 710238106Sdes } 711238106Sdes } 712238106Sdes 713238106Sdes /* check to see if we have a wildcard NODATA proof. */ 714238106Sdes 715238106Sdes /* The wildcard NODATA is 1 NSEC proving that qname does not exist 716238106Sdes * (and also proving what the closest encloser is), and 1 NSEC 717238106Sdes * showing the matching wildcard, which must be *.closest_encloser. */ 718238106Sdes if(wc && !ce) 719238106Sdes has_valid_nsec = 0; 720238106Sdes else if(wc && ce) { 721238106Sdes if(query_dname_compare(wc, ce) != 0) { 722238106Sdes has_valid_nsec = 0; 723238106Sdes } 724238106Sdes } 725238106Sdes 726238106Sdes if(!has_valid_nsec && nsec3s_seen) { 727238106Sdes enum sec_status sec = nsec3_prove_nodata(env, ve, 728238106Sdes chase_reply->rrsets+chase_reply->an_numrrsets, 729238106Sdes chase_reply->ns_numrrsets, qchase, kkey); 730238106Sdes if(sec == sec_status_insecure) { 731238106Sdes verbose(VERB_ALGO, "NODATA response is insecure"); 732238106Sdes chase_reply->security = sec_status_insecure; 733238106Sdes return; 734238106Sdes } else if(sec == sec_status_secure) 735238106Sdes has_valid_nsec = 1; 736238106Sdes } 737238106Sdes 738238106Sdes if(!has_valid_nsec) { 739238106Sdes verbose(VERB_QUERY, "NODATA response failed to prove NODATA " 740238106Sdes "status with NSEC/NSEC3"); 741238106Sdes if(verbosity >= VERB_ALGO) 742238106Sdes log_dns_msg("Failed NODATA", qchase, chase_reply); 743238106Sdes chase_reply->security = sec_status_bogus; 744238106Sdes return; 745238106Sdes } 746238106Sdes 747238106Sdes verbose(VERB_ALGO, "successfully validated NODATA response."); 748238106Sdes chase_reply->security = sec_status_secure; 749238106Sdes} 750238106Sdes 751238106Sdes/** 752238106Sdes * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN 753238106Sdes * Rcode. 754238106Sdes * This consists of making certain that the authority section NSEC proves 755238106Sdes * that the qname doesn't exist and the covering wildcard also doesn't exist.. 756238106Sdes * 757238106Sdes * The answer and authority RRsets must have already been verified as secure. 758238106Sdes * 759238106Sdes * @param env: module env for verify. 760238106Sdes * @param ve: validator env for verify. 761238106Sdes * @param qchase: query that was made. 762238106Sdes * @param chase_reply: answer to that query to validate. 763238106Sdes * @param kkey: the key entry, which is trusted, and which matches 764238106Sdes * the signer of the answer. The key entry isgood(). 765269257Sdes * @param rcode: adjusted RCODE, in case of RCODE/proof mismatch leniency. 766238106Sdes */ 767238106Sdesstatic void 768238106Sdesvalidate_nameerror_response(struct module_env* env, struct val_env* ve, 769238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 770269257Sdes struct key_entry_key* kkey, int* rcode) 771238106Sdes{ 772238106Sdes int has_valid_nsec = 0; 773238106Sdes int has_valid_wnsec = 0; 774238106Sdes int nsec3s_seen = 0; 775238106Sdes struct ub_packed_rrset_key* s; 776238106Sdes size_t i; 777238106Sdes 778238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 779238106Sdes chase_reply->ns_numrrsets; i++) { 780238106Sdes s = chase_reply->rrsets[i]; 781238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 782238106Sdes if(val_nsec_proves_name_error(s, qchase->qname)) 783238106Sdes has_valid_nsec = 1; 784238106Sdes if(val_nsec_proves_no_wc(s, qchase->qname, 785238106Sdes qchase->qname_len)) 786238106Sdes has_valid_wnsec = 1; 787238106Sdes if(val_nsec_proves_insecuredelegation(s, qchase)) { 788238106Sdes verbose(VERB_ALGO, "delegation is insecure"); 789238106Sdes chase_reply->security = sec_status_insecure; 790238106Sdes return; 791238106Sdes } 792238106Sdes } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) 793238106Sdes nsec3s_seen = 1; 794238106Sdes } 795238106Sdes 796238106Sdes if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) { 797238106Sdes /* use NSEC3 proof, both answer and auth rrsets, in case 798238106Sdes * NSEC3s end up in the answer (due to qtype=NSEC3 or so) */ 799238106Sdes chase_reply->security = nsec3_prove_nameerror(env, ve, 800238106Sdes chase_reply->rrsets, chase_reply->an_numrrsets+ 801238106Sdes chase_reply->ns_numrrsets, qchase, kkey); 802238106Sdes if(chase_reply->security != sec_status_secure) { 803238106Sdes verbose(VERB_QUERY, "NameError response failed nsec, " 804238106Sdes "nsec3 proof was %s", sec_status_to_string( 805238106Sdes chase_reply->security)); 806238106Sdes return; 807238106Sdes } 808238106Sdes has_valid_nsec = 1; 809238106Sdes has_valid_wnsec = 1; 810238106Sdes } 811238106Sdes 812238106Sdes /* If the message fails to prove either condition, it is bogus. */ 813238106Sdes if(!has_valid_nsec) { 814238106Sdes verbose(VERB_QUERY, "NameError response has failed to prove: " 815238106Sdes "qname does not exist"); 816238106Sdes chase_reply->security = sec_status_bogus; 817269257Sdes /* Be lenient with RCODE in NSEC NameError responses */ 818269257Sdes validate_nodata_response(env, ve, qchase, chase_reply, kkey); 819269257Sdes if (chase_reply->security == sec_status_secure) 820269257Sdes *rcode = LDNS_RCODE_NOERROR; 821238106Sdes return; 822238106Sdes } 823238106Sdes 824238106Sdes if(!has_valid_wnsec) { 825238106Sdes verbose(VERB_QUERY, "NameError response has failed to prove: " 826238106Sdes "covering wildcard does not exist"); 827238106Sdes chase_reply->security = sec_status_bogus; 828269257Sdes /* Be lenient with RCODE in NSEC NameError responses */ 829269257Sdes validate_nodata_response(env, ve, qchase, chase_reply, kkey); 830269257Sdes if (chase_reply->security == sec_status_secure) 831269257Sdes *rcode = LDNS_RCODE_NOERROR; 832238106Sdes return; 833238106Sdes } 834238106Sdes 835238106Sdes /* Otherwise, we consider the message secure. */ 836238106Sdes verbose(VERB_ALGO, "successfully validated NAME ERROR response."); 837238106Sdes chase_reply->security = sec_status_secure; 838238106Sdes} 839238106Sdes 840238106Sdes/** 841238106Sdes * Given a referral response, validate rrsets and take least trusted rrset 842238106Sdes * as the current validation status. 843238106Sdes * 844238106Sdes * Note that by the time this method is called, the process of finding the 845238106Sdes * trusted DNSKEY rrset that signs this response must already have been 846238106Sdes * completed. 847238106Sdes * 848238106Sdes * @param chase_reply: answer to validate. 849238106Sdes */ 850238106Sdesstatic void 851238106Sdesvalidate_referral_response(struct reply_info* chase_reply) 852238106Sdes{ 853238106Sdes size_t i; 854238106Sdes enum sec_status s; 855238106Sdes /* message security equals lowest rrset security */ 856238106Sdes chase_reply->security = sec_status_secure; 857238106Sdes for(i=0; i<chase_reply->rrset_count; i++) { 858238106Sdes s = ((struct packed_rrset_data*)chase_reply->rrsets[i] 859238106Sdes ->entry.data)->security; 860238106Sdes if(s < chase_reply->security) 861238106Sdes chase_reply->security = s; 862238106Sdes } 863238106Sdes verbose(VERB_ALGO, "validated part of referral response as %s", 864238106Sdes sec_status_to_string(chase_reply->security)); 865238106Sdes} 866238106Sdes 867238106Sdes/** 868238106Sdes * Given an "ANY" response -- a response that contains an answer to a 869238106Sdes * qtype==ANY question, with answers. This does no checking that all 870238106Sdes * types are present. 871238106Sdes * 872238106Sdes * NOTE: it may be possible to get parent-side delegation point records 873238106Sdes * here, which won't all be signed. Right now, this routine relies on the 874238106Sdes * upstream iterative resolver to not return these responses -- instead 875238106Sdes * treating them as referrals. 876238106Sdes * 877238106Sdes * NOTE: RFC 4035 is silent on this issue, so this may change upon 878238106Sdes * clarification. Clarification draft -05 says to not check all types are 879238106Sdes * present. 880238106Sdes * 881238106Sdes * Note that by the time this method is called, the process of finding the 882238106Sdes * trusted DNSKEY rrset that signs this response must already have been 883238106Sdes * completed. 884238106Sdes * 885238106Sdes * @param env: module env for verify. 886238106Sdes * @param ve: validator env for verify. 887238106Sdes * @param qchase: query that was made. 888238106Sdes * @param chase_reply: answer to that query to validate. 889238106Sdes * @param kkey: the key entry, which is trusted, and which matches 890238106Sdes * the signer of the answer. The key entry isgood(). 891238106Sdes */ 892238106Sdesstatic void 893238106Sdesvalidate_any_response(struct module_env* env, struct val_env* ve, 894238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 895238106Sdes struct key_entry_key* kkey) 896238106Sdes{ 897238106Sdes /* all answer and auth rrsets already verified */ 898238106Sdes /* but check if a wildcard response is given, then check NSEC/NSEC3 899238106Sdes * for qname denial to see if wildcard is applicable */ 900238106Sdes uint8_t* wc = NULL; 901238106Sdes int wc_NSEC_ok = 0; 902238106Sdes int nsec3s_seen = 0; 903238106Sdes size_t i; 904238106Sdes struct ub_packed_rrset_key* s; 905238106Sdes 906238106Sdes if(qchase->qtype != LDNS_RR_TYPE_ANY) { 907238106Sdes log_err("internal error: ANY validation called for non-ANY"); 908238106Sdes chase_reply->security = sec_status_bogus; 909238106Sdes return; 910238106Sdes } 911238106Sdes 912238106Sdes /* validate the ANSWER section - this will be the answer itself */ 913238106Sdes for(i=0; i<chase_reply->an_numrrsets; i++) { 914238106Sdes s = chase_reply->rrsets[i]; 915238106Sdes 916238106Sdes /* Check to see if the rrset is the result of a wildcard 917238106Sdes * expansion. If so, an additional check will need to be 918238106Sdes * made in the authority section. */ 919238106Sdes if(!val_rrset_wildcard(s, &wc)) { 920238106Sdes log_nametypeclass(VERB_QUERY, "Positive ANY response" 921238106Sdes " has inconsistent wildcard sigs:", 922238106Sdes s->rk.dname, ntohs(s->rk.type), 923238106Sdes ntohs(s->rk.rrset_class)); 924238106Sdes chase_reply->security = sec_status_bogus; 925238106Sdes return; 926238106Sdes } 927238106Sdes } 928238106Sdes 929238106Sdes /* if it was a wildcard, check for NSEC/NSEC3s in both answer 930238106Sdes * and authority sections (NSEC may be moved to the ANSWER section) */ 931238106Sdes if(wc != NULL) 932238106Sdes for(i=0; i<chase_reply->an_numrrsets+chase_reply->ns_numrrsets; 933238106Sdes i++) { 934238106Sdes s = chase_reply->rrsets[i]; 935238106Sdes 936238106Sdes /* If this is a positive wildcard response, and we have a 937238106Sdes * (just verified) NSEC record, try to use it to 1) prove 938238106Sdes * that qname doesn't exist and 2) that the correct wildcard 939238106Sdes * was used. */ 940238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 941238106Sdes if(val_nsec_proves_positive_wildcard(s, qchase, wc)) { 942238106Sdes wc_NSEC_ok = 1; 943238106Sdes } 944238106Sdes /* if not, continue looking for proof */ 945238106Sdes } 946238106Sdes 947238106Sdes /* Otherwise, if this is a positive wildcard response and 948238106Sdes * we have NSEC3 records */ 949238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { 950238106Sdes nsec3s_seen = 1; 951238106Sdes } 952238106Sdes } 953238106Sdes 954238106Sdes /* If this was a positive wildcard response that we haven't already 955238106Sdes * proven, and we have NSEC3 records, try to prove it using the NSEC3 956238106Sdes * records. */ 957238106Sdes if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { 958238106Sdes /* look both in answer and auth section for NSEC3s */ 959238106Sdes enum sec_status sec = nsec3_prove_wildcard(env, ve, 960238106Sdes chase_reply->rrsets, 961238106Sdes chase_reply->an_numrrsets+chase_reply->ns_numrrsets, 962238106Sdes qchase, kkey, wc); 963238106Sdes if(sec == sec_status_insecure) { 964238106Sdes verbose(VERB_ALGO, "Positive ANY wildcard response is " 965238106Sdes "insecure"); 966238106Sdes chase_reply->security = sec_status_insecure; 967238106Sdes return; 968238106Sdes } else if(sec == sec_status_secure) 969238106Sdes wc_NSEC_ok = 1; 970238106Sdes } 971238106Sdes 972238106Sdes /* If after all this, we still haven't proven the positive wildcard 973238106Sdes * response, fail. */ 974238106Sdes if(wc != NULL && !wc_NSEC_ok) { 975238106Sdes verbose(VERB_QUERY, "positive ANY response was wildcard " 976238106Sdes "expansion and did not prove original data " 977238106Sdes "did not exist"); 978238106Sdes chase_reply->security = sec_status_bogus; 979238106Sdes return; 980238106Sdes } 981238106Sdes 982238106Sdes verbose(VERB_ALGO, "Successfully validated positive ANY response"); 983238106Sdes chase_reply->security = sec_status_secure; 984238106Sdes} 985238106Sdes 986238106Sdes/** 987238106Sdes * Validate CNAME response, or DNAME+CNAME. 988238106Sdes * This is just like a positive proof, except that this is about a 989238106Sdes * DNAME+CNAME. Possible wildcard proof. 990238106Sdes * Difference with positive proof is that this routine refuses 991238106Sdes * wildcarded DNAMEs. 992238106Sdes * 993238106Sdes * The answer and authority rrsets must already be verified as secure. 994238106Sdes * 995238106Sdes * @param env: module env for verify. 996238106Sdes * @param ve: validator env for verify. 997238106Sdes * @param qchase: query that was made. 998238106Sdes * @param chase_reply: answer to that query to validate. 999238106Sdes * @param kkey: the key entry, which is trusted, and which matches 1000238106Sdes * the signer of the answer. The key entry isgood(). 1001238106Sdes */ 1002238106Sdesstatic void 1003238106Sdesvalidate_cname_response(struct module_env* env, struct val_env* ve, 1004238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 1005238106Sdes struct key_entry_key* kkey) 1006238106Sdes{ 1007238106Sdes uint8_t* wc = NULL; 1008238106Sdes int wc_NSEC_ok = 0; 1009238106Sdes int nsec3s_seen = 0; 1010238106Sdes size_t i; 1011238106Sdes struct ub_packed_rrset_key* s; 1012238106Sdes 1013238106Sdes /* validate the ANSWER section - this will be the CNAME (+DNAME) */ 1014238106Sdes for(i=0; i<chase_reply->an_numrrsets; i++) { 1015238106Sdes s = chase_reply->rrsets[i]; 1016238106Sdes 1017238106Sdes /* Check to see if the rrset is the result of a wildcard 1018238106Sdes * expansion. If so, an additional check will need to be 1019238106Sdes * made in the authority section. */ 1020238106Sdes if(!val_rrset_wildcard(s, &wc)) { 1021238106Sdes log_nametypeclass(VERB_QUERY, "Cname response has " 1022238106Sdes "inconsistent wildcard sigs:", s->rk.dname, 1023238106Sdes ntohs(s->rk.type), ntohs(s->rk.rrset_class)); 1024238106Sdes chase_reply->security = sec_status_bogus; 1025238106Sdes return; 1026238106Sdes } 1027238106Sdes 1028238106Sdes /* Refuse wildcarded DNAMEs rfc 4597. 1029238106Sdes * Do not follow a wildcarded DNAME because 1030238106Sdes * its synthesized CNAME expansion is underdefined */ 1031238106Sdes if(qchase->qtype != LDNS_RR_TYPE_DNAME && 1032238106Sdes ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME && wc) { 1033238106Sdes log_nametypeclass(VERB_QUERY, "cannot validate a " 1034238106Sdes "wildcarded DNAME:", s->rk.dname, 1035238106Sdes ntohs(s->rk.type), ntohs(s->rk.rrset_class)); 1036238106Sdes chase_reply->security = sec_status_bogus; 1037238106Sdes return; 1038238106Sdes } 1039249141Sdes 1040249141Sdes /* If we have found a CNAME, stop looking for one. 1041249141Sdes * The iterator has placed the CNAME chain in correct 1042249141Sdes * order. */ 1043249141Sdes if (ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) { 1044249141Sdes break; 1045249141Sdes } 1046238106Sdes } 1047238106Sdes 1048238106Sdes /* AUTHORITY section */ 1049238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 1050238106Sdes chase_reply->ns_numrrsets; i++) { 1051238106Sdes s = chase_reply->rrsets[i]; 1052238106Sdes 1053238106Sdes /* If this is a positive wildcard response, and we have a 1054238106Sdes * (just verified) NSEC record, try to use it to 1) prove 1055238106Sdes * that qname doesn't exist and 2) that the correct wildcard 1056238106Sdes * was used. */ 1057238106Sdes if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 1058238106Sdes if(val_nsec_proves_positive_wildcard(s, qchase, wc)) { 1059238106Sdes wc_NSEC_ok = 1; 1060238106Sdes } 1061238106Sdes /* if not, continue looking for proof */ 1062238106Sdes } 1063238106Sdes 1064238106Sdes /* Otherwise, if this is a positive wildcard response and 1065238106Sdes * we have NSEC3 records */ 1066238106Sdes if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { 1067238106Sdes nsec3s_seen = 1; 1068238106Sdes } 1069238106Sdes } 1070238106Sdes 1071238106Sdes /* If this was a positive wildcard response that we haven't already 1072238106Sdes * proven, and we have NSEC3 records, try to prove it using the NSEC3 1073238106Sdes * records. */ 1074238106Sdes if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { 1075238106Sdes enum sec_status sec = nsec3_prove_wildcard(env, ve, 1076238106Sdes chase_reply->rrsets+chase_reply->an_numrrsets, 1077238106Sdes chase_reply->ns_numrrsets, qchase, kkey, wc); 1078238106Sdes if(sec == sec_status_insecure) { 1079238106Sdes verbose(VERB_ALGO, "wildcard CNAME response is " 1080238106Sdes "insecure"); 1081238106Sdes chase_reply->security = sec_status_insecure; 1082238106Sdes return; 1083238106Sdes } else if(sec == sec_status_secure) 1084238106Sdes wc_NSEC_ok = 1; 1085238106Sdes } 1086238106Sdes 1087238106Sdes /* If after all this, we still haven't proven the positive wildcard 1088238106Sdes * response, fail. */ 1089238106Sdes if(wc != NULL && !wc_NSEC_ok) { 1090238106Sdes verbose(VERB_QUERY, "CNAME response was wildcard " 1091238106Sdes "expansion and did not prove original data " 1092238106Sdes "did not exist"); 1093238106Sdes chase_reply->security = sec_status_bogus; 1094238106Sdes return; 1095238106Sdes } 1096238106Sdes 1097238106Sdes verbose(VERB_ALGO, "Successfully validated CNAME response"); 1098238106Sdes chase_reply->security = sec_status_secure; 1099238106Sdes} 1100238106Sdes 1101238106Sdes/** 1102238106Sdes * Validate CNAME NOANSWER response, no more data after a CNAME chain. 1103238106Sdes * This can be a NODATA or a NAME ERROR case, but not both at the same time. 1104238106Sdes * We don't know because the rcode has been set to NOERROR by the CNAME. 1105238106Sdes * 1106238106Sdes * The answer and authority rrsets must already be verified as secure. 1107238106Sdes * 1108238106Sdes * @param env: module env for verify. 1109238106Sdes * @param ve: validator env for verify. 1110238106Sdes * @param qchase: query that was made. 1111238106Sdes * @param chase_reply: answer to that query to validate. 1112238106Sdes * @param kkey: the key entry, which is trusted, and which matches 1113238106Sdes * the signer of the answer. The key entry isgood(). 1114238106Sdes */ 1115238106Sdesstatic void 1116238106Sdesvalidate_cname_noanswer_response(struct module_env* env, struct val_env* ve, 1117238106Sdes struct query_info* qchase, struct reply_info* chase_reply, 1118238106Sdes struct key_entry_key* kkey) 1119238106Sdes{ 1120238106Sdes int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/ 1121238106Sdes uint8_t* ce = NULL; /* for wildcard nodata responses. This is the 1122238106Sdes proven closest encloser. */ 1123238106Sdes uint8_t* wc = NULL; /* for wildcard nodata responses. wildcard nsec */ 1124238106Sdes int nxdomain_valid_nsec = 0; /* if true, namerror has been proven */ 1125238106Sdes int nxdomain_valid_wnsec = 0; 1126238106Sdes int nsec3s_seen = 0; /* nsec3s seen */ 1127238106Sdes struct ub_packed_rrset_key* s; 1128238106Sdes size_t i; 1129238106Sdes 1130238106Sdes /* the AUTHORITY section */ 1131238106Sdes for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+ 1132238106Sdes chase_reply->ns_numrrsets; i++) { 1133238106Sdes s = chase_reply->rrsets[i]; 1134238106Sdes 1135238106Sdes /* If we encounter an NSEC record, try to use it to prove 1136238106Sdes * NODATA. This needs to handle the ENT NODATA case. 1137238106Sdes * Also try to prove NAMEERROR, and absence of a wildcard */ 1138238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) { 1139238106Sdes if(nsec_proves_nodata(s, qchase, &wc)) { 1140238106Sdes nodata_valid_nsec = 1; 1141238106Sdes /* set wc encloser if wildcard applicable */ 1142238106Sdes } 1143238106Sdes if(val_nsec_proves_name_error(s, qchase->qname)) { 1144238106Sdes ce = nsec_closest_encloser(qchase->qname, s); 1145238106Sdes nxdomain_valid_nsec = 1; 1146238106Sdes } 1147238106Sdes if(val_nsec_proves_no_wc(s, qchase->qname, 1148238106Sdes qchase->qname_len)) 1149238106Sdes nxdomain_valid_wnsec = 1; 1150238106Sdes if(val_nsec_proves_insecuredelegation(s, qchase)) { 1151238106Sdes verbose(VERB_ALGO, "delegation is insecure"); 1152238106Sdes chase_reply->security = sec_status_insecure; 1153238106Sdes return; 1154238106Sdes } 1155238106Sdes } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { 1156238106Sdes nsec3s_seen = 1; 1157238106Sdes } 1158238106Sdes } 1159238106Sdes 1160238106Sdes /* check to see if we have a wildcard NODATA proof. */ 1161238106Sdes 1162238106Sdes /* The wildcard NODATA is 1 NSEC proving that qname does not exists 1163238106Sdes * (and also proving what the closest encloser is), and 1 NSEC 1164238106Sdes * showing the matching wildcard, which must be *.closest_encloser. */ 1165238106Sdes if(wc && !ce) 1166238106Sdes nodata_valid_nsec = 0; 1167238106Sdes else if(wc && ce) { 1168238106Sdes if(query_dname_compare(wc, ce) != 0) { 1169238106Sdes nodata_valid_nsec = 0; 1170238106Sdes } 1171238106Sdes } 1172238106Sdes if(nxdomain_valid_nsec && !nxdomain_valid_wnsec) { 1173238106Sdes /* name error is missing wildcard denial proof */ 1174238106Sdes nxdomain_valid_nsec = 0; 1175238106Sdes } 1176238106Sdes 1177238106Sdes if(nodata_valid_nsec && nxdomain_valid_nsec) { 1178238106Sdes verbose(VERB_QUERY, "CNAMEchain to noanswer proves that name " 1179238106Sdes "exists and not exists, bogus"); 1180238106Sdes chase_reply->security = sec_status_bogus; 1181238106Sdes return; 1182238106Sdes } 1183238106Sdes if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) { 1184238106Sdes int nodata; 1185238106Sdes enum sec_status sec = nsec3_prove_nxornodata(env, ve, 1186238106Sdes chase_reply->rrsets+chase_reply->an_numrrsets, 1187238106Sdes chase_reply->ns_numrrsets, qchase, kkey, &nodata); 1188238106Sdes if(sec == sec_status_insecure) { 1189238106Sdes verbose(VERB_ALGO, "CNAMEchain to noanswer response " 1190238106Sdes "is insecure"); 1191238106Sdes chase_reply->security = sec_status_insecure; 1192238106Sdes return; 1193238106Sdes } else if(sec == sec_status_secure) { 1194238106Sdes if(nodata) 1195238106Sdes nodata_valid_nsec = 1; 1196238106Sdes else nxdomain_valid_nsec = 1; 1197238106Sdes } 1198238106Sdes } 1199238106Sdes 1200238106Sdes if(!nodata_valid_nsec && !nxdomain_valid_nsec) { 1201238106Sdes verbose(VERB_QUERY, "CNAMEchain to noanswer response failed " 1202238106Sdes "to prove status with NSEC/NSEC3"); 1203238106Sdes if(verbosity >= VERB_ALGO) 1204238106Sdes log_dns_msg("Failed CNAMEnoanswer", qchase, chase_reply); 1205238106Sdes chase_reply->security = sec_status_bogus; 1206238106Sdes return; 1207238106Sdes } 1208238106Sdes 1209238106Sdes if(nodata_valid_nsec) 1210238106Sdes verbose(VERB_ALGO, "successfully validated CNAME chain to a " 1211238106Sdes "NODATA response."); 1212238106Sdes else verbose(VERB_ALGO, "successfully validated CNAME chain to a " 1213238106Sdes "NAMEERROR response."); 1214238106Sdes chase_reply->security = sec_status_secure; 1215238106Sdes} 1216238106Sdes 1217238106Sdes/** 1218238106Sdes * Process init state for validator. 1219238106Sdes * Process the INIT state. First tier responses start in the INIT state. 1220238106Sdes * This is where they are vetted for validation suitability, and the initial 1221238106Sdes * key search is done. 1222238106Sdes * 1223238106Sdes * Currently, events the come through this routine will be either promoted 1224238106Sdes * to FINISHED/CNAME_RESP (no validation needed), FINDKEY (next step to 1225238106Sdes * validation), or will be (temporarily) retired and a new priming request 1226238106Sdes * event will be generated. 1227238106Sdes * 1228238106Sdes * @param qstate: query state. 1229238106Sdes * @param vq: validator query state. 1230238106Sdes * @param ve: validator shared global environment. 1231238106Sdes * @param id: module id. 1232238106Sdes * @return true if the event should be processed further on return, false if 1233238106Sdes * not. 1234238106Sdes */ 1235238106Sdesstatic int 1236238106SdesprocessInit(struct module_qstate* qstate, struct val_qstate* vq, 1237238106Sdes struct val_env* ve, int id) 1238238106Sdes{ 1239238106Sdes uint8_t* lookup_name; 1240238106Sdes size_t lookup_len; 1241238106Sdes struct trust_anchor* anchor; 1242238106Sdes enum val_classification subtype = val_classify_response( 1243238106Sdes qstate->query_flags, &qstate->qinfo, &vq->qchase, 1244238106Sdes vq->orig_msg->rep, vq->rrset_skip); 1245238106Sdes if(vq->restart_count > VAL_MAX_RESTART_COUNT) { 1246238106Sdes verbose(VERB_ALGO, "restart count exceeded"); 1247238106Sdes return val_error(qstate, id); 1248238106Sdes } 1249238106Sdes verbose(VERB_ALGO, "validator classification %s", 1250238106Sdes val_classification_to_string(subtype)); 1251238106Sdes if(subtype == VAL_CLASS_REFERRAL && 1252238106Sdes vq->rrset_skip < vq->orig_msg->rep->rrset_count) { 1253238106Sdes /* referral uses the rrset name as qchase, to find keys for 1254238106Sdes * that rrset */ 1255238106Sdes vq->qchase.qname = vq->orig_msg->rep-> 1256238106Sdes rrsets[vq->rrset_skip]->rk.dname; 1257238106Sdes vq->qchase.qname_len = vq->orig_msg->rep-> 1258238106Sdes rrsets[vq->rrset_skip]->rk.dname_len; 1259238106Sdes vq->qchase.qtype = ntohs(vq->orig_msg->rep-> 1260238106Sdes rrsets[vq->rrset_skip]->rk.type); 1261238106Sdes vq->qchase.qclass = ntohs(vq->orig_msg->rep-> 1262238106Sdes rrsets[vq->rrset_skip]->rk.rrset_class); 1263238106Sdes } 1264238106Sdes lookup_name = vq->qchase.qname; 1265238106Sdes lookup_len = vq->qchase.qname_len; 1266238106Sdes /* for type DS look at the parent side for keys/trustanchor */ 1267238106Sdes /* also for NSEC not at apex */ 1268238106Sdes if(vq->qchase.qtype == LDNS_RR_TYPE_DS || 1269238106Sdes (vq->qchase.qtype == LDNS_RR_TYPE_NSEC && 1270238106Sdes vq->orig_msg->rep->rrset_count > vq->rrset_skip && 1271238106Sdes ntohs(vq->orig_msg->rep->rrsets[vq->rrset_skip]->rk.type) == 1272238106Sdes LDNS_RR_TYPE_NSEC && 1273238106Sdes !(vq->orig_msg->rep->rrsets[vq->rrset_skip]-> 1274238106Sdes rk.flags&PACKED_RRSET_NSEC_AT_APEX))) { 1275238106Sdes dname_remove_label(&lookup_name, &lookup_len); 1276238106Sdes } 1277238106Sdes 1278238106Sdes val_mark_indeterminate(vq->chase_reply, qstate->env->anchors, 1279238106Sdes qstate->env->rrset_cache, qstate->env); 1280238106Sdes vq->key_entry = NULL; 1281238106Sdes vq->empty_DS_name = NULL; 1282238106Sdes vq->ds_rrset = 0; 1283238106Sdes anchor = anchors_lookup(qstate->env->anchors, 1284238106Sdes lookup_name, lookup_len, vq->qchase.qclass); 1285238106Sdes 1286238106Sdes /* Determine the signer/lookup name */ 1287238106Sdes val_find_signer(subtype, &vq->qchase, vq->orig_msg->rep, 1288238106Sdes vq->rrset_skip, &vq->signer_name, &vq->signer_len); 1289238106Sdes if(vq->signer_name != NULL && 1290238106Sdes !dname_subdomain_c(lookup_name, vq->signer_name)) { 1291238106Sdes log_nametypeclass(VERB_ALGO, "this signer name is not a parent " 1292238106Sdes "of lookupname, omitted", vq->signer_name, 0, 0); 1293238106Sdes vq->signer_name = NULL; 1294238106Sdes } 1295238106Sdes if(vq->signer_name == NULL) { 1296238106Sdes log_nametypeclass(VERB_ALGO, "no signer, using", lookup_name, 1297238106Sdes 0, 0); 1298238106Sdes } else { 1299238106Sdes lookup_name = vq->signer_name; 1300238106Sdes lookup_len = vq->signer_len; 1301238106Sdes log_nametypeclass(VERB_ALGO, "signer is", lookup_name, 0, 0); 1302238106Sdes } 1303238106Sdes 1304238106Sdes /* for NXDOMAIN it could be signed by a parent of the trust anchor */ 1305238106Sdes if(subtype == VAL_CLASS_NAMEERROR && vq->signer_name && 1306238106Sdes anchor && dname_strict_subdomain_c(anchor->name, lookup_name)){ 1307238106Sdes lock_basic_unlock(&anchor->lock); 1308238106Sdes anchor = anchors_lookup(qstate->env->anchors, 1309238106Sdes lookup_name, lookup_len, vq->qchase.qclass); 1310238106Sdes if(!anchor) { /* unsigned parent denies anchor*/ 1311238106Sdes verbose(VERB_QUERY, "unsigned parent zone denies" 1312238106Sdes " trust anchor, indeterminate"); 1313238106Sdes vq->chase_reply->security = sec_status_indeterminate; 1314238106Sdes vq->state = VAL_FINISHED_STATE; 1315238106Sdes return 1; 1316238106Sdes } 1317238106Sdes verbose(VERB_ALGO, "trust anchor NXDOMAIN by signed parent"); 1318238106Sdes } else if(subtype == VAL_CLASS_POSITIVE && 1319238106Sdes qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY && 1320238106Sdes query_dname_compare(lookup_name, qstate->qinfo.qname) == 0) { 1321238106Sdes /* is a DNSKEY so lookup a bit higher since we want to 1322238106Sdes * get it from a parent or from trustanchor */ 1323238106Sdes dname_remove_label(&lookup_name, &lookup_len); 1324238106Sdes } 1325238106Sdes 1326238106Sdes if(vq->rrset_skip > 0 || subtype == VAL_CLASS_CNAME || 1327238106Sdes subtype == VAL_CLASS_REFERRAL) { 1328238106Sdes /* extract this part of orig_msg into chase_reply for 1329238106Sdes * the eventual VALIDATE stage */ 1330238106Sdes val_fill_reply(vq->chase_reply, vq->orig_msg->rep, 1331238106Sdes vq->rrset_skip, lookup_name, lookup_len, 1332238106Sdes vq->signer_name); 1333238106Sdes if(verbosity >= VERB_ALGO) 1334238106Sdes log_dns_msg("chased extract", &vq->qchase, 1335238106Sdes vq->chase_reply); 1336238106Sdes } 1337238106Sdes 1338238106Sdes vq->key_entry = key_cache_obtain(ve->kcache, lookup_name, lookup_len, 1339238106Sdes vq->qchase.qclass, qstate->region, *qstate->env->now); 1340238106Sdes 1341238106Sdes /* there is no key(from DLV) and no trust anchor */ 1342238106Sdes if(vq->key_entry == NULL && anchor == NULL) { 1343238106Sdes /*response isn't under a trust anchor, so we cannot validate.*/ 1344238106Sdes vq->chase_reply->security = sec_status_indeterminate; 1345238106Sdes /* go to finished state to cache this result */ 1346238106Sdes vq->state = VAL_FINISHED_STATE; 1347238106Sdes return 1; 1348238106Sdes } 1349238106Sdes /* if not key, or if keyentry is *above* the trustanchor, i.e. 1350238106Sdes * the keyentry is based on another (higher) trustanchor */ 1351238106Sdes else if(vq->key_entry == NULL || (anchor && 1352238106Sdes dname_strict_subdomain_c(anchor->name, vq->key_entry->name))) { 1353238106Sdes /* trust anchor is an 'unsigned' trust anchor */ 1354238106Sdes if(anchor && anchor->numDS == 0 && anchor->numDNSKEY == 0) { 1355238106Sdes vq->chase_reply->security = sec_status_insecure; 1356238106Sdes val_mark_insecure(vq->chase_reply, anchor->name, 1357238106Sdes qstate->env->rrset_cache, qstate->env); 1358238106Sdes lock_basic_unlock(&anchor->lock); 1359238106Sdes vq->dlv_checked=1; /* skip DLV check */ 1360238106Sdes /* go to finished state to cache this result */ 1361238106Sdes vq->state = VAL_FINISHED_STATE; 1362238106Sdes return 1; 1363238106Sdes } 1364238106Sdes /* fire off a trust anchor priming query. */ 1365238106Sdes verbose(VERB_DETAIL, "prime trust anchor"); 1366238106Sdes if(!prime_trust_anchor(qstate, vq, id, anchor)) { 1367238106Sdes lock_basic_unlock(&anchor->lock); 1368238106Sdes return val_error(qstate, id); 1369238106Sdes } 1370238106Sdes lock_basic_unlock(&anchor->lock); 1371238106Sdes /* and otherwise, don't continue processing this event. 1372238106Sdes * (it will be reactivated when the priming query returns). */ 1373238106Sdes vq->state = VAL_FINDKEY_STATE; 1374238106Sdes return 0; 1375238106Sdes } 1376238106Sdes if(anchor) { 1377238106Sdes lock_basic_unlock(&anchor->lock); 1378238106Sdes } 1379238106Sdes 1380238106Sdes if(key_entry_isnull(vq->key_entry)) { 1381238106Sdes /* response is under a null key, so we cannot validate 1382238106Sdes * However, we do set the status to INSECURE, since it is 1383238106Sdes * essentially proven insecure. */ 1384238106Sdes vq->chase_reply->security = sec_status_insecure; 1385238106Sdes val_mark_insecure(vq->chase_reply, vq->key_entry->name, 1386238106Sdes qstate->env->rrset_cache, qstate->env); 1387238106Sdes /* go to finished state to cache this result */ 1388238106Sdes vq->state = VAL_FINISHED_STATE; 1389238106Sdes return 1; 1390238106Sdes } else if(key_entry_isbad(vq->key_entry)) { 1391238106Sdes /* key is bad, chain is bad, reply is bogus */ 1392238106Sdes errinf_dname(qstate, "key for validation", vq->key_entry->name); 1393238106Sdes errinf(qstate, "is marked as invalid"); 1394238106Sdes if(key_entry_get_reason(vq->key_entry)) { 1395238106Sdes errinf(qstate, "because of a previous"); 1396238106Sdes errinf(qstate, key_entry_get_reason(vq->key_entry)); 1397238106Sdes } 1398238106Sdes /* no retries, stop bothering the authority until timeout */ 1399238106Sdes vq->restart_count = VAL_MAX_RESTART_COUNT; 1400238106Sdes vq->chase_reply->security = sec_status_bogus; 1401238106Sdes vq->state = VAL_FINISHED_STATE; 1402238106Sdes return 1; 1403238106Sdes } 1404238106Sdes 1405238106Sdes /* otherwise, we have our "closest" cached key -- continue 1406238106Sdes * processing in the next state. */ 1407238106Sdes vq->state = VAL_FINDKEY_STATE; 1408238106Sdes return 1; 1409238106Sdes} 1410238106Sdes 1411238106Sdes/** 1412238106Sdes * Process the FINDKEY state. Generally this just calculates the next name 1413238106Sdes * to query and either issues a DS or a DNSKEY query. It will check to see 1414238106Sdes * if the correct key has already been reached, in which case it will 1415238106Sdes * advance the event to the next state. 1416238106Sdes * 1417238106Sdes * @param qstate: query state. 1418238106Sdes * @param vq: validator query state. 1419238106Sdes * @param id: module id. 1420238106Sdes * @return true if the event should be processed further on return, false if 1421238106Sdes * not. 1422238106Sdes */ 1423238106Sdesstatic int 1424238106SdesprocessFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) 1425238106Sdes{ 1426238106Sdes uint8_t* target_key_name, *current_key_name; 1427238106Sdes size_t target_key_len; 1428238106Sdes int strip_lab; 1429238106Sdes 1430238106Sdes log_query_info(VERB_ALGO, "validator: FindKey", &vq->qchase); 1431238106Sdes /* We know that state.key_entry is not 0 or bad key -- if it were, 1432238106Sdes * then previous processing should have directed this event to 1433238106Sdes * a different state. 1434238106Sdes * It could be an isnull key, which signals that a DLV was just 1435238106Sdes * done and the DNSKEY after the DLV failed with dnssec-retry state 1436238106Sdes * and the DNSKEY has to be performed again. */ 1437238106Sdes log_assert(vq->key_entry && !key_entry_isbad(vq->key_entry)); 1438238106Sdes if(key_entry_isnull(vq->key_entry)) { 1439238106Sdes if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, 1440238106Sdes vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, 1441238106Sdes vq->qchase.qclass, BIT_CD)) { 1442238106Sdes log_err("mem error generating DNSKEY request"); 1443238106Sdes return val_error(qstate, id); 1444238106Sdes } 1445238106Sdes return 0; 1446238106Sdes } 1447238106Sdes 1448238106Sdes target_key_name = vq->signer_name; 1449238106Sdes target_key_len = vq->signer_len; 1450238106Sdes if(!target_key_name) { 1451238106Sdes target_key_name = vq->qchase.qname; 1452238106Sdes target_key_len = vq->qchase.qname_len; 1453238106Sdes } 1454238106Sdes 1455238106Sdes current_key_name = vq->key_entry->name; 1456238106Sdes 1457238106Sdes /* If our current key entry matches our target, then we are done. */ 1458238106Sdes if(query_dname_compare(target_key_name, current_key_name) == 0) { 1459238106Sdes vq->state = VAL_VALIDATE_STATE; 1460238106Sdes return 1; 1461238106Sdes } 1462238106Sdes 1463238106Sdes if(vq->empty_DS_name) { 1464238106Sdes /* if the last empty nonterminal/emptyDS name we detected is 1465238106Sdes * below the current key, use that name to make progress 1466238106Sdes * along the chain of trust */ 1467238106Sdes if(query_dname_compare(target_key_name, 1468238106Sdes vq->empty_DS_name) == 0) { 1469238106Sdes /* do not query for empty_DS_name again */ 1470238106Sdes verbose(VERB_ALGO, "Cannot retrieve DS for signature"); 1471238106Sdes errinf(qstate, "no signatures"); 1472238106Sdes errinf_origin(qstate, qstate->reply_origin); 1473238106Sdes vq->chase_reply->security = sec_status_bogus; 1474238106Sdes vq->state = VAL_FINISHED_STATE; 1475238106Sdes return 1; 1476238106Sdes } 1477238106Sdes current_key_name = vq->empty_DS_name; 1478238106Sdes } 1479238106Sdes 1480238106Sdes log_nametypeclass(VERB_ALGO, "current keyname", current_key_name, 1481238106Sdes LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN); 1482238106Sdes log_nametypeclass(VERB_ALGO, "target keyname", target_key_name, 1483238106Sdes LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN); 1484238106Sdes /* assert we are walking down the DNS tree */ 1485238106Sdes if(!dname_subdomain_c(target_key_name, current_key_name)) { 1486238106Sdes verbose(VERB_ALGO, "bad signer name"); 1487238106Sdes vq->chase_reply->security = sec_status_bogus; 1488238106Sdes vq->state = VAL_FINISHED_STATE; 1489238106Sdes return 1; 1490238106Sdes } 1491238106Sdes /* so this value is >= -1 */ 1492238106Sdes strip_lab = dname_count_labels(target_key_name) - 1493238106Sdes dname_count_labels(current_key_name) - 1; 1494238106Sdes log_assert(strip_lab >= -1); 1495238106Sdes verbose(VERB_ALGO, "striplab %d", strip_lab); 1496238106Sdes if(strip_lab > 0) { 1497238106Sdes dname_remove_labels(&target_key_name, &target_key_len, 1498238106Sdes strip_lab); 1499238106Sdes } 1500238106Sdes log_nametypeclass(VERB_ALGO, "next keyname", target_key_name, 1501238106Sdes LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN); 1502238106Sdes 1503238106Sdes /* The next step is either to query for the next DS, or to query 1504238106Sdes * for the next DNSKEY. */ 1505238106Sdes if(vq->ds_rrset) 1506238106Sdes log_nametypeclass(VERB_ALGO, "DS RRset", vq->ds_rrset->rk.dname, LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN); 1507238106Sdes else verbose(VERB_ALGO, "No DS RRset"); 1508238106Sdes 1509238106Sdes if(vq->ds_rrset && query_dname_compare(vq->ds_rrset->rk.dname, 1510238106Sdes vq->key_entry->name) != 0) { 1511238106Sdes if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, 1512238106Sdes vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, 1513238106Sdes vq->qchase.qclass, BIT_CD)) { 1514238106Sdes log_err("mem error generating DNSKEY request"); 1515238106Sdes return val_error(qstate, id); 1516238106Sdes } 1517238106Sdes return 0; 1518238106Sdes } 1519238106Sdes 1520238106Sdes if(!vq->ds_rrset || query_dname_compare(vq->ds_rrset->rk.dname, 1521238106Sdes target_key_name) != 0) { 1522238106Sdes /* check if there is a cache entry : pick up an NSEC if 1523238106Sdes * there is no DS, check if that NSEC has DS-bit unset, and 1524238106Sdes * thus can disprove the secure delagation we seek. 1525238106Sdes * We can then use that NSEC even in the absence of a SOA 1526238106Sdes * record that would be required by the iterator to supply 1527238106Sdes * a completely protocol-correct response. 1528238106Sdes * Uses negative cache for NSEC3 lookup of DS responses. */ 1529238106Sdes /* only if cache not blacklisted, of course */ 1530238106Sdes struct dns_msg* msg; 1531238106Sdes if(!qstate->blacklist && !vq->chain_blacklist && 1532238106Sdes (msg=val_find_DS(qstate->env, target_key_name, 1533238106Sdes target_key_len, vq->qchase.qclass, qstate->region, 1534238106Sdes vq->key_entry->name)) ) { 1535238106Sdes verbose(VERB_ALGO, "Process cached DS response"); 1536238106Sdes process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR, 1537238106Sdes msg, &msg->qinfo, NULL); 1538238106Sdes return 1; /* continue processing ds-response results */ 1539238106Sdes } 1540238106Sdes if(!generate_request(qstate, id, target_key_name, 1541238106Sdes target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass, 1542238106Sdes BIT_CD)) { 1543238106Sdes log_err("mem error generating DS request"); 1544238106Sdes return val_error(qstate, id); 1545238106Sdes } 1546238106Sdes return 0; 1547238106Sdes } 1548238106Sdes 1549238106Sdes /* Otherwise, it is time to query for the DNSKEY */ 1550238106Sdes if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, 1551238106Sdes vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, 1552238106Sdes vq->qchase.qclass, BIT_CD)) { 1553238106Sdes log_err("mem error generating DNSKEY request"); 1554238106Sdes return val_error(qstate, id); 1555238106Sdes } 1556238106Sdes 1557238106Sdes return 0; 1558238106Sdes} 1559238106Sdes 1560238106Sdes/** 1561238106Sdes * Process the VALIDATE stage, the init and findkey stages are finished, 1562238106Sdes * and the right keys are available to validate the response. 1563238106Sdes * Or, there are no keys available, in order to invalidate the response. 1564238106Sdes * 1565238106Sdes * After validation, the status is recorded in the message and rrsets, 1566238106Sdes * and finished state is started. 1567238106Sdes * 1568238106Sdes * @param qstate: query state. 1569238106Sdes * @param vq: validator query state. 1570238106Sdes * @param ve: validator shared global environment. 1571238106Sdes * @param id: module id. 1572238106Sdes * @return true if the event should be processed further on return, false if 1573238106Sdes * not. 1574238106Sdes */ 1575238106Sdesstatic int 1576238106SdesprocessValidate(struct module_qstate* qstate, struct val_qstate* vq, 1577238106Sdes struct val_env* ve, int id) 1578238106Sdes{ 1579238106Sdes enum val_classification subtype; 1580269257Sdes int rcode; 1581238106Sdes 1582238106Sdes if(!vq->key_entry) { 1583238106Sdes verbose(VERB_ALGO, "validate: no key entry, failed"); 1584238106Sdes return val_error(qstate, id); 1585238106Sdes } 1586238106Sdes 1587238106Sdes /* This is the default next state. */ 1588238106Sdes vq->state = VAL_FINISHED_STATE; 1589238106Sdes 1590238106Sdes /* Unsigned responses must be underneath a "null" key entry.*/ 1591238106Sdes if(key_entry_isnull(vq->key_entry)) { 1592238106Sdes verbose(VERB_DETAIL, "Verified that %sresponse is INSECURE", 1593238106Sdes vq->signer_name?"":"unsigned "); 1594238106Sdes vq->chase_reply->security = sec_status_insecure; 1595238106Sdes val_mark_insecure(vq->chase_reply, vq->key_entry->name, 1596238106Sdes qstate->env->rrset_cache, qstate->env); 1597238106Sdes key_cache_insert(ve->kcache, vq->key_entry, qstate); 1598238106Sdes return 1; 1599238106Sdes } 1600238106Sdes 1601238106Sdes if(key_entry_isbad(vq->key_entry)) { 1602238106Sdes log_nametypeclass(VERB_DETAIL, "Could not establish a chain " 1603238106Sdes "of trust to keys for", vq->key_entry->name, 1604238106Sdes LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class); 1605238106Sdes vq->chase_reply->security = sec_status_bogus; 1606238106Sdes errinf(qstate, "while building chain of trust"); 1607238106Sdes if(vq->restart_count >= VAL_MAX_RESTART_COUNT) 1608238106Sdes key_cache_insert(ve->kcache, vq->key_entry, qstate); 1609238106Sdes return 1; 1610238106Sdes } 1611238106Sdes 1612238106Sdes /* signerName being null is the indicator that this response was 1613238106Sdes * unsigned */ 1614238106Sdes if(vq->signer_name == NULL) { 1615238106Sdes log_query_info(VERB_ALGO, "processValidate: state has no " 1616238106Sdes "signer name", &vq->qchase); 1617238106Sdes verbose(VERB_DETAIL, "Could not establish validation of " 1618238106Sdes "INSECURE status of unsigned response."); 1619238106Sdes errinf(qstate, "no signatures"); 1620238106Sdes errinf_origin(qstate, qstate->reply_origin); 1621238106Sdes vq->chase_reply->security = sec_status_bogus; 1622238106Sdes return 1; 1623238106Sdes } 1624238106Sdes subtype = val_classify_response(qstate->query_flags, &qstate->qinfo, 1625238106Sdes &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); 1626238106Sdes 1627238106Sdes /* check signatures in the message; 1628238106Sdes * answer and authority must be valid, additional is only checked. */ 1629238106Sdes if(!validate_msg_signatures(qstate, qstate->env, ve, &vq->qchase, 1630238106Sdes vq->chase_reply, vq->key_entry)) { 1631238106Sdes /* workaround bad recursor out there that truncates (even 1632238106Sdes * with EDNS4k) to 512 by removing RRSIG from auth section 1633238106Sdes * for positive replies*/ 1634238106Sdes if((subtype == VAL_CLASS_POSITIVE || subtype == VAL_CLASS_ANY 1635238106Sdes || subtype == VAL_CLASS_CNAME) && 1636238106Sdes detect_wrongly_truncated(vq->orig_msg->rep)) { 1637238106Sdes /* truncate the message some more */ 1638238106Sdes vq->orig_msg->rep->ns_numrrsets = 0; 1639238106Sdes vq->orig_msg->rep->ar_numrrsets = 0; 1640238106Sdes vq->orig_msg->rep->rrset_count = 1641238106Sdes vq->orig_msg->rep->an_numrrsets; 1642238106Sdes vq->chase_reply->ns_numrrsets = 0; 1643238106Sdes vq->chase_reply->ar_numrrsets = 0; 1644238106Sdes vq->chase_reply->rrset_count = 1645238106Sdes vq->chase_reply->an_numrrsets; 1646238106Sdes qstate->errinf = NULL; 1647238106Sdes } 1648238106Sdes else { 1649238106Sdes verbose(VERB_DETAIL, "Validate: message contains " 1650238106Sdes "bad rrsets"); 1651238106Sdes return 1; 1652238106Sdes } 1653238106Sdes } 1654238106Sdes 1655238106Sdes switch(subtype) { 1656238106Sdes case VAL_CLASS_POSITIVE: 1657238106Sdes verbose(VERB_ALGO, "Validating a positive response"); 1658238106Sdes validate_positive_response(qstate->env, ve, 1659238106Sdes &vq->qchase, vq->chase_reply, vq->key_entry); 1660238106Sdes verbose(VERB_DETAIL, "validate(positive): %s", 1661238106Sdes sec_status_to_string( 1662238106Sdes vq->chase_reply->security)); 1663238106Sdes break; 1664269257Sdes 1665238106Sdes case VAL_CLASS_NODATA: 1666238106Sdes verbose(VERB_ALGO, "Validating a nodata response"); 1667238106Sdes validate_nodata_response(qstate->env, ve, 1668238106Sdes &vq->qchase, vq->chase_reply, vq->key_entry); 1669238106Sdes verbose(VERB_DETAIL, "validate(nodata): %s", 1670238106Sdes sec_status_to_string( 1671238106Sdes vq->chase_reply->security)); 1672238106Sdes break; 1673238106Sdes 1674238106Sdes case VAL_CLASS_NAMEERROR: 1675269257Sdes rcode = (int)FLAGS_GET_RCODE(vq->orig_msg->rep->flags); 1676238106Sdes verbose(VERB_ALGO, "Validating a nxdomain response"); 1677238106Sdes validate_nameerror_response(qstate->env, ve, 1678269257Sdes &vq->qchase, vq->chase_reply, vq->key_entry, &rcode); 1679238106Sdes verbose(VERB_DETAIL, "validate(nxdomain): %s", 1680238106Sdes sec_status_to_string( 1681238106Sdes vq->chase_reply->security)); 1682269257Sdes FLAGS_SET_RCODE(vq->orig_msg->rep->flags, rcode); 1683269257Sdes FLAGS_SET_RCODE(vq->chase_reply->flags, rcode); 1684238106Sdes break; 1685238106Sdes 1686238106Sdes case VAL_CLASS_CNAME: 1687238106Sdes verbose(VERB_ALGO, "Validating a cname response"); 1688238106Sdes validate_cname_response(qstate->env, ve, 1689238106Sdes &vq->qchase, vq->chase_reply, vq->key_entry); 1690238106Sdes verbose(VERB_DETAIL, "validate(cname): %s", 1691238106Sdes sec_status_to_string( 1692238106Sdes vq->chase_reply->security)); 1693238106Sdes break; 1694238106Sdes 1695238106Sdes case VAL_CLASS_CNAMENOANSWER: 1696238106Sdes verbose(VERB_ALGO, "Validating a cname noanswer " 1697238106Sdes "response"); 1698238106Sdes validate_cname_noanswer_response(qstate->env, ve, 1699238106Sdes &vq->qchase, vq->chase_reply, vq->key_entry); 1700238106Sdes verbose(VERB_DETAIL, "validate(cname_noanswer): %s", 1701238106Sdes sec_status_to_string( 1702238106Sdes vq->chase_reply->security)); 1703238106Sdes break; 1704238106Sdes 1705238106Sdes case VAL_CLASS_REFERRAL: 1706238106Sdes verbose(VERB_ALGO, "Validating a referral response"); 1707238106Sdes validate_referral_response(vq->chase_reply); 1708238106Sdes verbose(VERB_DETAIL, "validate(referral): %s", 1709238106Sdes sec_status_to_string( 1710238106Sdes vq->chase_reply->security)); 1711238106Sdes break; 1712238106Sdes 1713238106Sdes case VAL_CLASS_ANY: 1714238106Sdes verbose(VERB_ALGO, "Validating a positive ANY " 1715238106Sdes "response"); 1716238106Sdes validate_any_response(qstate->env, ve, &vq->qchase, 1717238106Sdes vq->chase_reply, vq->key_entry); 1718238106Sdes verbose(VERB_DETAIL, "validate(positive_any): %s", 1719238106Sdes sec_status_to_string( 1720238106Sdes vq->chase_reply->security)); 1721238106Sdes break; 1722238106Sdes 1723238106Sdes default: 1724238106Sdes log_err("validate: unhandled response subtype: %d", 1725238106Sdes subtype); 1726238106Sdes } 1727238106Sdes if(vq->chase_reply->security == sec_status_bogus) { 1728238106Sdes if(subtype == VAL_CLASS_POSITIVE) 1729238106Sdes errinf(qstate, "wildcard"); 1730238106Sdes else errinf(qstate, val_classification_to_string(subtype)); 1731238106Sdes errinf(qstate, "proof failed"); 1732238106Sdes errinf_origin(qstate, qstate->reply_origin); 1733238106Sdes } 1734238106Sdes 1735238106Sdes return 1; 1736238106Sdes} 1737238106Sdes 1738238106Sdes/** 1739238106Sdes * Init DLV check. 1740238106Sdes * Called when a query is determined by other trust anchors to be insecure 1741238106Sdes * (or indeterminate). Then we look if there is a key in the DLV. 1742238106Sdes * Performs aggressive negative cache check to see if there is no key. 1743238106Sdes * Otherwise, spawns a DLV query, and changes to the DLV wait state. 1744238106Sdes * 1745238106Sdes * @param qstate: query state. 1746238106Sdes * @param vq: validator query state. 1747238106Sdes * @param ve: validator shared global environment. 1748238106Sdes * @param id: module id. 1749238106Sdes * @return true if there is no DLV. 1750238106Sdes * false: processing is finished for the validator operate(). 1751238106Sdes * This function may exit in three ways: 1752238106Sdes * o no DLV (agressive cache), so insecure. (true) 1753238106Sdes * o error - stop processing (false) 1754238106Sdes * o DLV lookup was started, stop processing (false) 1755238106Sdes */ 1756238106Sdesstatic int 1757238106Sdesval_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, 1758238106Sdes struct val_env* ve, int id) 1759238106Sdes{ 1760238106Sdes uint8_t* nm; 1761238106Sdes size_t nm_len; 1762238106Sdes /* there must be a DLV configured */ 1763238106Sdes log_assert(qstate->env->anchors->dlv_anchor); 1764238106Sdes /* this bool is true to avoid looping in the DLV checks */ 1765238106Sdes log_assert(vq->dlv_checked); 1766238106Sdes 1767238106Sdes /* init the DLV lookup variables */ 1768238106Sdes vq->dlv_lookup_name = NULL; 1769238106Sdes vq->dlv_lookup_name_len = 0; 1770238106Sdes vq->dlv_insecure_at = NULL; 1771238106Sdes vq->dlv_insecure_at_len = 0; 1772238106Sdes 1773238106Sdes /* Determine the name for which we want to lookup DLV. 1774238106Sdes * This name is for the current message, or 1775238106Sdes * for the current RRset for CNAME, referral subtypes. 1776238106Sdes * If there is a signer, use that, otherwise the domain name */ 1777238106Sdes if(vq->signer_name) { 1778238106Sdes nm = vq->signer_name; 1779238106Sdes nm_len = vq->signer_len; 1780238106Sdes } else { 1781238106Sdes /* use qchase */ 1782238106Sdes nm = vq->qchase.qname; 1783238106Sdes nm_len = vq->qchase.qname_len; 1784238106Sdes if(vq->qchase.qtype == LDNS_RR_TYPE_DS) 1785238106Sdes dname_remove_label(&nm, &nm_len); 1786238106Sdes } 1787238106Sdes log_nametypeclass(VERB_ALGO, "DLV init look", nm, LDNS_RR_TYPE_DS, 1788238106Sdes vq->qchase.qclass); 1789238106Sdes log_assert(nm && nm_len); 1790238106Sdes /* sanity check: no DLV lookups below the DLV anchor itself. 1791238106Sdes * Like, an securely insecure delegation there makes no sense. */ 1792238106Sdes if(dname_subdomain_c(nm, qstate->env->anchors->dlv_anchor->name)) { 1793238106Sdes verbose(VERB_ALGO, "DLV lookup within DLV repository denied"); 1794238106Sdes return 1; 1795238106Sdes } 1796238106Sdes /* concat name (minus root label) + dlv name */ 1797238106Sdes vq->dlv_lookup_name_len = nm_len - 1 + 1798238106Sdes qstate->env->anchors->dlv_anchor->namelen; 1799238106Sdes vq->dlv_lookup_name = regional_alloc(qstate->region, 1800238106Sdes vq->dlv_lookup_name_len); 1801238106Sdes if(!vq->dlv_lookup_name) { 1802238106Sdes log_err("Out of memory preparing DLV lookup"); 1803238106Sdes return val_error(qstate, id); 1804238106Sdes } 1805238106Sdes memmove(vq->dlv_lookup_name, nm, nm_len-1); 1806238106Sdes memmove(vq->dlv_lookup_name+nm_len-1, 1807238106Sdes qstate->env->anchors->dlv_anchor->name, 1808238106Sdes qstate->env->anchors->dlv_anchor->namelen); 1809238106Sdes log_nametypeclass(VERB_ALGO, "DLV name", vq->dlv_lookup_name, 1810238106Sdes LDNS_RR_TYPE_DLV, vq->qchase.qclass); 1811238106Sdes 1812238106Sdes /* determine where the insecure point was determined, the DLV must 1813238106Sdes * be equal or below that to continue building the trust chain 1814238106Sdes * down. May be NULL if no trust chain was built yet */ 1815238106Sdes nm = NULL; 1816238106Sdes if(vq->key_entry && key_entry_isnull(vq->key_entry)) { 1817238106Sdes nm = vq->key_entry->name; 1818238106Sdes nm_len = vq->key_entry->namelen; 1819238106Sdes } 1820238106Sdes if(nm) { 1821238106Sdes vq->dlv_insecure_at_len = nm_len - 1 + 1822238106Sdes qstate->env->anchors->dlv_anchor->namelen; 1823238106Sdes vq->dlv_insecure_at = regional_alloc(qstate->region, 1824238106Sdes vq->dlv_insecure_at_len); 1825238106Sdes if(!vq->dlv_insecure_at) { 1826238106Sdes log_err("Out of memory preparing DLV lookup"); 1827238106Sdes return val_error(qstate, id); 1828238106Sdes } 1829238106Sdes memmove(vq->dlv_insecure_at, nm, nm_len-1); 1830238106Sdes memmove(vq->dlv_insecure_at+nm_len-1, 1831238106Sdes qstate->env->anchors->dlv_anchor->name, 1832238106Sdes qstate->env->anchors->dlv_anchor->namelen); 1833238106Sdes log_nametypeclass(VERB_ALGO, "insecure_at", 1834238106Sdes vq->dlv_insecure_at, 0, vq->qchase.qclass); 1835238106Sdes } 1836238106Sdes 1837238106Sdes /* If we can find the name in the aggressive negative cache, 1838238106Sdes * give up; insecure is the answer */ 1839238106Sdes while(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name, 1840238106Sdes vq->dlv_lookup_name_len, vq->qchase.qclass, 1841238106Sdes qstate->env->rrset_cache, *qstate->env->now)) { 1842238106Sdes /* go up */ 1843238106Sdes dname_remove_label(&vq->dlv_lookup_name, 1844238106Sdes &vq->dlv_lookup_name_len); 1845238106Sdes /* too high? */ 1846238106Sdes if(!dname_subdomain_c(vq->dlv_lookup_name, 1847238106Sdes qstate->env->anchors->dlv_anchor->name)) { 1848238106Sdes verbose(VERB_ALGO, "ask above dlv repo"); 1849238106Sdes return 1; /* Above the repo is insecure */ 1850238106Sdes } 1851238106Sdes /* above chain of trust? */ 1852238106Sdes if(vq->dlv_insecure_at && !dname_subdomain_c( 1853238106Sdes vq->dlv_lookup_name, vq->dlv_insecure_at)) { 1854238106Sdes verbose(VERB_ALGO, "ask above insecure endpoint"); 1855238106Sdes return 1; 1856238106Sdes } 1857238106Sdes } 1858238106Sdes 1859238106Sdes /* perform a lookup for the DLV; with validation */ 1860238106Sdes vq->state = VAL_DLVLOOKUP_STATE; 1861238106Sdes if(!generate_request(qstate, id, vq->dlv_lookup_name, 1862238106Sdes vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, 1863238106Sdes vq->qchase.qclass, 0)) { 1864238106Sdes return val_error(qstate, id); 1865238106Sdes } 1866238106Sdes 1867238106Sdes /* Find the closest encloser DLV from the repository. 1868238106Sdes * then that is used to build another chain of trust 1869238106Sdes * This may first require a query 'too low' that has NSECs in 1870238106Sdes * the answer, from which we determine the closest encloser DLV. 1871238106Sdes * When determine the closest encloser, skip empty nonterminals, 1872238106Sdes * since we want a nonempty node in the DLV repository. */ 1873238106Sdes 1874238106Sdes return 0; 1875238106Sdes} 1876238106Sdes 1877238106Sdes/** 1878238106Sdes * The Finished state. The validation status (good or bad) has been determined. 1879238106Sdes * 1880238106Sdes * @param qstate: query state. 1881238106Sdes * @param vq: validator query state. 1882238106Sdes * @param ve: validator shared global environment. 1883238106Sdes * @param id: module id. 1884238106Sdes * @return true if the event should be processed further on return, false if 1885238106Sdes * not. 1886238106Sdes */ 1887238106Sdesstatic int 1888238106SdesprocessFinished(struct module_qstate* qstate, struct val_qstate* vq, 1889238106Sdes struct val_env* ve, int id) 1890238106Sdes{ 1891238106Sdes enum val_classification subtype = val_classify_response( 1892238106Sdes qstate->query_flags, &qstate->qinfo, &vq->qchase, 1893238106Sdes vq->orig_msg->rep, vq->rrset_skip); 1894238106Sdes 1895238106Sdes /* if the result is insecure or indeterminate and we have not 1896238106Sdes * checked the DLV yet, check the DLV */ 1897238106Sdes if((vq->chase_reply->security == sec_status_insecure || 1898238106Sdes vq->chase_reply->security == sec_status_indeterminate) && 1899238106Sdes qstate->env->anchors->dlv_anchor && !vq->dlv_checked) { 1900238106Sdes vq->dlv_checked = 1; 1901238106Sdes if(!val_dlv_init(qstate, vq, ve, id)) 1902238106Sdes return 0; 1903238106Sdes } 1904238106Sdes 1905238106Sdes /* store overall validation result in orig_msg */ 1906238106Sdes if(vq->rrset_skip == 0) 1907238106Sdes vq->orig_msg->rep->security = vq->chase_reply->security; 1908249141Sdes else if(subtype != VAL_CLASS_REFERRAL || 1909249141Sdes vq->rrset_skip < vq->orig_msg->rep->an_numrrsets + 1910238106Sdes vq->orig_msg->rep->ns_numrrsets) { 1911238106Sdes /* ignore sec status of additional section if a referral 1912238106Sdes * type message skips there and 1913238106Sdes * use the lowest security status as end result. */ 1914238106Sdes if(vq->chase_reply->security < vq->orig_msg->rep->security) 1915238106Sdes vq->orig_msg->rep->security = 1916238106Sdes vq->chase_reply->security; 1917238106Sdes } 1918238106Sdes 1919238106Sdes if(subtype == VAL_CLASS_REFERRAL) { 1920238106Sdes /* for a referral, move to next unchecked rrset and check it*/ 1921238106Sdes vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep, 1922238106Sdes vq->rrset_skip); 1923238106Sdes if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) { 1924238106Sdes /* and restart for this rrset */ 1925238106Sdes verbose(VERB_ALGO, "validator: go to next rrset"); 1926238106Sdes vq->chase_reply->security = sec_status_unchecked; 1927238106Sdes vq->dlv_checked = 0; /* can do DLV for this RR */ 1928238106Sdes vq->state = VAL_INIT_STATE; 1929238106Sdes return 1; 1930238106Sdes } 1931238106Sdes /* referral chase is done */ 1932238106Sdes } 1933238106Sdes if(vq->chase_reply->security != sec_status_bogus && 1934238106Sdes subtype == VAL_CLASS_CNAME) { 1935238106Sdes /* chase the CNAME; process next part of the message */ 1936238106Sdes if(!val_chase_cname(&vq->qchase, vq->orig_msg->rep, 1937238106Sdes &vq->rrset_skip)) { 1938238106Sdes verbose(VERB_ALGO, "validator: failed to chase CNAME"); 1939238106Sdes vq->orig_msg->rep->security = sec_status_bogus; 1940238106Sdes } else { 1941238106Sdes /* restart process for new qchase at rrset_skip */ 1942238106Sdes log_query_info(VERB_ALGO, "validator: chased to", 1943238106Sdes &vq->qchase); 1944238106Sdes vq->chase_reply->security = sec_status_unchecked; 1945238106Sdes vq->dlv_checked = 0; /* can do DLV for this RR */ 1946238106Sdes vq->state = VAL_INIT_STATE; 1947238106Sdes return 1; 1948238106Sdes } 1949238106Sdes } 1950238106Sdes 1951238106Sdes if(vq->orig_msg->rep->security == sec_status_secure) { 1952238106Sdes /* If the message is secure, check that all rrsets are 1953238106Sdes * secure (i.e. some inserted RRset for CNAME chain with 1954238106Sdes * a different signer name). And drop additional rrsets 1955238106Sdes * that are not secure (if clean-additional option is set) */ 1956238106Sdes /* this may cause the msg to be marked bogus */ 1957238106Sdes val_check_nonsecure(ve, vq->orig_msg->rep); 1958238106Sdes if(vq->orig_msg->rep->security == sec_status_secure) { 1959238106Sdes log_query_info(VERB_DETAIL, "validation success", 1960238106Sdes &qstate->qinfo); 1961238106Sdes } 1962238106Sdes } 1963238106Sdes 1964238106Sdes /* if the result is bogus - set message ttl to bogus ttl to avoid 1965238106Sdes * endless bogus revalidation */ 1966238106Sdes if(vq->orig_msg->rep->security == sec_status_bogus) { 1967238106Sdes /* see if we can try again to fetch data */ 1968238106Sdes if(vq->restart_count < VAL_MAX_RESTART_COUNT) { 1969238106Sdes int restart_count = vq->restart_count+1; 1970238106Sdes verbose(VERB_ALGO, "validation failed, " 1971238106Sdes "blacklist and retry to fetch data"); 1972238106Sdes val_blacklist(&qstate->blacklist, qstate->region, 1973238106Sdes qstate->reply_origin, 0); 1974238106Sdes qstate->reply_origin = NULL; 1975238106Sdes qstate->errinf = NULL; 1976238106Sdes memset(vq, 0, sizeof(*vq)); 1977238106Sdes vq->restart_count = restart_count; 1978238106Sdes vq->state = VAL_INIT_STATE; 1979238106Sdes verbose(VERB_ALGO, "pass back to next module"); 1980238106Sdes qstate->ext_state[id] = module_restart_next; 1981238106Sdes return 0; 1982238106Sdes } 1983238106Sdes 1984238106Sdes vq->orig_msg->rep->ttl = ve->bogus_ttl; 1985238106Sdes vq->orig_msg->rep->prefetch_ttl = 1986238106Sdes PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl); 1987238106Sdes if(qstate->env->cfg->val_log_level >= 1 && 1988238106Sdes !qstate->env->cfg->val_log_squelch) { 1989238106Sdes if(qstate->env->cfg->val_log_level < 2) 1990238106Sdes log_query_info(0, "validation failure", 1991238106Sdes &qstate->qinfo); 1992238106Sdes else { 1993238106Sdes char* err = errinf_to_str(qstate); 1994238106Sdes if(err) log_info("%s", err); 1995238106Sdes free(err); 1996238106Sdes } 1997238106Sdes } 1998238106Sdes /* If we are in permissive mode, bogus gets indeterminate */ 1999238106Sdes if(ve->permissive_mode) 2000238106Sdes vq->orig_msg->rep->security = sec_status_indeterminate; 2001238106Sdes } 2002238106Sdes 2003238106Sdes /* store results in cache */ 2004238106Sdes if(qstate->query_flags&BIT_RD) { 2005238106Sdes /* if secure, this will override cache anyway, no need 2006238106Sdes * to check if from parentNS */ 2007238106Sdes if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, 2008238106Sdes vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL)) { 2009238106Sdes log_err("out of memory caching validator results"); 2010238106Sdes } 2011238106Sdes } else { 2012238106Sdes /* for a referral, store the verified RRsets */ 2013238106Sdes /* and this does not get prefetched, so no leeway */ 2014238106Sdes if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, 2015238106Sdes vq->orig_msg->rep, 1, 0, 0, NULL)) { 2016238106Sdes log_err("out of memory caching validator results"); 2017238106Sdes } 2018238106Sdes } 2019238106Sdes qstate->return_rcode = LDNS_RCODE_NOERROR; 2020238106Sdes qstate->return_msg = vq->orig_msg; 2021238106Sdes qstate->ext_state[id] = module_finished; 2022238106Sdes return 0; 2023238106Sdes} 2024238106Sdes 2025238106Sdes/** 2026238106Sdes * The DLVLookup state. Process DLV lookups. 2027238106Sdes * 2028238106Sdes * @param qstate: query state. 2029238106Sdes * @param vq: validator query state. 2030238106Sdes * @param ve: validator shared global environment. 2031238106Sdes * @param id: module id. 2032238106Sdes * @return true if the event should be processed further on return, false if 2033238106Sdes * not. 2034238106Sdes */ 2035238106Sdesstatic int 2036238106SdesprocessDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, 2037238106Sdes struct val_env* ve, int id) 2038238106Sdes{ 2039238106Sdes /* see if this we are ready to continue normal resolution */ 2040238106Sdes /* we may need more DLV lookups */ 2041238106Sdes if(vq->dlv_status==dlv_error) 2042238106Sdes verbose(VERB_ALGO, "DLV woke up with status dlv_error"); 2043238106Sdes else if(vq->dlv_status==dlv_success) 2044238106Sdes verbose(VERB_ALGO, "DLV woke up with status dlv_success"); 2045238106Sdes else if(vq->dlv_status==dlv_ask_higher) 2046238106Sdes verbose(VERB_ALGO, "DLV woke up with status dlv_ask_higher"); 2047238106Sdes else if(vq->dlv_status==dlv_there_is_no_dlv) 2048238106Sdes verbose(VERB_ALGO, "DLV woke up with status dlv_there_is_no_dlv"); 2049238106Sdes else verbose(VERB_ALGO, "DLV woke up with status unknown"); 2050238106Sdes 2051238106Sdes if(vq->dlv_status == dlv_error) { 2052238106Sdes verbose(VERB_QUERY, "failed DLV lookup"); 2053238106Sdes return val_error(qstate, id); 2054238106Sdes } else if(vq->dlv_status == dlv_success) { 2055238106Sdes uint8_t* nm; 2056238106Sdes size_t nmlen; 2057238106Sdes /* chain continues with DNSKEY, continue in FINDKEY */ 2058238106Sdes vq->state = VAL_FINDKEY_STATE; 2059238106Sdes 2060238106Sdes /* strip off the DLV suffix from the name; could result in . */ 2061238106Sdes log_assert(dname_subdomain_c(vq->ds_rrset->rk.dname, 2062238106Sdes qstate->env->anchors->dlv_anchor->name)); 2063238106Sdes nmlen = vq->ds_rrset->rk.dname_len - 2064238106Sdes qstate->env->anchors->dlv_anchor->namelen + 1; 2065238106Sdes nm = regional_alloc_init(qstate->region, 2066238106Sdes vq->ds_rrset->rk.dname, nmlen); 2067238106Sdes if(!nm) { 2068238106Sdes log_err("Out of memory in DLVLook"); 2069238106Sdes return val_error(qstate, id); 2070238106Sdes } 2071238106Sdes nm[nmlen-1] = 0; 2072238106Sdes 2073238106Sdes vq->ds_rrset->rk.dname = nm; 2074238106Sdes vq->ds_rrset->rk.dname_len = nmlen; 2075238106Sdes 2076238106Sdes /* create a nullentry for the key so the dnskey lookup 2077238106Sdes * can be retried after a validation failure for it */ 2078238106Sdes vq->key_entry = key_entry_create_null(qstate->region, 2079238106Sdes nm, nmlen, vq->qchase.qclass, 0, 0); 2080238106Sdes if(!vq->key_entry) { 2081238106Sdes log_err("Out of memory in DLVLook"); 2082238106Sdes return val_error(qstate, id); 2083238106Sdes } 2084238106Sdes 2085238106Sdes if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, 2086238106Sdes vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, 2087238106Sdes vq->qchase.qclass, BIT_CD)) { 2088238106Sdes log_err("mem error generating DNSKEY request"); 2089238106Sdes return val_error(qstate, id); 2090238106Sdes } 2091238106Sdes return 0; 2092238106Sdes } else if(vq->dlv_status == dlv_there_is_no_dlv) { 2093238106Sdes /* continue with the insecure result we got */ 2094238106Sdes vq->state = VAL_FINISHED_STATE; 2095238106Sdes return 1; 2096238106Sdes } 2097238106Sdes log_assert(vq->dlv_status == dlv_ask_higher); 2098238106Sdes 2099238106Sdes /* ask higher, make sure we stay in DLV repo, below dlv_at */ 2100238106Sdes if(!dname_subdomain_c(vq->dlv_lookup_name, 2101238106Sdes qstate->env->anchors->dlv_anchor->name)) { 2102238106Sdes /* just like, there is no DLV */ 2103238106Sdes verbose(VERB_ALGO, "ask above dlv repo"); 2104238106Sdes vq->state = VAL_FINISHED_STATE; 2105238106Sdes return 1; 2106238106Sdes } 2107238106Sdes if(vq->dlv_insecure_at && !dname_subdomain_c(vq->dlv_lookup_name, 2108238106Sdes vq->dlv_insecure_at)) { 2109238106Sdes /* already checked a chain lower than dlv_lookup_name */ 2110238106Sdes verbose(VERB_ALGO, "ask above insecure endpoint"); 2111238106Sdes log_nametypeclass(VERB_ALGO, "enpt", vq->dlv_insecure_at, 0, 0); 2112238106Sdes vq->state = VAL_FINISHED_STATE; 2113238106Sdes return 1; 2114238106Sdes } 2115238106Sdes 2116238106Sdes /* check negative cache before making new request */ 2117238106Sdes if(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name, 2118238106Sdes vq->dlv_lookup_name_len, vq->qchase.qclass, 2119238106Sdes qstate->env->rrset_cache, *qstate->env->now)) { 2120238106Sdes /* does not exist, go up one (go higher). */ 2121238106Sdes dname_remove_label(&vq->dlv_lookup_name, 2122238106Sdes &vq->dlv_lookup_name_len); 2123238106Sdes /* limit number of labels, limited number of recursion */ 2124238106Sdes return processDLVLookup(qstate, vq, ve, id); 2125238106Sdes } 2126238106Sdes 2127238106Sdes if(!generate_request(qstate, id, vq->dlv_lookup_name, 2128238106Sdes vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, 2129238106Sdes vq->qchase.qclass, 0)) { 2130238106Sdes return val_error(qstate, id); 2131238106Sdes } 2132238106Sdes 2133238106Sdes return 0; 2134238106Sdes} 2135238106Sdes 2136238106Sdes/** 2137238106Sdes * Handle validator state. 2138238106Sdes * If a method returns true, the next state is started. If false, then 2139238106Sdes * processing will stop. 2140238106Sdes * @param qstate: query state. 2141238106Sdes * @param vq: validator query state. 2142238106Sdes * @param ve: validator shared global environment. 2143238106Sdes * @param id: module id. 2144238106Sdes */ 2145238106Sdesstatic void 2146238106Sdesval_handle(struct module_qstate* qstate, struct val_qstate* vq, 2147238106Sdes struct val_env* ve, int id) 2148238106Sdes{ 2149238106Sdes int cont = 1; 2150238106Sdes while(cont) { 2151238106Sdes verbose(VERB_ALGO, "val handle processing q with state %s", 2152238106Sdes val_state_to_string(vq->state)); 2153238106Sdes switch(vq->state) { 2154238106Sdes case VAL_INIT_STATE: 2155238106Sdes cont = processInit(qstate, vq, ve, id); 2156238106Sdes break; 2157238106Sdes case VAL_FINDKEY_STATE: 2158238106Sdes cont = processFindKey(qstate, vq, id); 2159238106Sdes break; 2160238106Sdes case VAL_VALIDATE_STATE: 2161238106Sdes cont = processValidate(qstate, vq, ve, id); 2162238106Sdes break; 2163238106Sdes case VAL_FINISHED_STATE: 2164238106Sdes cont = processFinished(qstate, vq, ve, id); 2165238106Sdes break; 2166238106Sdes case VAL_DLVLOOKUP_STATE: 2167238106Sdes cont = processDLVLookup(qstate, vq, ve, id); 2168238106Sdes break; 2169238106Sdes default: 2170238106Sdes log_warn("validator: invalid state %d", 2171238106Sdes vq->state); 2172238106Sdes cont = 0; 2173238106Sdes break; 2174238106Sdes } 2175238106Sdes } 2176238106Sdes} 2177238106Sdes 2178238106Sdesvoid 2179238106Sdesval_operate(struct module_qstate* qstate, enum module_ev event, int id, 2180238106Sdes struct outbound_entry* outbound) 2181238106Sdes{ 2182238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2183238106Sdes struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id]; 2184238106Sdes verbose(VERB_QUERY, "validator[module %d] operate: extstate:%s " 2185238106Sdes "event:%s", id, strextstate(qstate->ext_state[id]), 2186238106Sdes strmodulevent(event)); 2187238106Sdes log_query_info(VERB_QUERY, "validator operate: query", 2188238106Sdes &qstate->qinfo); 2189238106Sdes if(vq && qstate->qinfo.qname != vq->qchase.qname) 2190238106Sdes log_query_info(VERB_QUERY, "validator operate: chased to", 2191238106Sdes &vq->qchase); 2192238106Sdes (void)outbound; 2193238106Sdes if(event == module_event_new || 2194238106Sdes (event == module_event_pass && vq == NULL)) { 2195238106Sdes /* pass request to next module, to get it */ 2196238106Sdes verbose(VERB_ALGO, "validator: pass to next module"); 2197238106Sdes qstate->ext_state[id] = module_wait_module; 2198238106Sdes return; 2199238106Sdes } 2200238106Sdes if(event == module_event_moddone) { 2201238106Sdes /* check if validation is needed */ 2202238106Sdes verbose(VERB_ALGO, "validator: nextmodule returned"); 2203238106Sdes if(!needs_validation(qstate, qstate->return_rcode, 2204238106Sdes qstate->return_msg)) { 2205238106Sdes /* no need to validate this */ 2206238106Sdes if(qstate->return_msg) 2207238106Sdes qstate->return_msg->rep->security = 2208238106Sdes sec_status_indeterminate; 2209238106Sdes qstate->ext_state[id] = module_finished; 2210238106Sdes return; 2211238106Sdes } 2212238106Sdes if(already_validated(qstate->return_msg)) { 2213238106Sdes qstate->ext_state[id] = module_finished; 2214238106Sdes return; 2215238106Sdes } 2216238106Sdes /* qclass ANY should have validation result from spawned 2217238106Sdes * queries. If we get here, it is bogus or an internal error */ 2218238106Sdes if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) { 2219238106Sdes verbose(VERB_ALGO, "cannot validate classANY: bogus"); 2220238106Sdes if(qstate->return_msg) 2221238106Sdes qstate->return_msg->rep->security = 2222238106Sdes sec_status_bogus; 2223238106Sdes qstate->ext_state[id] = module_finished; 2224238106Sdes return; 2225238106Sdes } 2226238106Sdes /* create state to start validation */ 2227238106Sdes qstate->ext_state[id] = module_error; /* override this */ 2228238106Sdes if(!vq) { 2229238106Sdes vq = val_new(qstate, id); 2230238106Sdes if(!vq) { 2231238106Sdes log_err("validator: malloc failure"); 2232238106Sdes qstate->ext_state[id] = module_error; 2233238106Sdes return; 2234238106Sdes } 2235238106Sdes } else if(!vq->orig_msg) { 2236238106Sdes if(!val_new_getmsg(qstate, vq)) { 2237238106Sdes log_err("validator: malloc failure"); 2238238106Sdes qstate->ext_state[id] = module_error; 2239238106Sdes return; 2240238106Sdes } 2241238106Sdes } 2242238106Sdes val_handle(qstate, vq, ve, id); 2243238106Sdes return; 2244238106Sdes } 2245238106Sdes if(event == module_event_pass) { 2246238106Sdes qstate->ext_state[id] = module_error; /* override this */ 2247238106Sdes /* continue processing, since val_env exists */ 2248238106Sdes val_handle(qstate, vq, ve, id); 2249238106Sdes return; 2250238106Sdes } 2251238106Sdes log_err("validator: bad event %s", strmodulevent(event)); 2252238106Sdes qstate->ext_state[id] = module_error; 2253238106Sdes return; 2254238106Sdes} 2255238106Sdes 2256238106Sdes/** 2257238106Sdes * Evaluate the response to a priming request. 2258238106Sdes * 2259238106Sdes * @param dnskey_rrset: DNSKEY rrset (can be NULL if none) in prime reply. 2260238106Sdes * (this rrset is allocated in the wrong region, not the qstate). 2261238106Sdes * @param ta: trust anchor. 2262238106Sdes * @param qstate: qstate that needs key. 2263238106Sdes * @param id: module id. 2264238106Sdes * @return new key entry or NULL on allocation failure. 2265238106Sdes * The key entry will either contain a validated DNSKEY rrset, or 2266238106Sdes * represent a Null key (query failed, but validation did not), or a 2267238106Sdes * Bad key (validation failed). 2268238106Sdes */ 2269238106Sdesstatic struct key_entry_key* 2270238106SdesprimeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, 2271238106Sdes struct trust_anchor* ta, struct module_qstate* qstate, int id) 2272238106Sdes{ 2273238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2274238106Sdes struct key_entry_key* kkey = NULL; 2275238106Sdes enum sec_status sec = sec_status_unchecked; 2276238106Sdes char* reason = NULL; 2277238106Sdes int downprot = 1; 2278238106Sdes 2279238106Sdes if(!dnskey_rrset) { 2280238106Sdes log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- " 2281238106Sdes "could not fetch DNSKEY rrset", 2282238106Sdes ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass); 2283238106Sdes if(qstate->env->cfg->harden_dnssec_stripped) { 2284238106Sdes errinf(qstate, "no DNSKEY rrset"); 2285238106Sdes kkey = key_entry_create_bad(qstate->region, ta->name, 2286238106Sdes ta->namelen, ta->dclass, BOGUS_KEY_TTL, 2287238106Sdes *qstate->env->now); 2288238106Sdes } else kkey = key_entry_create_null(qstate->region, ta->name, 2289238106Sdes ta->namelen, ta->dclass, NULL_KEY_TTL, 2290238106Sdes *qstate->env->now); 2291238106Sdes if(!kkey) { 2292238106Sdes log_err("out of memory: allocate fail prime key"); 2293238106Sdes return NULL; 2294238106Sdes } 2295238106Sdes return kkey; 2296238106Sdes } 2297238106Sdes /* attempt to verify with trust anchor DS and DNSKEY */ 2298238106Sdes kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, 2299238106Sdes dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot, 2300238106Sdes &reason); 2301238106Sdes if(!kkey) { 2302238106Sdes log_err("out of memory: verifying prime TA"); 2303238106Sdes return NULL; 2304238106Sdes } 2305238106Sdes if(key_entry_isgood(kkey)) 2306238106Sdes sec = sec_status_secure; 2307238106Sdes else 2308238106Sdes sec = sec_status_bogus; 2309238106Sdes verbose(VERB_DETAIL, "validate keys with anchor(DS): %s", 2310238106Sdes sec_status_to_string(sec)); 2311238106Sdes 2312238106Sdes if(sec != sec_status_secure) { 2313238106Sdes log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- " 2314238106Sdes "DNSKEY rrset is not secure", 2315238106Sdes ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass); 2316238106Sdes /* NOTE: in this case, we should probably reject the trust 2317238106Sdes * anchor for longer, perhaps forever. */ 2318238106Sdes if(qstate->env->cfg->harden_dnssec_stripped) { 2319238106Sdes errinf(qstate, reason); 2320238106Sdes kkey = key_entry_create_bad(qstate->region, ta->name, 2321238106Sdes ta->namelen, ta->dclass, BOGUS_KEY_TTL, 2322238106Sdes *qstate->env->now); 2323238106Sdes } else kkey = key_entry_create_null(qstate->region, ta->name, 2324238106Sdes ta->namelen, ta->dclass, NULL_KEY_TTL, 2325238106Sdes *qstate->env->now); 2326238106Sdes if(!kkey) { 2327238106Sdes log_err("out of memory: allocate null prime key"); 2328238106Sdes return NULL; 2329238106Sdes } 2330238106Sdes return kkey; 2331238106Sdes } 2332238106Sdes 2333238106Sdes log_nametypeclass(VERB_DETAIL, "Successfully primed trust anchor", 2334238106Sdes ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass); 2335238106Sdes return kkey; 2336238106Sdes} 2337238106Sdes 2338238106Sdes/** 2339238106Sdes * In inform supers, with the resulting message and rcode and the current 2340238106Sdes * keyset in the super state, validate the DS response, returning a KeyEntry. 2341238106Sdes * 2342238106Sdes * @param qstate: query state that is validating and asked for a DS. 2343238106Sdes * @param vq: validator query state 2344238106Sdes * @param id: module id. 2345238106Sdes * @param rcode: rcode result value. 2346238106Sdes * @param msg: result message (if rcode is OK). 2347238106Sdes * @param qinfo: from the sub query state, query info. 2348238106Sdes * @param ke: the key entry to return. It returns 2349238106Sdes * is_bad if the DS response fails to validate, is_null if the 2350238106Sdes * DS response indicated an end to secure space, is_good if the DS 2351238106Sdes * validated. It returns ke=NULL if the DS response indicated that the 2352238106Sdes * request wasn't a delegation point. 2353238106Sdes * @return 0 on servfail error (malloc failure). 2354238106Sdes */ 2355238106Sdesstatic int 2356238106Sdesds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, 2357238106Sdes int id, int rcode, struct dns_msg* msg, struct query_info* qinfo, 2358238106Sdes struct key_entry_key** ke) 2359238106Sdes{ 2360238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2361238106Sdes char* reason = NULL; 2362238106Sdes enum val_classification subtype; 2363238106Sdes if(rcode != LDNS_RCODE_NOERROR) { 2364269257Sdes char rc[16]; 2365269257Sdes rc[0]=0; 2366269257Sdes (void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc)); 2367238106Sdes /* errors here pretty much break validation */ 2368238106Sdes verbose(VERB_DETAIL, "DS response was error, thus bogus"); 2369238106Sdes errinf(qstate, rc); 2370238106Sdes errinf(qstate, "no DS"); 2371238106Sdes goto return_bogus; 2372238106Sdes } 2373238106Sdes 2374238106Sdes subtype = val_classify_response(BIT_RD, qinfo, qinfo, msg->rep, 0); 2375238106Sdes if(subtype == VAL_CLASS_POSITIVE) { 2376238106Sdes struct ub_packed_rrset_key* ds; 2377238106Sdes enum sec_status sec; 2378238106Sdes ds = reply_find_answer_rrset(qinfo, msg->rep); 2379238106Sdes /* If there was no DS rrset, then we have mis-classified 2380238106Sdes * this message. */ 2381238106Sdes if(!ds) { 2382238106Sdes log_warn("internal error: POSITIVE DS response was " 2383238106Sdes "missing DS."); 2384238106Sdes errinf(qstate, "no DS record"); 2385238106Sdes goto return_bogus; 2386238106Sdes } 2387238106Sdes /* Verify only returns BOGUS or SECURE. If the rrset is 2388238106Sdes * bogus, then we are done. */ 2389238106Sdes sec = val_verify_rrset_entry(qstate->env, ve, ds, 2390238106Sdes vq->key_entry, &reason); 2391238106Sdes if(sec != sec_status_secure) { 2392238106Sdes verbose(VERB_DETAIL, "DS rrset in DS response did " 2393238106Sdes "not verify"); 2394238106Sdes errinf(qstate, reason); 2395238106Sdes goto return_bogus; 2396238106Sdes } 2397238106Sdes 2398238106Sdes /* If the DS rrset validates, we still have to make sure 2399238106Sdes * that they are usable. */ 2400238106Sdes if(!val_dsset_isusable(ds)) { 2401238106Sdes /* If they aren't usable, then we treat it like 2402238106Sdes * there was no DS. */ 2403238106Sdes *ke = key_entry_create_null(qstate->region, 2404238106Sdes qinfo->qname, qinfo->qname_len, qinfo->qclass, 2405238106Sdes ub_packed_rrset_ttl(ds), *qstate->env->now); 2406238106Sdes return (*ke) != NULL; 2407238106Sdes } 2408238106Sdes 2409238106Sdes /* Otherwise, we return the positive response. */ 2410238106Sdes log_query_info(VERB_DETAIL, "validated DS", qinfo); 2411238106Sdes *ke = key_entry_create_rrset(qstate->region, 2412238106Sdes qinfo->qname, qinfo->qname_len, qinfo->qclass, ds, 2413238106Sdes NULL, *qstate->env->now); 2414238106Sdes return (*ke) != NULL; 2415238106Sdes } else if(subtype == VAL_CLASS_NODATA || 2416238106Sdes subtype == VAL_CLASS_NAMEERROR) { 2417238106Sdes /* NODATA means that the qname exists, but that there was 2418238106Sdes * no DS. This is a pretty normal case. */ 2419269257Sdes time_t proof_ttl = 0; 2420238106Sdes enum sec_status sec; 2421238106Sdes 2422238106Sdes /* make sure there are NSECs or NSEC3s with signatures */ 2423238106Sdes if(!val_has_signed_nsecs(msg->rep, &reason)) { 2424238106Sdes verbose(VERB_ALGO, "no NSECs: %s", reason); 2425238106Sdes errinf(qstate, reason); 2426238106Sdes goto return_bogus; 2427238106Sdes } 2428238106Sdes 2429238106Sdes /* For subtype Name Error. 2430238106Sdes * attempt ANS 2.8.1.0 compatibility where it sets rcode 2431238106Sdes * to nxdomain, but really this is an Nodata/Noerror response. 2432238106Sdes * Find and prove the empty nonterminal in that case */ 2433238106Sdes 2434238106Sdes /* Try to prove absence of the DS with NSEC */ 2435238106Sdes sec = val_nsec_prove_nodata_dsreply( 2436238106Sdes qstate->env, ve, qinfo, msg->rep, vq->key_entry, 2437238106Sdes &proof_ttl, &reason); 2438238106Sdes switch(sec) { 2439238106Sdes case sec_status_secure: 2440238106Sdes verbose(VERB_DETAIL, "NSEC RRset for the " 2441238106Sdes "referral proved no DS."); 2442238106Sdes *ke = key_entry_create_null(qstate->region, 2443238106Sdes qinfo->qname, qinfo->qname_len, 2444238106Sdes qinfo->qclass, proof_ttl, 2445238106Sdes *qstate->env->now); 2446238106Sdes return (*ke) != NULL; 2447238106Sdes case sec_status_insecure: 2448238106Sdes verbose(VERB_DETAIL, "NSEC RRset for the " 2449238106Sdes "referral proved not a delegation point"); 2450238106Sdes *ke = NULL; 2451238106Sdes return 1; 2452238106Sdes case sec_status_bogus: 2453238106Sdes verbose(VERB_DETAIL, "NSEC RRset for the " 2454238106Sdes "referral did not prove no DS."); 2455238106Sdes errinf(qstate, reason); 2456238106Sdes goto return_bogus; 2457238106Sdes case sec_status_unchecked: 2458238106Sdes default: 2459238106Sdes /* NSEC proof did not work, try next */ 2460238106Sdes break; 2461238106Sdes } 2462238106Sdes 2463238106Sdes sec = nsec3_prove_nods(qstate->env, ve, 2464238106Sdes msg->rep->rrsets + msg->rep->an_numrrsets, 2465238106Sdes msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason); 2466238106Sdes switch(sec) { 2467238106Sdes case sec_status_insecure: 2468238106Sdes /* case insecure also continues to unsigned 2469238106Sdes * space. If nsec3-iter-count too high or 2470238106Sdes * optout, then treat below as unsigned */ 2471238106Sdes case sec_status_secure: 2472238106Sdes verbose(VERB_DETAIL, "NSEC3s for the " 2473238106Sdes "referral proved no DS."); 2474238106Sdes *ke = key_entry_create_null(qstate->region, 2475238106Sdes qinfo->qname, qinfo->qname_len, 2476238106Sdes qinfo->qclass, proof_ttl, 2477238106Sdes *qstate->env->now); 2478238106Sdes return (*ke) != NULL; 2479238106Sdes case sec_status_indeterminate: 2480238106Sdes verbose(VERB_DETAIL, "NSEC3s for the " 2481238106Sdes "referral proved no delegation"); 2482238106Sdes *ke = NULL; 2483238106Sdes return 1; 2484238106Sdes case sec_status_bogus: 2485238106Sdes verbose(VERB_DETAIL, "NSEC3s for the " 2486238106Sdes "referral did not prove no DS."); 2487238106Sdes errinf(qstate, reason); 2488238106Sdes goto return_bogus; 2489238106Sdes case sec_status_unchecked: 2490238106Sdes default: 2491238106Sdes /* NSEC3 proof did not work */ 2492238106Sdes break; 2493238106Sdes } 2494238106Sdes 2495238106Sdes /* Apparently, no available NSEC/NSEC3 proved NODATA, so 2496238106Sdes * this is BOGUS. */ 2497238106Sdes verbose(VERB_DETAIL, "DS %s ran out of options, so return " 2498238106Sdes "bogus", val_classification_to_string(subtype)); 2499238106Sdes errinf(qstate, "no DS but also no proof of that"); 2500238106Sdes goto return_bogus; 2501238106Sdes } else if(subtype == VAL_CLASS_CNAME || 2502238106Sdes subtype == VAL_CLASS_CNAMENOANSWER) { 2503238106Sdes /* if the CNAME matches the exact name we want and is signed 2504238106Sdes * properly, then also, we are sure that no DS exists there, 2505238106Sdes * much like a NODATA proof */ 2506238106Sdes enum sec_status sec; 2507238106Sdes struct ub_packed_rrset_key* cname; 2508238106Sdes cname = reply_find_rrset_section_an(msg->rep, qinfo->qname, 2509238106Sdes qinfo->qname_len, LDNS_RR_TYPE_CNAME, qinfo->qclass); 2510238106Sdes if(!cname) { 2511238106Sdes errinf(qstate, "validator classified CNAME but no " 2512238106Sdes "CNAME of the queried name for DS"); 2513238106Sdes goto return_bogus; 2514238106Sdes } 2515238106Sdes if(((struct packed_rrset_data*)cname->entry.data)->rrsig_count 2516238106Sdes == 0) { 2517238106Sdes if(msg->rep->an_numrrsets != 0 && ntohs(msg->rep-> 2518238106Sdes rrsets[0]->rk.type)==LDNS_RR_TYPE_DNAME) { 2519238106Sdes errinf(qstate, "DS got DNAME answer"); 2520238106Sdes } else { 2521238106Sdes errinf(qstate, "DS got unsigned CNAME answer"); 2522238106Sdes } 2523238106Sdes goto return_bogus; 2524238106Sdes } 2525238106Sdes sec = val_verify_rrset_entry(qstate->env, ve, cname, 2526238106Sdes vq->key_entry, &reason); 2527238106Sdes if(sec == sec_status_secure) { 2528238106Sdes verbose(VERB_ALGO, "CNAME validated, " 2529238106Sdes "proof that DS does not exist"); 2530238106Sdes /* and that it is not a referral point */ 2531238106Sdes *ke = NULL; 2532238106Sdes return 1; 2533238106Sdes } 2534238106Sdes errinf(qstate, "CNAME in DS response was not secure."); 2535238106Sdes errinf(qstate, reason); 2536238106Sdes goto return_bogus; 2537238106Sdes } else { 2538238106Sdes verbose(VERB_QUERY, "Encountered an unhandled type of " 2539238106Sdes "DS response, thus bogus."); 2540238106Sdes errinf(qstate, "no DS and"); 2541238106Sdes if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR) { 2542269257Sdes char rc[16]; 2543269257Sdes rc[0]=0; 2544269257Sdes (void)sldns_wire2str_rcode_buf((int)FLAGS_GET_RCODE( 2545269257Sdes msg->rep->flags), rc, sizeof(rc)); 2546238106Sdes errinf(qstate, rc); 2547238106Sdes } else errinf(qstate, val_classification_to_string(subtype)); 2548238106Sdes errinf(qstate, "message fails to prove that"); 2549238106Sdes goto return_bogus; 2550238106Sdes } 2551238106Sdesreturn_bogus: 2552238106Sdes *ke = key_entry_create_bad(qstate->region, qinfo->qname, 2553238106Sdes qinfo->qname_len, qinfo->qclass, 2554238106Sdes BOGUS_KEY_TTL, *qstate->env->now); 2555238106Sdes return (*ke) != NULL; 2556238106Sdes} 2557238106Sdes 2558238106Sdes/** 2559238106Sdes * Process DS response. Called from inform_supers. 2560238106Sdes * Because it is in inform_supers, the mesh itself is busy doing callbacks 2561238106Sdes * for a state that is to be deleted soon; don't touch the mesh; instead 2562238106Sdes * set a state in the super, as the super will be reactivated soon. 2563238106Sdes * Perform processing to determine what state to set in the super. 2564238106Sdes * 2565238106Sdes * @param qstate: query state that is validating and asked for a DS. 2566238106Sdes * @param vq: validator query state 2567238106Sdes * @param id: module id. 2568238106Sdes * @param rcode: rcode result value. 2569238106Sdes * @param msg: result message (if rcode is OK). 2570238106Sdes * @param qinfo: from the sub query state, query info. 2571238106Sdes * @param origin: the origin of msg. 2572238106Sdes */ 2573238106Sdesstatic void 2574238106Sdesprocess_ds_response(struct module_qstate* qstate, struct val_qstate* vq, 2575238106Sdes int id, int rcode, struct dns_msg* msg, struct query_info* qinfo, 2576238106Sdes struct sock_list* origin) 2577238106Sdes{ 2578238106Sdes struct key_entry_key* dske = NULL; 2579238106Sdes uint8_t* olds = vq->empty_DS_name; 2580238106Sdes vq->empty_DS_name = NULL; 2581238106Sdes if(!ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske)) { 2582238106Sdes log_err("malloc failure in process_ds_response"); 2583238106Sdes vq->key_entry = NULL; /* make it error */ 2584238106Sdes vq->state = VAL_VALIDATE_STATE; 2585238106Sdes return; 2586238106Sdes } 2587238106Sdes if(dske == NULL) { 2588238106Sdes vq->empty_DS_name = regional_alloc_init(qstate->region, 2589238106Sdes qinfo->qname, qinfo->qname_len); 2590238106Sdes if(!vq->empty_DS_name) { 2591238106Sdes log_err("malloc failure in empty_DS_name"); 2592238106Sdes vq->key_entry = NULL; /* make it error */ 2593238106Sdes vq->state = VAL_VALIDATE_STATE; 2594238106Sdes return; 2595238106Sdes } 2596238106Sdes vq->empty_DS_len = qinfo->qname_len; 2597238106Sdes vq->chain_blacklist = NULL; 2598238106Sdes /* ds response indicated that we aren't on a delegation point. 2599238106Sdes * Keep the forState.state on FINDKEY. */ 2600238106Sdes } else if(key_entry_isgood(dske)) { 2601238106Sdes vq->ds_rrset = key_entry_get_rrset(dske, qstate->region); 2602238106Sdes if(!vq->ds_rrset) { 2603238106Sdes log_err("malloc failure in process DS"); 2604238106Sdes vq->key_entry = NULL; /* make it error */ 2605238106Sdes vq->state = VAL_VALIDATE_STATE; 2606238106Sdes return; 2607238106Sdes } 2608238106Sdes vq->chain_blacklist = NULL; /* fresh blacklist for next part*/ 2609238106Sdes /* Keep the forState.state on FINDKEY. */ 2610238106Sdes } else if(key_entry_isbad(dske) 2611238106Sdes && vq->restart_count < VAL_MAX_RESTART_COUNT) { 2612238106Sdes vq->empty_DS_name = olds; 2613238106Sdes val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1); 2614238106Sdes qstate->errinf = NULL; 2615238106Sdes vq->restart_count++; 2616238106Sdes } else { 2617238106Sdes if(key_entry_isbad(dske)) { 2618238106Sdes errinf_origin(qstate, origin); 2619238106Sdes errinf_dname(qstate, "for DS", qinfo->qname); 2620238106Sdes } 2621238106Sdes /* NOTE: the reason for the DS to be not good (that is, 2622238106Sdes * either bad or null) should have been logged by 2623238106Sdes * dsResponseToKE. */ 2624238106Sdes vq->key_entry = dske; 2625238106Sdes /* The FINDKEY phase has ended, so move on. */ 2626238106Sdes vq->state = VAL_VALIDATE_STATE; 2627238106Sdes } 2628238106Sdes} 2629238106Sdes 2630238106Sdes/** 2631238106Sdes * Process DNSKEY response. Called from inform_supers. 2632238106Sdes * Sets the key entry in the state. 2633238106Sdes * Because it is in inform_supers, the mesh itself is busy doing callbacks 2634238106Sdes * for a state that is to be deleted soon; don't touch the mesh; instead 2635238106Sdes * set a state in the super, as the super will be reactivated soon. 2636238106Sdes * Perform processing to determine what state to set in the super. 2637238106Sdes * 2638238106Sdes * @param qstate: query state that is validating and asked for a DNSKEY. 2639238106Sdes * @param vq: validator query state 2640238106Sdes * @param id: module id. 2641238106Sdes * @param rcode: rcode result value. 2642238106Sdes * @param msg: result message (if rcode is OK). 2643238106Sdes * @param qinfo: from the sub query state, query info. 2644238106Sdes * @param origin: the origin of msg. 2645238106Sdes */ 2646238106Sdesstatic void 2647238106Sdesprocess_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, 2648238106Sdes int id, int rcode, struct dns_msg* msg, struct query_info* qinfo, 2649238106Sdes struct sock_list* origin) 2650238106Sdes{ 2651238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2652238106Sdes struct key_entry_key* old = vq->key_entry; 2653238106Sdes struct ub_packed_rrset_key* dnskey = NULL; 2654238106Sdes int downprot; 2655238106Sdes char* reason = NULL; 2656238106Sdes 2657238106Sdes if(rcode == LDNS_RCODE_NOERROR) 2658238106Sdes dnskey = reply_find_answer_rrset(qinfo, msg->rep); 2659238106Sdes 2660238106Sdes if(dnskey == NULL) { 2661238106Sdes /* bad response */ 2662238106Sdes verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to " 2663238106Sdes "DNSKEY query."); 2664238106Sdes if(vq->restart_count < VAL_MAX_RESTART_COUNT) { 2665238106Sdes val_blacklist(&vq->chain_blacklist, qstate->region, 2666238106Sdes origin, 1); 2667238106Sdes qstate->errinf = NULL; 2668238106Sdes vq->restart_count++; 2669238106Sdes return; 2670238106Sdes } 2671238106Sdes vq->key_entry = key_entry_create_bad(qstate->region, 2672238106Sdes qinfo->qname, qinfo->qname_len, qinfo->qclass, 2673238106Sdes BOGUS_KEY_TTL, *qstate->env->now); 2674238106Sdes if(!vq->key_entry) { 2675238106Sdes log_err("alloc failure in missing dnskey response"); 2676238106Sdes /* key_entry is NULL for failure in Validate */ 2677238106Sdes } 2678238106Sdes errinf(qstate, "No DNSKEY record"); 2679238106Sdes errinf_origin(qstate, origin); 2680238106Sdes errinf_dname(qstate, "for key", qinfo->qname); 2681238106Sdes vq->state = VAL_VALIDATE_STATE; 2682238106Sdes return; 2683238106Sdes } 2684238106Sdes if(!vq->ds_rrset) { 2685238106Sdes log_err("internal error: no DS rrset for new DNSKEY response"); 2686238106Sdes vq->key_entry = NULL; 2687238106Sdes vq->state = VAL_VALIDATE_STATE; 2688238106Sdes return; 2689238106Sdes } 2690238106Sdes downprot = 1; 2691238106Sdes vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, 2692238106Sdes ve, dnskey, vq->ds_rrset, downprot, &reason); 2693238106Sdes 2694238106Sdes if(!vq->key_entry) { 2695238106Sdes log_err("out of memory in verify new DNSKEYs"); 2696238106Sdes vq->state = VAL_VALIDATE_STATE; 2697238106Sdes return; 2698238106Sdes } 2699238106Sdes /* If the key entry isBad or isNull, then we can move on to the next 2700238106Sdes * state. */ 2701238106Sdes if(!key_entry_isgood(vq->key_entry)) { 2702238106Sdes if(key_entry_isbad(vq->key_entry)) { 2703238106Sdes if(vq->restart_count < VAL_MAX_RESTART_COUNT) { 2704238106Sdes val_blacklist(&vq->chain_blacklist, 2705238106Sdes qstate->region, origin, 1); 2706238106Sdes qstate->errinf = NULL; 2707238106Sdes vq->restart_count++; 2708238106Sdes vq->key_entry = old; 2709238106Sdes return; 2710238106Sdes } 2711238106Sdes verbose(VERB_DETAIL, "Did not match a DS to a DNSKEY, " 2712238106Sdes "thus bogus."); 2713238106Sdes errinf(qstate, reason); 2714238106Sdes errinf_origin(qstate, origin); 2715238106Sdes errinf_dname(qstate, "for key", qinfo->qname); 2716238106Sdes } 2717238106Sdes vq->chain_blacklist = NULL; 2718238106Sdes vq->state = VAL_VALIDATE_STATE; 2719238106Sdes return; 2720238106Sdes } 2721238106Sdes vq->chain_blacklist = NULL; 2722238106Sdes qstate->errinf = NULL; 2723238106Sdes 2724238106Sdes /* The DNSKEY validated, so cache it as a trusted key rrset. */ 2725238106Sdes key_cache_insert(ve->kcache, vq->key_entry, qstate); 2726238106Sdes 2727238106Sdes /* If good, we stay in the FINDKEY state. */ 2728238106Sdes log_query_info(VERB_DETAIL, "validated DNSKEY", qinfo); 2729238106Sdes} 2730238106Sdes 2731238106Sdes/** 2732238106Sdes * Process prime response 2733238106Sdes * Sets the key entry in the state. 2734238106Sdes * 2735238106Sdes * @param qstate: query state that is validating and primed a trust anchor. 2736238106Sdes * @param vq: validator query state 2737238106Sdes * @param id: module id. 2738238106Sdes * @param rcode: rcode result value. 2739238106Sdes * @param msg: result message (if rcode is OK). 2740238106Sdes * @param origin: the origin of msg. 2741238106Sdes */ 2742238106Sdesstatic void 2743238106Sdesprocess_prime_response(struct module_qstate* qstate, struct val_qstate* vq, 2744238106Sdes int id, int rcode, struct dns_msg* msg, struct sock_list* origin) 2745238106Sdes{ 2746238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2747238106Sdes struct ub_packed_rrset_key* dnskey_rrset = NULL; 2748238106Sdes struct trust_anchor* ta = anchor_find(qstate->env->anchors, 2749238106Sdes vq->trust_anchor_name, vq->trust_anchor_labs, 2750238106Sdes vq->trust_anchor_len, vq->qchase.qclass); 2751238106Sdes if(!ta) { 2752238106Sdes /* trust anchor revoked, restart with less anchors */ 2753238106Sdes vq->state = VAL_INIT_STATE; 2754238106Sdes if(!vq->trust_anchor_name) 2755238106Sdes vq->state = VAL_VALIDATE_STATE; /* break a loop */ 2756238106Sdes vq->trust_anchor_name = NULL; 2757238106Sdes return; 2758238106Sdes } 2759238106Sdes /* Fetch and validate the keyEntry that corresponds to the 2760238106Sdes * current trust anchor. */ 2761238106Sdes if(rcode == LDNS_RCODE_NOERROR) { 2762238106Sdes dnskey_rrset = reply_find_rrset_section_an(msg->rep, 2763238106Sdes ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY, 2764238106Sdes ta->dclass); 2765238106Sdes } 2766238106Sdes if(ta->autr) { 2767238106Sdes if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) { 2768238106Sdes /* trust anchor revoked, restart with less anchors */ 2769238106Sdes vq->state = VAL_INIT_STATE; 2770238106Sdes vq->trust_anchor_name = NULL; 2771238106Sdes return; 2772238106Sdes } 2773238106Sdes } 2774238106Sdes vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id); 2775238106Sdes lock_basic_unlock(&ta->lock); 2776238106Sdes if(vq->key_entry) { 2777238106Sdes if(key_entry_isbad(vq->key_entry) 2778238106Sdes && vq->restart_count < VAL_MAX_RESTART_COUNT) { 2779238106Sdes val_blacklist(&vq->chain_blacklist, qstate->region, 2780238106Sdes origin, 1); 2781238106Sdes qstate->errinf = NULL; 2782238106Sdes vq->restart_count++; 2783238106Sdes vq->key_entry = NULL; 2784238106Sdes vq->state = VAL_INIT_STATE; 2785238106Sdes return; 2786238106Sdes } 2787238106Sdes vq->chain_blacklist = NULL; 2788238106Sdes errinf_origin(qstate, origin); 2789238106Sdes errinf_dname(qstate, "for trust anchor", ta->name); 2790238106Sdes /* store the freshly primed entry in the cache */ 2791238106Sdes key_cache_insert(ve->kcache, vq->key_entry, qstate); 2792238106Sdes } 2793238106Sdes 2794238106Sdes /* If the result of the prime is a null key, skip the FINDKEY state.*/ 2795238106Sdes if(!vq->key_entry || key_entry_isnull(vq->key_entry) || 2796238106Sdes key_entry_isbad(vq->key_entry)) { 2797238106Sdes vq->state = VAL_VALIDATE_STATE; 2798238106Sdes } 2799238106Sdes /* the qstate will be reactivated after inform_super is done */ 2800238106Sdes} 2801238106Sdes 2802238106Sdes/** 2803238106Sdes * Process DLV response. Called from inform_supers. 2804238106Sdes * Because it is in inform_supers, the mesh itself is busy doing callbacks 2805238106Sdes * for a state that is to be deleted soon; don't touch the mesh; instead 2806238106Sdes * set a state in the super, as the super will be reactivated soon. 2807238106Sdes * Perform processing to determine what state to set in the super. 2808238106Sdes * 2809238106Sdes * @param qstate: query state that is validating and asked for a DLV. 2810238106Sdes * @param vq: validator query state 2811238106Sdes * @param id: module id. 2812238106Sdes * @param rcode: rcode result value. 2813238106Sdes * @param msg: result message (if rcode is OK). 2814238106Sdes * @param qinfo: from the sub query state, query info. 2815238106Sdes */ 2816238106Sdesstatic void 2817238106Sdesprocess_dlv_response(struct module_qstate* qstate, struct val_qstate* vq, 2818238106Sdes int id, int rcode, struct dns_msg* msg, struct query_info* qinfo) 2819238106Sdes{ 2820238106Sdes struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; 2821238106Sdes 2822238106Sdes verbose(VERB_ALGO, "process dlv response to super"); 2823238106Sdes if(rcode != LDNS_RCODE_NOERROR) { 2824238106Sdes /* lookup failed, set in vq to give up */ 2825238106Sdes vq->dlv_status = dlv_error; 2826238106Sdes verbose(VERB_ALGO, "response is error"); 2827238106Sdes return; 2828238106Sdes } 2829238106Sdes if(msg->rep->security != sec_status_secure) { 2830238106Sdes vq->dlv_status = dlv_error; 2831238106Sdes verbose(VERB_ALGO, "response is not secure, %s", 2832238106Sdes sec_status_to_string(msg->rep->security)); 2833238106Sdes return; 2834238106Sdes } 2835238106Sdes /* was the lookup a success? validated DLV? */ 2836238106Sdes if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NOERROR && 2837238106Sdes msg->rep->an_numrrsets == 1 && 2838238106Sdes msg->rep->security == sec_status_secure && 2839238106Sdes ntohs(msg->rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_DLV && 2840238106Sdes ntohs(msg->rep->rrsets[0]->rk.rrset_class) == qinfo->qclass && 2841238106Sdes query_dname_compare(msg->rep->rrsets[0]->rk.dname, 2842238106Sdes vq->dlv_lookup_name) == 0) { 2843238106Sdes /* yay! it is just like a DS */ 2844238106Sdes vq->ds_rrset = (struct ub_packed_rrset_key*) 2845238106Sdes regional_alloc_init(qstate->region, 2846238106Sdes msg->rep->rrsets[0], sizeof(*vq->ds_rrset)); 2847238106Sdes if(!vq->ds_rrset) { 2848238106Sdes log_err("out of memory in process_dlv"); 2849238106Sdes return; 2850238106Sdes } 2851238106Sdes vq->ds_rrset->entry.key = vq->ds_rrset; 2852238106Sdes vq->ds_rrset->rk.dname = (uint8_t*)regional_alloc_init( 2853238106Sdes qstate->region, vq->ds_rrset->rk.dname, 2854238106Sdes vq->ds_rrset->rk.dname_len); 2855238106Sdes if(!vq->ds_rrset->rk.dname) { 2856238106Sdes log_err("out of memory in process_dlv"); 2857238106Sdes vq->dlv_status = dlv_error; 2858238106Sdes return; 2859238106Sdes } 2860238106Sdes vq->ds_rrset->entry.data = regional_alloc_init(qstate->region, 2861238106Sdes vq->ds_rrset->entry.data, 2862238106Sdes packed_rrset_sizeof(vq->ds_rrset->entry.data)); 2863238106Sdes if(!vq->ds_rrset->entry.data) { 2864238106Sdes log_err("out of memory in process_dlv"); 2865238106Sdes vq->dlv_status = dlv_error; 2866238106Sdes return; 2867238106Sdes } 2868238106Sdes packed_rrset_ptr_fixup(vq->ds_rrset->entry.data); 2869238106Sdes /* make vq do a DNSKEY query next up */ 2870238106Sdes vq->dlv_status = dlv_success; 2871238106Sdes return; 2872238106Sdes } 2873238106Sdes /* store NSECs into negative cache */ 2874238106Sdes val_neg_addreply(ve->neg_cache, msg->rep); 2875238106Sdes 2876238106Sdes /* was the lookup a failure? 2877238106Sdes * if we have to go up into the DLV for a higher DLV anchor 2878238106Sdes * then set this in the vq, so it can make queries when activated. 2879238106Sdes * See if the NSECs indicate that we should look for higher DLV 2880238106Sdes * or, that there is no DLV securely */ 2881238106Sdes if(!val_nsec_check_dlv(qinfo, msg->rep, &vq->dlv_lookup_name, 2882238106Sdes &vq->dlv_lookup_name_len)) { 2883238106Sdes vq->dlv_status = dlv_error; 2884238106Sdes verbose(VERB_ALGO, "nsec error"); 2885238106Sdes return; 2886238106Sdes } 2887238106Sdes if(!dname_subdomain_c(vq->dlv_lookup_name, 2888238106Sdes qstate->env->anchors->dlv_anchor->name)) { 2889238106Sdes vq->dlv_status = dlv_there_is_no_dlv; 2890238106Sdes return; 2891238106Sdes } 2892238106Sdes vq->dlv_status = dlv_ask_higher; 2893238106Sdes} 2894238106Sdes 2895238106Sdes/* 2896238106Sdes * inform validator super. 2897238106Sdes * 2898238106Sdes * @param qstate: query state that finished. 2899238106Sdes * @param id: module id. 2900238106Sdes * @param super: the qstate to inform. 2901238106Sdes */ 2902238106Sdesvoid 2903238106Sdesval_inform_super(struct module_qstate* qstate, int id, 2904238106Sdes struct module_qstate* super) 2905238106Sdes{ 2906238106Sdes struct val_qstate* vq = (struct val_qstate*)super->minfo[id]; 2907238106Sdes log_query_info(VERB_ALGO, "validator: inform_super, sub is", 2908238106Sdes &qstate->qinfo); 2909238106Sdes log_query_info(VERB_ALGO, "super is", &super->qinfo); 2910238106Sdes if(!vq) { 2911238106Sdes verbose(VERB_ALGO, "super: has no validator state"); 2912238106Sdes return; 2913238106Sdes } 2914238106Sdes if(vq->wait_prime_ta) { 2915238106Sdes vq->wait_prime_ta = 0; 2916238106Sdes process_prime_response(super, vq, id, qstate->return_rcode, 2917238106Sdes qstate->return_msg, qstate->reply_origin); 2918238106Sdes return; 2919238106Sdes } 2920238106Sdes if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) { 2921238106Sdes process_ds_response(super, vq, id, qstate->return_rcode, 2922238106Sdes qstate->return_msg, &qstate->qinfo, 2923238106Sdes qstate->reply_origin); 2924238106Sdes return; 2925238106Sdes } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) { 2926238106Sdes process_dnskey_response(super, vq, id, qstate->return_rcode, 2927238106Sdes qstate->return_msg, &qstate->qinfo, 2928238106Sdes qstate->reply_origin); 2929238106Sdes return; 2930238106Sdes } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DLV) { 2931238106Sdes process_dlv_response(super, vq, id, qstate->return_rcode, 2932238106Sdes qstate->return_msg, &qstate->qinfo); 2933238106Sdes return; 2934238106Sdes } 2935238106Sdes log_err("internal error in validator: no inform_supers possible"); 2936238106Sdes} 2937238106Sdes 2938238106Sdesvoid 2939238106Sdesval_clear(struct module_qstate* qstate, int id) 2940238106Sdes{ 2941238106Sdes if(!qstate) 2942238106Sdes return; 2943238106Sdes /* everything is allocated in the region, so assign NULL */ 2944238106Sdes qstate->minfo[id] = NULL; 2945238106Sdes} 2946238106Sdes 2947238106Sdessize_t 2948238106Sdesval_get_mem(struct module_env* env, int id) 2949238106Sdes{ 2950238106Sdes struct val_env* ve = (struct val_env*)env->modinfo[id]; 2951238106Sdes if(!ve) 2952238106Sdes return 0; 2953238106Sdes return sizeof(*ve) + key_cache_get_mem(ve->kcache) + 2954238106Sdes val_neg_get_mem(ve->neg_cache) + 2955238106Sdes sizeof(size_t)*2*ve->nsec3_keyiter_count; 2956238106Sdes} 2957238106Sdes 2958238106Sdes/** 2959238106Sdes * The validator function block 2960238106Sdes */ 2961238106Sdesstatic struct module_func_block val_block = { 2962238106Sdes "validator", 2963238106Sdes &val_init, &val_deinit, &val_operate, &val_inform_super, &val_clear, 2964238106Sdes &val_get_mem 2965238106Sdes}; 2966238106Sdes 2967238106Sdesstruct module_func_block* 2968238106Sdesval_get_funcblock(void) 2969238106Sdes{ 2970238106Sdes return &val_block; 2971238106Sdes} 2972238106Sdes 2973238106Sdesconst char* 2974238106Sdesval_state_to_string(enum val_state state) 2975238106Sdes{ 2976238106Sdes switch(state) { 2977238106Sdes case VAL_INIT_STATE: return "VAL_INIT_STATE"; 2978238106Sdes case VAL_FINDKEY_STATE: return "VAL_FINDKEY_STATE"; 2979238106Sdes case VAL_VALIDATE_STATE: return "VAL_VALIDATE_STATE"; 2980238106Sdes case VAL_FINISHED_STATE: return "VAL_FINISHED_STATE"; 2981238106Sdes case VAL_DLVLOOKUP_STATE: return "VAL_DLVLOOKUP_STATE"; 2982238106Sdes } 2983238106Sdes return "UNKNOWN VALIDATOR STATE"; 2984238106Sdes} 2985238106Sdes 2986