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