1238106Sdes/* 2238106Sdes * validator/autotrust.c - RFC5011 trust anchor management for unbound. 3238106Sdes * 4238106Sdes * Copyright (c) 2009, 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 * Contains autotrust implementation. The implementation was taken from 40238106Sdes * the autotrust daemon (BSD licensed), written by Matthijs Mekking. 41238106Sdes * It was modified to fit into unbound. The state table process is the same. 42238106Sdes */ 43238106Sdes#include "config.h" 44238106Sdes#include <ldns/ldns.h> 45238106Sdes#include "validator/autotrust.h" 46238106Sdes#include "validator/val_anchor.h" 47238106Sdes#include "validator/val_utils.h" 48238106Sdes#include "validator/val_sigcrypt.h" 49238106Sdes#include "util/data/dname.h" 50238106Sdes#include "util/data/packed_rrset.h" 51238106Sdes#include "util/log.h" 52238106Sdes#include "util/module.h" 53238106Sdes#include "util/net_help.h" 54238106Sdes#include "util/config_file.h" 55238106Sdes#include "util/regional.h" 56238106Sdes#include "util/random.h" 57238106Sdes#include "util/data/msgparse.h" 58238106Sdes#include "services/mesh.h" 59238106Sdes#include "services/cache/rrset.h" 60238106Sdes#include "validator/val_kcache.h" 61238106Sdes 62238106Sdes/** number of times a key must be seen before it can become valid */ 63238106Sdes#define MIN_PENDINGCOUNT 2 64238106Sdes 65238106Sdes/** Event: Revoked */ 66238106Sdesstatic void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c); 67238106Sdes 68238106Sdesstruct autr_global_data* autr_global_create(void) 69238106Sdes{ 70238106Sdes struct autr_global_data* global; 71238106Sdes global = (struct autr_global_data*)malloc(sizeof(*global)); 72238106Sdes if(!global) 73238106Sdes return NULL; 74238106Sdes rbtree_init(&global->probe, &probetree_cmp); 75238106Sdes return global; 76238106Sdes} 77238106Sdes 78238106Sdesvoid autr_global_delete(struct autr_global_data* global) 79238106Sdes{ 80238106Sdes if(!global) 81238106Sdes return; 82238106Sdes /* elements deleted by parent */ 83238106Sdes memset(global, 0, sizeof(*global)); 84238106Sdes free(global); 85238106Sdes} 86238106Sdes 87238106Sdesint probetree_cmp(const void* x, const void* y) 88238106Sdes{ 89238106Sdes struct trust_anchor* a = (struct trust_anchor*)x; 90238106Sdes struct trust_anchor* b = (struct trust_anchor*)y; 91238106Sdes log_assert(a->autr && b->autr); 92238106Sdes if(a->autr->next_probe_time < b->autr->next_probe_time) 93238106Sdes return -1; 94238106Sdes if(a->autr->next_probe_time > b->autr->next_probe_time) 95238106Sdes return 1; 96238106Sdes /* time is equal, sort on trust point identity */ 97238106Sdes return anchor_cmp(x, y); 98238106Sdes} 99238106Sdes 100238106Sdessize_t 101238106Sdesautr_get_num_anchors(struct val_anchors* anchors) 102238106Sdes{ 103238106Sdes size_t res = 0; 104238106Sdes if(!anchors) 105238106Sdes return 0; 106238106Sdes lock_basic_lock(&anchors->lock); 107238106Sdes if(anchors->autr) 108238106Sdes res = anchors->autr->probe.count; 109238106Sdes lock_basic_unlock(&anchors->lock); 110238106Sdes return res; 111238106Sdes} 112238106Sdes 113238106Sdes/** Position in string */ 114238106Sdesstatic int 115238106Sdesposition_in_string(char *str, const char* sub) 116238106Sdes{ 117238106Sdes char* pos = strstr(str, sub); 118238106Sdes if(pos) 119238106Sdes return (int)(pos-str)+(int)strlen(sub); 120238106Sdes return -1; 121238106Sdes} 122238106Sdes 123238106Sdes/** Debug routine to print pretty key information */ 124238106Sdesstatic void 125238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level, 126238106Sdes const char* format, ...) ATTR_FORMAT(printf, 3, 4); 127238106Sdes 128238106Sdes/** 129238106Sdes * Implementation of debug pretty key print 130238106Sdes * @param ta: trust anchor key with DNSKEY data. 131238106Sdes * @param level: verbosity level to print at. 132238106Sdes * @param format: printf style format string. 133238106Sdes */ 134238106Sdesstatic void 135238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level, 136238106Sdes const char* format, ...) 137238106Sdes{ 138238106Sdes va_list args; 139238106Sdes va_start(args, format); 140238106Sdes if(verbosity >= level) { 141238106Sdes char* str = ldns_rdf2str(ldns_rr_owner(ta->rr)); 142238106Sdes int keytag = (int)ldns_calc_keytag(ta->rr); 143238106Sdes char msg[MAXSYSLOGMSGLEN]; 144238106Sdes vsnprintf(msg, sizeof(msg), format, args); 145238106Sdes verbose(level, "%s key %d %s", str?str:"??", keytag, msg); 146238106Sdes free(str); 147238106Sdes } 148238106Sdes va_end(args); 149238106Sdes} 150238106Sdes 151238106Sdes/** 152238106Sdes * Parse comments 153238106Sdes * @param str: to parse 154238106Sdes * @param ta: trust key autotrust metadata 155238106Sdes * @return false on failure. 156238106Sdes */ 157238106Sdesstatic int 158238106Sdesparse_comments(char* str, struct autr_ta* ta) 159238106Sdes{ 160238106Sdes int len = (int)strlen(str), pos = 0, timestamp = 0; 161238106Sdes char* comment = (char*) malloc(sizeof(char)*len+1); 162238106Sdes char* comments = comment; 163238106Sdes if(!comment) { 164238106Sdes log_err("malloc failure in parse"); 165238106Sdes return 0; 166238106Sdes } 167238106Sdes /* skip over whitespace and data at start of line */ 168238106Sdes while (*str != '\0' && *str != ';') 169238106Sdes str++; 170238106Sdes if (*str == ';') 171238106Sdes str++; 172238106Sdes /* copy comments */ 173238106Sdes while (*str != '\0') 174238106Sdes { 175238106Sdes *comments = *str; 176238106Sdes comments++; 177238106Sdes str++; 178238106Sdes } 179238106Sdes *comments = '\0'; 180238106Sdes 181238106Sdes comments = comment; 182238106Sdes 183238106Sdes /* read state */ 184238106Sdes pos = position_in_string(comments, "state="); 185238106Sdes if (pos >= (int) strlen(comments)) 186238106Sdes { 187238106Sdes log_err("parse error"); 188238106Sdes free(comment); 189238106Sdes return 0; 190238106Sdes } 191238106Sdes if (pos <= 0) 192238106Sdes ta->s = AUTR_STATE_VALID; 193238106Sdes else 194238106Sdes { 195238106Sdes int s = (int) comments[pos] - '0'; 196238106Sdes switch(s) 197238106Sdes { 198238106Sdes case AUTR_STATE_START: 199238106Sdes case AUTR_STATE_ADDPEND: 200238106Sdes case AUTR_STATE_VALID: 201238106Sdes case AUTR_STATE_MISSING: 202238106Sdes case AUTR_STATE_REVOKED: 203238106Sdes case AUTR_STATE_REMOVED: 204238106Sdes ta->s = s; 205238106Sdes break; 206238106Sdes default: 207238106Sdes verbose_key(ta, VERB_OPS, "has undefined " 208238106Sdes "state, considered NewKey"); 209238106Sdes ta->s = AUTR_STATE_START; 210238106Sdes break; 211238106Sdes } 212238106Sdes } 213238106Sdes /* read pending count */ 214238106Sdes pos = position_in_string(comments, "count="); 215238106Sdes if (pos >= (int) strlen(comments)) 216238106Sdes { 217238106Sdes log_err("parse error"); 218238106Sdes free(comment); 219238106Sdes return 0; 220238106Sdes } 221238106Sdes if (pos <= 0) 222238106Sdes ta->pending_count = 0; 223238106Sdes else 224238106Sdes { 225238106Sdes comments += pos; 226238106Sdes ta->pending_count = (uint8_t)atoi(comments); 227238106Sdes } 228238106Sdes 229238106Sdes /* read last change */ 230238106Sdes pos = position_in_string(comments, "lastchange="); 231238106Sdes if (pos >= (int) strlen(comments)) 232238106Sdes { 233238106Sdes log_err("parse error"); 234238106Sdes free(comment); 235238106Sdes return 0; 236238106Sdes } 237238106Sdes if (pos >= 0) 238238106Sdes { 239238106Sdes comments += pos; 240238106Sdes timestamp = atoi(comments); 241238106Sdes } 242238106Sdes if (pos < 0 || !timestamp) 243238106Sdes ta->last_change = 0; 244238106Sdes else 245238106Sdes ta->last_change = (uint32_t)timestamp; 246238106Sdes 247238106Sdes free(comment); 248238106Sdes return 1; 249238106Sdes} 250238106Sdes 251238106Sdes/** Check if a line contains data (besides comments) */ 252238106Sdesstatic int 253238106Sdesstr_contains_data(char* str, char comment) 254238106Sdes{ 255238106Sdes while (*str != '\0') { 256238106Sdes if (*str == comment || *str == '\n') 257238106Sdes return 0; 258238106Sdes if (*str != ' ' && *str != '\t') 259238106Sdes return 1; 260238106Sdes str++; 261238106Sdes } 262238106Sdes return 0; 263238106Sdes} 264238106Sdes 265238106Sdes/** Get DNSKEY flags */ 266238106Sdesstatic int 267238106Sdesdnskey_flags(ldns_rr* rr) 268238106Sdes{ 269238106Sdes if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) 270238106Sdes return 0; 271238106Sdes return (int)ldns_read_uint16(ldns_rdf_data(ldns_rr_dnskey_flags(rr))); 272238106Sdes} 273238106Sdes 274238106Sdes 275238106Sdes/** Check if KSK DNSKEY */ 276238106Sdesstatic int 277238106Sdesrr_is_dnskey_sep(ldns_rr* rr) 278238106Sdes{ 279238106Sdes return (dnskey_flags(rr)&DNSKEY_BIT_SEP); 280238106Sdes} 281238106Sdes 282238106Sdes/** Check if REVOKED DNSKEY */ 283238106Sdesstatic int 284238106Sdesrr_is_dnskey_revoked(ldns_rr* rr) 285238106Sdes{ 286238106Sdes return (dnskey_flags(rr)&LDNS_KEY_REVOKE_KEY); 287238106Sdes} 288238106Sdes 289238106Sdes/** create ta */ 290238106Sdesstatic struct autr_ta* 291238106Sdesautr_ta_create(ldns_rr* rr) 292238106Sdes{ 293238106Sdes struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta)); 294238106Sdes if(!ta) { 295238106Sdes ldns_rr_free(rr); 296238106Sdes return NULL; 297238106Sdes } 298238106Sdes ta->rr = rr; 299238106Sdes return ta; 300238106Sdes} 301238106Sdes 302238106Sdes/** create tp */ 303238106Sdesstatic struct trust_anchor* 304238106Sdesautr_tp_create(struct val_anchors* anchors, ldns_rdf* own, uint16_t dc) 305238106Sdes{ 306238106Sdes struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp)); 307238106Sdes if(!tp) return NULL; 308238106Sdes tp->name = memdup(ldns_rdf_data(own), ldns_rdf_size(own)); 309238106Sdes if(!tp->name) { 310238106Sdes free(tp); 311238106Sdes return NULL; 312238106Sdes } 313238106Sdes tp->namelen = ldns_rdf_size(own); 314238106Sdes tp->namelabs = dname_count_labels(tp->name); 315238106Sdes tp->node.key = tp; 316238106Sdes tp->dclass = dc; 317238106Sdes tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr)); 318238106Sdes if(!tp->autr) { 319238106Sdes free(tp->name); 320238106Sdes free(tp); 321238106Sdes return NULL; 322238106Sdes } 323238106Sdes tp->autr->pnode.key = tp; 324238106Sdes 325238106Sdes lock_basic_lock(&anchors->lock); 326238106Sdes if(!rbtree_insert(anchors->tree, &tp->node)) { 327238106Sdes lock_basic_unlock(&anchors->lock); 328238106Sdes log_err("trust anchor presented twice"); 329238106Sdes free(tp->name); 330238106Sdes free(tp->autr); 331238106Sdes free(tp); 332238106Sdes return NULL; 333238106Sdes } 334238106Sdes if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) { 335238106Sdes (void)rbtree_delete(anchors->tree, tp); 336238106Sdes lock_basic_unlock(&anchors->lock); 337238106Sdes log_err("trust anchor in probetree twice"); 338238106Sdes free(tp->name); 339238106Sdes free(tp->autr); 340238106Sdes free(tp); 341238106Sdes return NULL; 342238106Sdes } 343238106Sdes lock_basic_unlock(&anchors->lock); 344238106Sdes lock_basic_init(&tp->lock); 345238106Sdes lock_protect(&tp->lock, tp, sizeof(*tp)); 346238106Sdes lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr)); 347238106Sdes return tp; 348238106Sdes} 349238106Sdes 350238106Sdes/** delete assembled rrsets */ 351238106Sdesstatic void 352238106Sdesautr_rrset_delete(struct ub_packed_rrset_key* r) 353238106Sdes{ 354238106Sdes if(r) { 355238106Sdes free(r->rk.dname); 356238106Sdes free(r->entry.data); 357238106Sdes free(r); 358238106Sdes } 359238106Sdes} 360238106Sdes 361238106Sdesvoid autr_point_delete(struct trust_anchor* tp) 362238106Sdes{ 363238106Sdes if(!tp) 364238106Sdes return; 365238106Sdes lock_unprotect(&tp->lock, tp); 366238106Sdes lock_unprotect(&tp->lock, tp->autr); 367238106Sdes lock_basic_destroy(&tp->lock); 368238106Sdes autr_rrset_delete(tp->ds_rrset); 369238106Sdes autr_rrset_delete(tp->dnskey_rrset); 370238106Sdes if(tp->autr) { 371238106Sdes struct autr_ta* p = tp->autr->keys, *np; 372238106Sdes while(p) { 373238106Sdes np = p->next; 374238106Sdes ldns_rr_free(p->rr); 375238106Sdes free(p); 376238106Sdes p = np; 377238106Sdes } 378238106Sdes free(tp->autr->file); 379238106Sdes free(tp->autr); 380238106Sdes } 381238106Sdes free(tp->name); 382238106Sdes free(tp); 383238106Sdes} 384238106Sdes 385238106Sdes/** find or add a new trust point for autotrust */ 386238106Sdesstatic struct trust_anchor* 387238106Sdesfind_add_tp(struct val_anchors* anchors, ldns_rr* rr) 388238106Sdes{ 389238106Sdes struct trust_anchor* tp; 390238106Sdes ldns_rdf* own = ldns_rr_owner(rr); 391238106Sdes tp = anchor_find(anchors, ldns_rdf_data(own), 392238106Sdes dname_count_labels(ldns_rdf_data(own)), 393238106Sdes ldns_rdf_size(own), ldns_rr_get_class(rr)); 394238106Sdes if(tp) { 395238106Sdes if(!tp->autr) { 396238106Sdes log_err("anchor cannot be with and without autotrust"); 397238106Sdes lock_basic_unlock(&tp->lock); 398238106Sdes return NULL; 399238106Sdes } 400238106Sdes return tp; 401238106Sdes } 402238106Sdes tp = autr_tp_create(anchors, ldns_rr_owner(rr), ldns_rr_get_class(rr)); 403238106Sdes lock_basic_lock(&tp->lock); 404238106Sdes return tp; 405238106Sdes} 406238106Sdes 407238106Sdes/** Add trust anchor from RR */ 408238106Sdesstatic struct autr_ta* 409238106Sdesadd_trustanchor_frm_rr(struct val_anchors* anchors, ldns_rr* rr, 410238106Sdes struct trust_anchor** tp) 411238106Sdes{ 412238106Sdes struct autr_ta* ta = autr_ta_create(rr); 413238106Sdes if(!ta) 414238106Sdes return NULL; 415238106Sdes *tp = find_add_tp(anchors, rr); 416238106Sdes if(!*tp) { 417238106Sdes ldns_rr_free(ta->rr); 418238106Sdes free(ta); 419238106Sdes return NULL; 420238106Sdes } 421238106Sdes /* add ta to tp */ 422238106Sdes ta->next = (*tp)->autr->keys; 423238106Sdes (*tp)->autr->keys = ta; 424238106Sdes lock_basic_unlock(&(*tp)->lock); 425238106Sdes return ta; 426238106Sdes} 427238106Sdes 428238106Sdes/** 429238106Sdes * Add new trust anchor from a string in file. 430238106Sdes * @param anchors: all anchors 431238106Sdes * @param str: string with anchor and comments, if any comments. 432238106Sdes * @param tp: trust point returned. 433238106Sdes * @param origin: what to use for @ 434238106Sdes * @param prev: previous rr name 435238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it. 436238106Sdes * @return new key in trust point. 437238106Sdes */ 438238106Sdesstatic struct autr_ta* 439238106Sdesadd_trustanchor_frm_str(struct val_anchors* anchors, char* str, 440238106Sdes struct trust_anchor** tp, ldns_rdf* origin, ldns_rdf** prev, int* skip) 441238106Sdes{ 442238106Sdes ldns_rr* rr; 443238106Sdes ldns_status lstatus; 444238106Sdes if (!str_contains_data(str, ';')) { 445238106Sdes *skip = 1; 446238106Sdes return NULL; /* empty line */ 447238106Sdes } 448238106Sdes if (LDNS_STATUS_OK != 449238106Sdes (lstatus = ldns_rr_new_frm_str(&rr, str, 0, origin, prev))) 450238106Sdes { 451238106Sdes log_err("ldns error while converting string to RR: %s", 452238106Sdes ldns_get_errorstr_by_id(lstatus)); 453238106Sdes return NULL; 454238106Sdes } 455238106Sdes if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY && 456238106Sdes ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS) { 457238106Sdes ldns_rr_free(rr); 458238106Sdes *skip = 1; 459238106Sdes return NULL; /* only DS and DNSKEY allowed */ 460238106Sdes } 461238106Sdes return add_trustanchor_frm_rr(anchors, rr, tp); 462238106Sdes} 463238106Sdes 464238106Sdes/** 465238106Sdes * Load single anchor 466238106Sdes * @param anchors: all points. 467238106Sdes * @param str: comments line 468238106Sdes * @param fname: filename 469249141Sdes * @param origin: the $ORIGIN. 470238106Sdes * @param prev: passed to ldns. 471238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it. 472238106Sdes * @return false on failure, otherwise the tp read. 473238106Sdes */ 474238106Sdesstatic struct trust_anchor* 475238106Sdesload_trustanchor(struct val_anchors* anchors, char* str, const char* fname, 476238106Sdes ldns_rdf* origin, ldns_rdf** prev, int* skip) 477238106Sdes{ 478238106Sdes struct autr_ta* ta = NULL; 479238106Sdes struct trust_anchor* tp = NULL; 480238106Sdes 481238106Sdes ta = add_trustanchor_frm_str(anchors, str, &tp, origin, prev, skip); 482238106Sdes if(!ta) 483238106Sdes return NULL; 484238106Sdes lock_basic_lock(&tp->lock); 485238106Sdes if(!parse_comments(str, ta)) { 486238106Sdes lock_basic_unlock(&tp->lock); 487238106Sdes return NULL; 488238106Sdes } 489238106Sdes if(!tp->autr->file) { 490238106Sdes tp->autr->file = strdup(fname); 491238106Sdes if(!tp->autr->file) { 492238106Sdes lock_basic_unlock(&tp->lock); 493238106Sdes log_err("malloc failure"); 494238106Sdes return NULL; 495238106Sdes } 496238106Sdes } 497238106Sdes lock_basic_unlock(&tp->lock); 498238106Sdes return tp; 499238106Sdes} 500238106Sdes 501238106Sdes/** 502238106Sdes * Assemble the trust anchors into DS and DNSKEY packed rrsets. 503238106Sdes * Uses only VALID and MISSING DNSKEYs. 504238106Sdes * Read the ldns_rrs and builds packed rrsets 505238106Sdes * @param tp: the trust point. Must be locked. 506238106Sdes * @return false on malloc failure. 507238106Sdes */ 508238106Sdesstatic int 509238106Sdesautr_assemble(struct trust_anchor* tp) 510238106Sdes{ 511238106Sdes ldns_rr_list* ds, *dnskey; 512238106Sdes struct autr_ta* ta; 513238106Sdes struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL; 514238106Sdes 515238106Sdes ds = ldns_rr_list_new(); 516238106Sdes dnskey = ldns_rr_list_new(); 517238106Sdes if(!ds || !dnskey) { 518238106Sdes ldns_rr_list_free(ds); 519238106Sdes ldns_rr_list_free(dnskey); 520238106Sdes return 0; 521238106Sdes } 522238106Sdes for(ta = tp->autr->keys; ta; ta = ta->next) { 523238106Sdes if(ldns_rr_get_type(ta->rr) == LDNS_RR_TYPE_DS) { 524238106Sdes if(!ldns_rr_list_push_rr(ds, ta->rr)) { 525238106Sdes ldns_rr_list_free(ds); 526238106Sdes ldns_rr_list_free(dnskey); 527238106Sdes return 0; 528238106Sdes } 529238106Sdes } else if(ta->s == AUTR_STATE_VALID || 530238106Sdes ta->s == AUTR_STATE_MISSING) { 531238106Sdes if(!ldns_rr_list_push_rr(dnskey, ta->rr)) { 532238106Sdes ldns_rr_list_free(ds); 533238106Sdes ldns_rr_list_free(dnskey); 534238106Sdes return 0; 535238106Sdes } 536238106Sdes } 537238106Sdes } 538238106Sdes 539238106Sdes /* make packed rrset keys - malloced with no ID number, they 540238106Sdes * are not in the cache */ 541238106Sdes /* make packed rrset data (if there is a key) */ 542238106Sdes 543238106Sdes if(ldns_rr_list_rr_count(ds) > 0) { 544238106Sdes ubds = ub_packed_rrset_heap_key(ds); 545238106Sdes if(!ubds) 546238106Sdes goto error_cleanup; 547238106Sdes ubds->entry.data = packed_rrset_heap_data(ds); 548238106Sdes if(!ubds->entry.data) 549238106Sdes goto error_cleanup; 550238106Sdes } 551238106Sdes if(ldns_rr_list_rr_count(dnskey) > 0) { 552238106Sdes ubdnskey = ub_packed_rrset_heap_key(dnskey); 553238106Sdes if(!ubdnskey) 554238106Sdes goto error_cleanup; 555238106Sdes ubdnskey->entry.data = packed_rrset_heap_data(dnskey); 556238106Sdes if(!ubdnskey->entry.data) { 557238106Sdes error_cleanup: 558238106Sdes autr_rrset_delete(ubds); 559238106Sdes autr_rrset_delete(ubdnskey); 560238106Sdes ldns_rr_list_free(ds); 561238106Sdes ldns_rr_list_free(dnskey); 562238106Sdes return 0; 563238106Sdes } 564238106Sdes } 565238106Sdes /* we have prepared the new keys so nothing can go wrong any more. 566238106Sdes * And we are sure we cannot be left without trustanchor after 567238106Sdes * any errors. Put in the new keys and remove old ones. */ 568238106Sdes 569238106Sdes /* free the old data */ 570238106Sdes autr_rrset_delete(tp->ds_rrset); 571238106Sdes autr_rrset_delete(tp->dnskey_rrset); 572238106Sdes 573238106Sdes /* assign the data to replace the old */ 574238106Sdes tp->ds_rrset = ubds; 575238106Sdes tp->dnskey_rrset = ubdnskey; 576238106Sdes tp->numDS = ldns_rr_list_rr_count(ds); 577238106Sdes tp->numDNSKEY = ldns_rr_list_rr_count(dnskey); 578238106Sdes 579238106Sdes ldns_rr_list_free(ds); 580238106Sdes ldns_rr_list_free(dnskey); 581238106Sdes return 1; 582238106Sdes} 583238106Sdes 584238106Sdes/** parse integer */ 585238106Sdesstatic unsigned int 586238106Sdesparse_int(char* line, int* ret) 587238106Sdes{ 588238106Sdes char *e; 589238106Sdes unsigned int x = (unsigned int)strtol(line, &e, 10); 590238106Sdes if(line == e) { 591238106Sdes *ret = -1; /* parse error */ 592238106Sdes return 0; 593238106Sdes } 594238106Sdes *ret = 1; /* matched */ 595238106Sdes return x; 596238106Sdes} 597238106Sdes 598238106Sdes/** parse id sequence for anchor */ 599238106Sdesstatic struct trust_anchor* 600238106Sdesparse_id(struct val_anchors* anchors, char* line) 601238106Sdes{ 602238106Sdes struct trust_anchor *tp; 603238106Sdes int r; 604238106Sdes ldns_rdf* rdf; 605238106Sdes uint16_t dclass; 606238106Sdes /* read the owner name */ 607238106Sdes char* next = strchr(line, ' '); 608238106Sdes if(!next) 609238106Sdes return NULL; 610238106Sdes next[0] = 0; 611238106Sdes rdf = ldns_dname_new_frm_str(line); 612238106Sdes if(!rdf) 613238106Sdes return NULL; 614238106Sdes 615238106Sdes /* read the class */ 616238106Sdes dclass = parse_int(next+1, &r); 617238106Sdes if(r == -1) { 618238106Sdes ldns_rdf_deep_free(rdf); 619238106Sdes return NULL; 620238106Sdes } 621238106Sdes 622238106Sdes /* find the trust point */ 623238106Sdes tp = autr_tp_create(anchors, rdf, dclass); 624238106Sdes ldns_rdf_deep_free(rdf); 625238106Sdes return tp; 626238106Sdes} 627238106Sdes 628238106Sdes/** 629238106Sdes * Parse variable from trustanchor header 630238106Sdes * @param line: to parse 631238106Sdes * @param anchors: the anchor is added to this, if "id:" is seen. 632238106Sdes * @param anchor: the anchor as result value or previously returned anchor 633238106Sdes * value to read the variable lines into. 634238106Sdes * @return: 0 no match, -1 failed syntax error, +1 success line read. 635238106Sdes * +2 revoked trust anchor file. 636238106Sdes */ 637238106Sdesstatic int 638238106Sdesparse_var_line(char* line, struct val_anchors* anchors, 639238106Sdes struct trust_anchor** anchor) 640238106Sdes{ 641238106Sdes struct trust_anchor* tp = *anchor; 642238106Sdes int r = 0; 643238106Sdes if(strncmp(line, ";;id: ", 6) == 0) { 644238106Sdes *anchor = parse_id(anchors, line+6); 645238106Sdes if(!*anchor) return -1; 646238106Sdes else return 1; 647238106Sdes } else if(strncmp(line, ";;REVOKED", 9) == 0) { 648238106Sdes if(tp) { 649238106Sdes log_err("REVOKED statement must be at start of file"); 650238106Sdes return -1; 651238106Sdes } 652238106Sdes return 2; 653238106Sdes } else if(strncmp(line, ";;last_queried: ", 16) == 0) { 654238106Sdes if(!tp) return -1; 655238106Sdes lock_basic_lock(&tp->lock); 656238106Sdes tp->autr->last_queried = (time_t)parse_int(line+16, &r); 657238106Sdes lock_basic_unlock(&tp->lock); 658238106Sdes } else if(strncmp(line, ";;last_success: ", 16) == 0) { 659238106Sdes if(!tp) return -1; 660238106Sdes lock_basic_lock(&tp->lock); 661238106Sdes tp->autr->last_success = (time_t)parse_int(line+16, &r); 662238106Sdes lock_basic_unlock(&tp->lock); 663238106Sdes } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) { 664238106Sdes if(!tp) return -1; 665238106Sdes lock_basic_lock(&anchors->lock); 666238106Sdes lock_basic_lock(&tp->lock); 667238106Sdes (void)rbtree_delete(&anchors->autr->probe, tp); 668238106Sdes tp->autr->next_probe_time = (time_t)parse_int(line+19, &r); 669238106Sdes (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode); 670238106Sdes lock_basic_unlock(&tp->lock); 671238106Sdes lock_basic_unlock(&anchors->lock); 672238106Sdes } else if(strncmp(line, ";;query_failed: ", 16) == 0) { 673238106Sdes if(!tp) return -1; 674238106Sdes lock_basic_lock(&tp->lock); 675238106Sdes tp->autr->query_failed = (uint8_t)parse_int(line+16, &r); 676238106Sdes lock_basic_unlock(&tp->lock); 677238106Sdes } else if(strncmp(line, ";;query_interval: ", 18) == 0) { 678238106Sdes if(!tp) return -1; 679238106Sdes lock_basic_lock(&tp->lock); 680238106Sdes tp->autr->query_interval = (uint32_t)parse_int(line+18, &r); 681238106Sdes lock_basic_unlock(&tp->lock); 682238106Sdes } else if(strncmp(line, ";;retry_time: ", 14) == 0) { 683238106Sdes if(!tp) return -1; 684238106Sdes lock_basic_lock(&tp->lock); 685238106Sdes tp->autr->retry_time = (uint32_t)parse_int(line+14, &r); 686238106Sdes lock_basic_unlock(&tp->lock); 687238106Sdes } 688238106Sdes return r; 689238106Sdes} 690238106Sdes 691238106Sdes/** handle origin lines */ 692238106Sdesstatic int 693238106Sdeshandle_origin(char* line, ldns_rdf** origin) 694238106Sdes{ 695238106Sdes while(isspace((int)*line)) 696238106Sdes line++; 697238106Sdes if(strncmp(line, "$ORIGIN", 7) != 0) 698238106Sdes return 0; 699238106Sdes ldns_rdf_deep_free(*origin); 700238106Sdes line += 7; 701238106Sdes while(isspace((int)*line)) 702238106Sdes line++; 703238106Sdes *origin = ldns_dname_new_frm_str(line); 704238106Sdes if(!*origin) 705238106Sdes log_warn("malloc failure or parse error in $ORIGIN"); 706238106Sdes return 1; 707238106Sdes} 708238106Sdes 709238106Sdes/** Read one line and put multiline RRs onto one line string */ 710238106Sdesstatic int 711238106Sdesread_multiline(char* buf, size_t len, FILE* in, int* linenr) 712238106Sdes{ 713238106Sdes char* pos = buf; 714238106Sdes size_t left = len; 715238106Sdes int depth = 0; 716238106Sdes buf[len-1] = 0; 717238106Sdes while(left > 0 && fgets(pos, (int)left, in) != NULL) { 718238106Sdes size_t i, poslen = strlen(pos); 719238106Sdes (*linenr)++; 720238106Sdes 721238106Sdes /* check what the new depth is after the line */ 722238106Sdes /* this routine cannot handle braces inside quotes, 723238106Sdes say for TXT records, but this routine only has to read keys */ 724238106Sdes for(i=0; i<poslen; i++) { 725238106Sdes if(pos[i] == '(') { 726238106Sdes depth++; 727238106Sdes } else if(pos[i] == ')') { 728238106Sdes if(depth == 0) { 729238106Sdes log_err("mismatch: too many ')'"); 730238106Sdes return -1; 731238106Sdes } 732238106Sdes depth--; 733238106Sdes } else if(pos[i] == ';') { 734238106Sdes break; 735238106Sdes } 736238106Sdes } 737238106Sdes 738238106Sdes /* normal oneline or last line: keeps newline and comments */ 739238106Sdes if(depth == 0) { 740238106Sdes return 1; 741238106Sdes } 742238106Sdes 743238106Sdes /* more lines expected, snip off comments and newline */ 744238106Sdes if(poslen>0) 745238106Sdes pos[poslen-1] = 0; /* strip newline */ 746238106Sdes if(strchr(pos, ';')) 747238106Sdes strchr(pos, ';')[0] = 0; /* strip comments */ 748238106Sdes 749238106Sdes /* move to paste other lines behind this one */ 750238106Sdes poslen = strlen(pos); 751238106Sdes pos += poslen; 752238106Sdes left -= poslen; 753238106Sdes /* the newline is changed into a space */ 754238106Sdes if(left <= 2 /* space and eos */) { 755238106Sdes log_err("line too long"); 756238106Sdes return -1; 757238106Sdes } 758238106Sdes pos[0] = ' '; 759238106Sdes pos[1] = 0; 760238106Sdes pos += 1; 761238106Sdes left -= 1; 762238106Sdes } 763238106Sdes if(depth != 0) { 764238106Sdes log_err("mismatch: too many '('"); 765238106Sdes return -1; 766238106Sdes } 767238106Sdes if(pos != buf) 768238106Sdes return 1; 769238106Sdes return 0; 770238106Sdes} 771238106Sdes 772238106Sdesint autr_read_file(struct val_anchors* anchors, const char* nm) 773238106Sdes{ 774238106Sdes /* the file descriptor */ 775238106Sdes FILE* fd; 776238106Sdes /* keep track of line numbers */ 777238106Sdes int line_nr = 0; 778238106Sdes /* single line */ 779238106Sdes char line[10240]; 780238106Sdes /* trust point being read */ 781238106Sdes struct trust_anchor *tp = NULL, *tp2; 782238106Sdes int r; 783238106Sdes /* for $ORIGIN parsing */ 784238106Sdes ldns_rdf *origin=NULL, *prev=NULL; 785238106Sdes 786238106Sdes if (!(fd = fopen(nm, "r"))) { 787238106Sdes log_err("unable to open %s for reading: %s", 788238106Sdes nm, strerror(errno)); 789238106Sdes return 0; 790238106Sdes } 791238106Sdes verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); 792238106Sdes while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { 793238106Sdes if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { 794238106Sdes log_err("could not parse auto-trust-anchor-file " 795238106Sdes "%s line %d", nm, line_nr); 796238106Sdes fclose(fd); 797238106Sdes ldns_rdf_deep_free(origin); 798238106Sdes ldns_rdf_deep_free(prev); 799238106Sdes return 0; 800238106Sdes } else if(r == 1) { 801238106Sdes continue; 802238106Sdes } else if(r == 2) { 803238106Sdes log_warn("trust anchor %s has been revoked", nm); 804238106Sdes fclose(fd); 805238106Sdes ldns_rdf_deep_free(origin); 806238106Sdes ldns_rdf_deep_free(prev); 807238106Sdes return 1; 808238106Sdes } 809238106Sdes if (!str_contains_data(line, ';')) 810238106Sdes continue; /* empty lines allowed */ 811238106Sdes if(handle_origin(line, &origin)) 812238106Sdes continue; 813238106Sdes r = 0; 814238106Sdes if(!(tp2=load_trustanchor(anchors, line, nm, origin, &prev, 815238106Sdes &r))) { 816238106Sdes if(!r) log_err("failed to load trust anchor from %s " 817238106Sdes "at line %i, skipping", nm, line_nr); 818238106Sdes /* try to do the rest */ 819238106Sdes continue; 820238106Sdes } 821238106Sdes if(tp && tp != tp2) { 822238106Sdes log_err("file %s has mismatching data inside: " 823238106Sdes "the file may only contain keys for one name, " 824238106Sdes "remove keys for other domain names", nm); 825238106Sdes fclose(fd); 826238106Sdes ldns_rdf_deep_free(origin); 827238106Sdes ldns_rdf_deep_free(prev); 828238106Sdes return 0; 829238106Sdes } 830238106Sdes tp = tp2; 831238106Sdes } 832238106Sdes fclose(fd); 833238106Sdes ldns_rdf_deep_free(origin); 834238106Sdes ldns_rdf_deep_free(prev); 835238106Sdes if(!tp) { 836238106Sdes log_err("failed to read %s", nm); 837238106Sdes return 0; 838238106Sdes } 839238106Sdes 840238106Sdes /* now assemble the data into DNSKEY and DS packed rrsets */ 841238106Sdes lock_basic_lock(&tp->lock); 842238106Sdes if(!autr_assemble(tp)) { 843238106Sdes lock_basic_unlock(&tp->lock); 844238106Sdes log_err("malloc failure assembling %s", nm); 845238106Sdes return 0; 846238106Sdes } 847238106Sdes lock_basic_unlock(&tp->lock); 848238106Sdes return 1; 849238106Sdes} 850238106Sdes 851238106Sdes/** string for a trustanchor state */ 852238106Sdesstatic const char* 853238106Sdestrustanchor_state2str(autr_state_t s) 854238106Sdes{ 855238106Sdes switch (s) { 856238106Sdes case AUTR_STATE_START: return " START "; 857238106Sdes case AUTR_STATE_ADDPEND: return " ADDPEND "; 858238106Sdes case AUTR_STATE_VALID: return " VALID "; 859238106Sdes case AUTR_STATE_MISSING: return " MISSING "; 860238106Sdes case AUTR_STATE_REVOKED: return " REVOKED "; 861238106Sdes case AUTR_STATE_REMOVED: return " REMOVED "; 862238106Sdes } 863238106Sdes return " UNKNOWN "; 864238106Sdes} 865238106Sdes 866238106Sdes/** print ID to file */ 867238106Sdesstatic int 868238106Sdesprint_id(FILE* out, char* fname, struct module_env* env, 869238106Sdes uint8_t* nm, size_t nmlen, uint16_t dclass) 870238106Sdes{ 871238106Sdes ldns_rdf rdf; 872238106Sdes#ifdef UNBOUND_DEBUG 873238106Sdes ldns_status s; 874238106Sdes#endif 875238106Sdes 876238106Sdes memset(&rdf, 0, sizeof(rdf)); 877238106Sdes ldns_rdf_set_data(&rdf, nm); 878238106Sdes ldns_rdf_set_size(&rdf, nmlen); 879238106Sdes ldns_rdf_set_type(&rdf, LDNS_RDF_TYPE_DNAME); 880238106Sdes 881238106Sdes ldns_buffer_clear(env->scratch_buffer); 882238106Sdes#ifdef UNBOUND_DEBUG 883238106Sdes s = 884238106Sdes#endif 885238106Sdes ldns_rdf2buffer_str_dname(env->scratch_buffer, &rdf); 886238106Sdes log_assert(s == LDNS_STATUS_OK); 887238106Sdes ldns_buffer_write_u8(env->scratch_buffer, 0); 888238106Sdes ldns_buffer_flip(env->scratch_buffer); 889238106Sdes if(fprintf(out, ";;id: %s %d\n", 890238106Sdes (char*)ldns_buffer_begin(env->scratch_buffer), 891238106Sdes (int)dclass) < 0) { 892238106Sdes log_err("could not write to %s: %s", fname, strerror(errno)); 893238106Sdes return 0; 894238106Sdes } 895238106Sdes return 1; 896238106Sdes} 897238106Sdes 898238106Sdesstatic int 899238106Sdesautr_write_contents(FILE* out, char* fn, struct module_env* env, 900238106Sdes struct trust_anchor* tp) 901238106Sdes{ 902238106Sdes char tmi[32]; 903238106Sdes struct autr_ta* ta; 904238106Sdes char* str; 905238106Sdes 906238106Sdes /* write pretty header */ 907238106Sdes if(fprintf(out, "; autotrust trust anchor file\n") < 0) { 908238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 909238106Sdes return 0; 910238106Sdes } 911238106Sdes if(tp->autr->revoked) { 912238106Sdes if(fprintf(out, ";;REVOKED\n") < 0 || 913238106Sdes fprintf(out, "; The zone has all keys revoked, and is\n" 914238106Sdes "; considered as if it has no trust anchors.\n" 915238106Sdes "; the remainder of the file is the last probe.\n" 916238106Sdes "; to restart the trust anchor, overwrite this file.\n" 917238106Sdes "; with one containing valid DNSKEYs or DSes.\n") < 0) { 918238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 919238106Sdes return 0; 920238106Sdes } 921238106Sdes } 922238106Sdes if(!print_id(out, fn, env, tp->name, tp->namelen, tp->dclass)) { 923238106Sdes return 0; 924238106Sdes } 925238106Sdes if(fprintf(out, ";;last_queried: %u ;;%s", 926238106Sdes (unsigned int)tp->autr->last_queried, 927238106Sdes ctime_r(&(tp->autr->last_queried), tmi)) < 0 || 928238106Sdes fprintf(out, ";;last_success: %u ;;%s", 929238106Sdes (unsigned int)tp->autr->last_success, 930238106Sdes ctime_r(&(tp->autr->last_success), tmi)) < 0 || 931238106Sdes fprintf(out, ";;next_probe_time: %u ;;%s", 932238106Sdes (unsigned int)tp->autr->next_probe_time, 933238106Sdes ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || 934238106Sdes fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0 935238106Sdes || fprintf(out, ";;query_interval: %d\n", 936238106Sdes (int)tp->autr->query_interval) < 0 || 937238106Sdes fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) { 938238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 939238106Sdes return 0; 940238106Sdes } 941238106Sdes 942238106Sdes /* write anchors */ 943238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 944238106Sdes /* by default do not store START and REMOVED keys */ 945238106Sdes if(ta->s == AUTR_STATE_START) 946238106Sdes continue; 947238106Sdes if(ta->s == AUTR_STATE_REMOVED) 948238106Sdes continue; 949238106Sdes /* only store keys */ 950238106Sdes if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY) 951238106Sdes continue; 952238106Sdes str = ldns_rr2str(ta->rr); 953238106Sdes if(!str || !str[0]) { 954238106Sdes free(str); 955238106Sdes log_err("malloc failure writing %s", fn); 956238106Sdes return 0; 957238106Sdes } 958238106Sdes str[strlen(str)-1] = 0; /* remove newline */ 959238106Sdes if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d " 960238106Sdes ";;lastchange=%u ;;%s", str, (int)ta->s, 961238106Sdes trustanchor_state2str(ta->s), (int)ta->pending_count, 962238106Sdes (unsigned int)ta->last_change, 963238106Sdes ctime_r(&(ta->last_change), tmi)) < 0) { 964238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 965238106Sdes free(str); 966238106Sdes return 0; 967238106Sdes } 968238106Sdes free(str); 969238106Sdes } 970238106Sdes return 1; 971238106Sdes} 972238106Sdes 973238106Sdesvoid autr_write_file(struct module_env* env, struct trust_anchor* tp) 974238106Sdes{ 975238106Sdes FILE* out; 976238106Sdes char* fname = tp->autr->file; 977238106Sdes char tempf[2048]; 978238106Sdes log_assert(tp->autr); 979238106Sdes /* unique name with pid number and thread number */ 980238106Sdes snprintf(tempf, sizeof(tempf), "%s.%d-%d", fname, (int)getpid(), 981238106Sdes env&&env->worker?*(int*)env->worker:0); 982238106Sdes verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf); 983238106Sdes out = fopen(tempf, "w"); 984238106Sdes if(!out) { 985238106Sdes log_err("could not open autotrust file for writing, %s: %s", 986238106Sdes tempf, strerror(errno)); 987238106Sdes return; 988238106Sdes } 989238106Sdes if(!autr_write_contents(out, tempf, env, tp)) { 990238106Sdes /* failed to write contents (completely) */ 991238106Sdes fclose(out); 992238106Sdes unlink(tempf); 993238106Sdes log_err("could not completely write: %s", fname); 994238106Sdes return; 995238106Sdes } 996238106Sdes /* success; overwrite actual file */ 997238106Sdes fclose(out); 998238106Sdes verbose(VERB_ALGO, "autotrust: replaced %s", fname); 999238106Sdes#ifdef UB_ON_WINDOWS 1000238106Sdes (void)unlink(fname); /* windows does not replace file with rename() */ 1001238106Sdes#endif 1002238106Sdes if(rename(tempf, fname) < 0) { 1003238106Sdes log_err("rename(%s to %s): %s", tempf, fname, strerror(errno)); 1004238106Sdes } 1005238106Sdes} 1006238106Sdes 1007238106Sdes/** 1008238106Sdes * Verify if dnskey works for trust point 1009238106Sdes * @param env: environment (with time) for verification 1010238106Sdes * @param ve: validator environment (with options) for verification. 1011238106Sdes * @param tp: trust point to verify with 1012238106Sdes * @param rrset: DNSKEY rrset to verify. 1013238106Sdes * @return false on failure, true if verification successful. 1014238106Sdes */ 1015238106Sdesstatic int 1016238106Sdesverify_dnskey(struct module_env* env, struct val_env* ve, 1017238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* rrset) 1018238106Sdes{ 1019238106Sdes char* reason = NULL; 1020238106Sdes uint8_t sigalg[ALGO_NEEDS_MAX+1]; 1021238106Sdes int downprot = 1; 1022238106Sdes enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, 1023238106Sdes tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason); 1024238106Sdes /* sigalg is ignored, it returns algorithms signalled to exist, but 1025238106Sdes * in 5011 there are no other rrsets to check. if downprot is 1026238106Sdes * enabled, then it checks that the DNSKEY is signed with all 1027238106Sdes * algorithms available in the trust store. */ 1028238106Sdes verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s", 1029238106Sdes sec_status_to_string(sec)); 1030238106Sdes return sec == sec_status_secure; 1031238106Sdes} 1032238106Sdes 1033238106Sdes/** Find minimum expiration interval from signatures */ 1034238106Sdesstatic uint32_t 1035238106Sdesmin_expiry(struct module_env* env, ldns_rr_list* rrset) 1036238106Sdes{ 1037238106Sdes size_t i; 1038238106Sdes uint32_t t, r = 15 * 24 * 3600; /* 15 days max */ 1039238106Sdes for(i=0; i<ldns_rr_list_rr_count(rrset); i++) { 1040238106Sdes ldns_rr* rr = ldns_rr_list_rr(rrset, i); 1041238106Sdes if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) 1042238106Sdes continue; 1043238106Sdes t = ldns_rdf2native_int32(ldns_rr_rrsig_expiration(rr)); 1044238106Sdes if(t - *env->now > 0) { 1045238106Sdes t -= *env->now; 1046238106Sdes if(t < r) 1047238106Sdes r = t; 1048238106Sdes } 1049238106Sdes } 1050238106Sdes return r; 1051238106Sdes} 1052238106Sdes 1053238106Sdes/** Is rr self-signed revoked key */ 1054238106Sdesstatic int 1055238106Sdesrr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, 1056238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t i) 1057238106Sdes{ 1058238106Sdes enum sec_status sec; 1059238106Sdes char* reason = NULL; 1060238106Sdes verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", 1061238106Sdes (int)i); 1062238106Sdes /* no algorithm downgrade protection necessary, if it is selfsigned 1063238106Sdes * revoked it can be removed. */ 1064238106Sdes sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, 1065238106Sdes &reason); 1066238106Sdes return (sec == sec_status_secure); 1067238106Sdes} 1068238106Sdes 1069238106Sdes/** Set fetched value */ 1070238106Sdesstatic void 1071238106Sdesseen_trustanchor(struct autr_ta* ta, uint8_t seen) 1072238106Sdes{ 1073238106Sdes ta->fetched = seen; 1074238106Sdes if(ta->pending_count < 250) /* no numerical overflow, please */ 1075238106Sdes ta->pending_count++; 1076238106Sdes} 1077238106Sdes 1078238106Sdes/** set revoked value */ 1079238106Sdesstatic void 1080238106Sdesseen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked) 1081238106Sdes{ 1082238106Sdes ta->revoked = revoked; 1083238106Sdes} 1084238106Sdes 1085238106Sdes/** revoke a trust anchor */ 1086238106Sdesstatic void 1087238106Sdesrevoke_dnskey(struct autr_ta* ta, int off) 1088238106Sdes{ 1089238106Sdes ldns_rdf* rdf; 1090238106Sdes uint16_t flags; 1091238106Sdes log_assert(ta && ta->rr); 1092238106Sdes if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY) 1093238106Sdes return; 1094238106Sdes rdf = ldns_rr_dnskey_flags(ta->rr); 1095238106Sdes flags = ldns_read_uint16(ldns_rdf_data(rdf)); 1096238106Sdes 1097238106Sdes if (off && (flags&LDNS_KEY_REVOKE_KEY)) 1098238106Sdes flags ^= LDNS_KEY_REVOKE_KEY; /* flip */ 1099238106Sdes else 1100238106Sdes flags |= LDNS_KEY_REVOKE_KEY; 1101238106Sdes ldns_write_uint16(ldns_rdf_data(rdf), flags); 1102238106Sdes} 1103238106Sdes 1104238106Sdes/** Compare two RR buffers skipping the REVOKED bit */ 1105238106Sdesstatic int 1106238106Sdesldns_rr_compare_wire_skip_revbit(ldns_buffer* rr1_buf, ldns_buffer* rr2_buf) 1107238106Sdes{ 1108238106Sdes size_t rr1_len, rr2_len, min_len, i, offset; 1109238106Sdes rr1_len = ldns_buffer_capacity(rr1_buf); 1110238106Sdes rr2_len = ldns_buffer_capacity(rr2_buf); 1111238106Sdes /* jump past dname (checked in earlier part) and especially past TTL */ 1112238106Sdes offset = 0; 1113238106Sdes while (offset < rr1_len && *ldns_buffer_at(rr1_buf, offset) != 0) 1114238106Sdes offset += *ldns_buffer_at(rr1_buf, offset) + 1; 1115238106Sdes /* jump to rdata section (PAST the rdata length field) */ 1116238106Sdes offset += 11; /* 0-dname-end + type + class + ttl + rdatalen */ 1117238106Sdes min_len = (rr1_len < rr2_len) ? rr1_len : rr2_len; 1118238106Sdes /* compare RRs RDATA byte for byte. */ 1119238106Sdes for(i = offset; i < min_len; i++) 1120238106Sdes { 1121238106Sdes uint8_t *rdf1, *rdf2; 1122238106Sdes rdf1 = ldns_buffer_at(rr1_buf, i); 1123238106Sdes rdf2 = ldns_buffer_at(rr2_buf, i); 1124238106Sdes if (i==(offset+1)) 1125238106Sdes { 1126238106Sdes /* this is the second part of the flags field */ 1127238106Sdes *rdf1 = *rdf1 | LDNS_KEY_REVOKE_KEY; 1128238106Sdes *rdf2 = *rdf2 | LDNS_KEY_REVOKE_KEY; 1129238106Sdes } 1130238106Sdes if (*rdf1 < *rdf2) return -1; 1131238106Sdes else if (*rdf1 > *rdf2) return 1; 1132238106Sdes } 1133238106Sdes return 0; 1134238106Sdes} 1135238106Sdes 1136238106Sdes/** Compare two RRs skipping the REVOKED bit */ 1137238106Sdesstatic int 1138238106Sdesldns_rr_compare_skip_revbit(const ldns_rr* rr1, const ldns_rr* rr2, int* result) 1139238106Sdes{ 1140238106Sdes size_t rr1_len, rr2_len; 1141238106Sdes ldns_buffer* rr1_buf; 1142238106Sdes ldns_buffer* rr2_buf; 1143238106Sdes 1144238106Sdes *result = ldns_rr_compare_no_rdata(rr1, rr2); 1145238106Sdes if (*result == 0) 1146238106Sdes { 1147238106Sdes rr1_len = ldns_rr_uncompressed_size(rr1); 1148238106Sdes rr2_len = ldns_rr_uncompressed_size(rr2); 1149238106Sdes rr1_buf = ldns_buffer_new(rr1_len); 1150238106Sdes rr2_buf = ldns_buffer_new(rr2_len); 1151238106Sdes if(!rr1_buf || !rr2_buf) { 1152238106Sdes ldns_buffer_free(rr1_buf); 1153238106Sdes ldns_buffer_free(rr2_buf); 1154238106Sdes return 0; 1155238106Sdes } 1156238106Sdes if (ldns_rr2buffer_wire_canonical(rr1_buf, rr1, 1157238106Sdes LDNS_SECTION_ANY) != LDNS_STATUS_OK) 1158238106Sdes { 1159238106Sdes ldns_buffer_free(rr1_buf); 1160238106Sdes ldns_buffer_free(rr2_buf); 1161238106Sdes return 0; 1162238106Sdes } 1163238106Sdes if (ldns_rr2buffer_wire_canonical(rr2_buf, rr2, 1164238106Sdes LDNS_SECTION_ANY) != LDNS_STATUS_OK) { 1165238106Sdes ldns_buffer_free(rr1_buf); 1166238106Sdes ldns_buffer_free(rr2_buf); 1167238106Sdes return 0; 1168238106Sdes } 1169238106Sdes *result = ldns_rr_compare_wire_skip_revbit(rr1_buf, rr2_buf); 1170238106Sdes ldns_buffer_free(rr1_buf); 1171238106Sdes ldns_buffer_free(rr2_buf); 1172238106Sdes } 1173238106Sdes return 1; 1174238106Sdes} 1175238106Sdes 1176238106Sdes 1177238106Sdes/** compare two trust anchors */ 1178238106Sdesstatic int 1179238106Sdesta_compare(ldns_rr* a, ldns_rr* b, int* result) 1180238106Sdes{ 1181238106Sdes if (!a && !b) *result = 0; 1182238106Sdes else if (!a) *result = -1; 1183238106Sdes else if (!b) *result = 1; 1184238106Sdes else if (ldns_rr_get_type(a) != ldns_rr_get_type(b)) 1185238106Sdes *result = (int)ldns_rr_get_type(a) - (int)ldns_rr_get_type(b); 1186238106Sdes else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DNSKEY) { 1187238106Sdes if(!ldns_rr_compare_skip_revbit(a, b, result)) 1188238106Sdes return 0; 1189238106Sdes } 1190238106Sdes else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DS) 1191238106Sdes *result = ldns_rr_compare(a, b); 1192238106Sdes else *result = -1; 1193238106Sdes return 1; 1194238106Sdes} 1195238106Sdes 1196238106Sdes/** 1197238106Sdes * Find key 1198238106Sdes * @param tp: to search in 1199238106Sdes * @param rr: to look for 1200238106Sdes * @param result: returns NULL or the ta key looked for. 1201238106Sdes * @return false on malloc failure during search. if true examine result. 1202238106Sdes */ 1203238106Sdesstatic int 1204238106Sdesfind_key(struct trust_anchor* tp, ldns_rr* rr, struct autr_ta** result) 1205238106Sdes{ 1206238106Sdes struct autr_ta* ta; 1207238106Sdes int ret; 1208238106Sdes if(!tp || !rr) 1209238106Sdes return 0; 1210238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 1211238106Sdes if(!ta_compare(ta->rr, rr, &ret)) 1212238106Sdes return 0; 1213238106Sdes if(ret == 0) { 1214238106Sdes *result = ta; 1215238106Sdes return 1; 1216238106Sdes } 1217238106Sdes } 1218238106Sdes *result = NULL; 1219238106Sdes return 1; 1220238106Sdes} 1221238106Sdes 1222238106Sdes/** add key and clone RR and tp already locked */ 1223238106Sdesstatic struct autr_ta* 1224238106Sdesadd_key(struct trust_anchor* tp, ldns_rr* rr) 1225238106Sdes{ 1226238106Sdes ldns_rr* c; 1227238106Sdes struct autr_ta* ta; 1228238106Sdes c = ldns_rr_clone(rr); 1229238106Sdes if(!c) return NULL; 1230238106Sdes ta = autr_ta_create(c); 1231238106Sdes if(!ta) { 1232238106Sdes ldns_rr_free(c); 1233238106Sdes return NULL; 1234238106Sdes } 1235238106Sdes /* link in, tp already locked */ 1236238106Sdes ta->next = tp->autr->keys; 1237238106Sdes tp->autr->keys = ta; 1238238106Sdes return ta; 1239238106Sdes} 1240238106Sdes 1241238106Sdes/** get TTL from DNSKEY rrset */ 1242238106Sdesstatic uint32_t 1243238106Sdeskey_ttl(struct ub_packed_rrset_key* k) 1244238106Sdes{ 1245238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1246238106Sdes return d->ttl; 1247238106Sdes} 1248238106Sdes 1249238106Sdes/** update the time values for the trustpoint */ 1250238106Sdesstatic void 1251238106Sdesset_tp_times(struct trust_anchor* tp, uint32_t rrsig_exp_interval, 1252238106Sdes uint32_t origttl, int* changed) 1253238106Sdes{ 1254238106Sdes uint32_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; 1255238106Sdes 1256238106Sdes /* x = MIN(15days, ttl/2, expire/2) */ 1257238106Sdes x = 15 * 24 * 3600; 1258238106Sdes if(origttl/2 < x) 1259238106Sdes x = origttl/2; 1260238106Sdes if(rrsig_exp_interval/2 < x) 1261238106Sdes x = rrsig_exp_interval/2; 1262238106Sdes /* MAX(1hr, x) */ 1263238106Sdes if(x < 3600) 1264238106Sdes tp->autr->query_interval = 3600; 1265238106Sdes else tp->autr->query_interval = x; 1266238106Sdes 1267238106Sdes /* x= MIN(1day, ttl/10, expire/10) */ 1268238106Sdes x = 24 * 3600; 1269238106Sdes if(origttl/10 < x) 1270238106Sdes x = origttl/10; 1271238106Sdes if(rrsig_exp_interval/10 < x) 1272238106Sdes x = rrsig_exp_interval/10; 1273238106Sdes /* MAX(1hr, x) */ 1274238106Sdes if(x < 3600) 1275238106Sdes tp->autr->retry_time = 3600; 1276238106Sdes else tp->autr->retry_time = x; 1277238106Sdes 1278238106Sdes if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { 1279238106Sdes *changed = 1; 1280238106Sdes verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl); 1281238106Sdes verbose(VERB_ALGO, "rrsig_exp_interval is %d", 1282238106Sdes (int)rrsig_exp_interval); 1283238106Sdes verbose(VERB_ALGO, "query_interval: %d, retry_time: %d", 1284238106Sdes (int)tp->autr->query_interval, 1285238106Sdes (int)tp->autr->retry_time); 1286238106Sdes } 1287238106Sdes} 1288238106Sdes 1289238106Sdes/** init events to zero */ 1290238106Sdesstatic void 1291238106Sdesinit_events(struct trust_anchor* tp) 1292238106Sdes{ 1293238106Sdes struct autr_ta* ta; 1294238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 1295238106Sdes ta->fetched = 0; 1296238106Sdes } 1297238106Sdes} 1298238106Sdes 1299238106Sdes/** check for revoked keys without trusting any other information */ 1300238106Sdesstatic void 1301238106Sdescheck_contains_revoked(struct module_env* env, struct val_env* ve, 1302238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1303238106Sdes int* changed) 1304238106Sdes{ 1305238106Sdes ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset, 1306238106Sdes env->scratch_buffer); 1307238106Sdes size_t i; 1308238106Sdes if(!r) { 1309238106Sdes log_err("malloc failure"); 1310238106Sdes return; 1311238106Sdes } 1312238106Sdes for(i=0; i<ldns_rr_list_rr_count(r); i++) { 1313238106Sdes ldns_rr* rr = ldns_rr_list_rr(r, i); 1314238106Sdes struct autr_ta* ta = NULL; 1315238106Sdes if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) 1316238106Sdes continue; 1317238106Sdes if(!rr_is_dnskey_sep(rr) || !rr_is_dnskey_revoked(rr)) 1318238106Sdes continue; /* not a revoked KSK */ 1319238106Sdes if(!find_key(tp, rr, &ta)) { 1320238106Sdes log_err("malloc failure"); 1321238106Sdes continue; /* malloc fail in compare*/ 1322238106Sdes } 1323238106Sdes if(!ta) 1324238106Sdes continue; /* key not found */ 1325238106Sdes if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) { 1326238106Sdes /* checked if there is an rrsig signed by this key. */ 1327238106Sdes log_assert(dnskey_calc_keytag(dnskey_rrset, i) == 1328238106Sdes ldns_calc_keytag(rr)); /* checks conversion*/ 1329238106Sdes verbose_key(ta, VERB_ALGO, "is self-signed revoked"); 1330238106Sdes if(!ta->revoked) 1331238106Sdes *changed = 1; 1332238106Sdes seen_revoked_trustanchor(ta, 1); 1333238106Sdes do_revoked(env, ta, changed); 1334238106Sdes } 1335238106Sdes } 1336238106Sdes ldns_rr_list_deep_free(r); 1337238106Sdes} 1338238106Sdes 1339238106Sdes/** See if a DNSKEY is verified by one of the DSes */ 1340238106Sdesstatic int 1341238106Sdeskey_matches_a_ds(struct module_env* env, struct val_env* ve, 1342238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx, 1343238106Sdes struct ub_packed_rrset_key* ds_rrset) 1344238106Sdes{ 1345238106Sdes struct packed_rrset_data* dd = (struct packed_rrset_data*) 1346238106Sdes ds_rrset->entry.data; 1347238106Sdes size_t ds_idx, num = dd->count; 1348238106Sdes int d = val_favorite_ds_algo(ds_rrset); 1349238106Sdes char* reason = ""; 1350238106Sdes for(ds_idx=0; ds_idx<num; ds_idx++) { 1351238106Sdes if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) || 1352238106Sdes !ds_key_algo_is_supported(ds_rrset, ds_idx) || 1353238106Sdes ds_get_digest_algo(ds_rrset, ds_idx) != d) 1354238106Sdes continue; 1355238106Sdes if(ds_get_key_algo(ds_rrset, ds_idx) 1356238106Sdes != dnskey_get_algo(dnskey_rrset, key_idx) 1357238106Sdes || dnskey_calc_keytag(dnskey_rrset, key_idx) 1358238106Sdes != ds_get_keytag(ds_rrset, ds_idx)) { 1359238106Sdes continue; 1360238106Sdes } 1361238106Sdes if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx, 1362238106Sdes ds_rrset, ds_idx)) { 1363238106Sdes verbose(VERB_ALGO, "DS match attempt failed"); 1364238106Sdes continue; 1365238106Sdes } 1366238106Sdes if(dnskey_verify_rrset(env, ve, dnskey_rrset, 1367238106Sdes dnskey_rrset, key_idx, &reason) == sec_status_secure) { 1368238106Sdes return 1; 1369238106Sdes } else { 1370238106Sdes verbose(VERB_ALGO, "DS match failed because the key " 1371238106Sdes "does not verify the keyset: %s", reason); 1372238106Sdes } 1373238106Sdes } 1374238106Sdes return 0; 1375238106Sdes} 1376238106Sdes 1377238106Sdes/** Set update events */ 1378238106Sdesstatic int 1379238106Sdesupdate_events(struct module_env* env, struct val_env* ve, 1380238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1381238106Sdes int* changed) 1382238106Sdes{ 1383238106Sdes ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset, 1384238106Sdes env->scratch_buffer); 1385238106Sdes size_t i; 1386238106Sdes if(!r) 1387238106Sdes return 0; 1388238106Sdes init_events(tp); 1389238106Sdes for(i=0; i<ldns_rr_list_rr_count(r); i++) { 1390238106Sdes ldns_rr* rr = ldns_rr_list_rr(r, i); 1391238106Sdes struct autr_ta* ta = NULL; 1392238106Sdes if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) 1393238106Sdes continue; 1394238106Sdes if(!rr_is_dnskey_sep(rr)) 1395238106Sdes continue; 1396238106Sdes if(rr_is_dnskey_revoked(rr)) { 1397238106Sdes /* self-signed revoked keys already detected before, 1398238106Sdes * other revoked keys are not 'added' again */ 1399238106Sdes continue; 1400238106Sdes } 1401238106Sdes /* is a key of this type supported?. Note rr_list and 1402238106Sdes * packed_rrset are in the same order. */ 1403238106Sdes if(!dnskey_algo_is_supported(dnskey_rrset, i)) { 1404238106Sdes /* skip unknown algorithm key, it is useless to us */ 1405238106Sdes log_nametypeclass(VERB_DETAIL, "trust point has " 1406238106Sdes "unsupported algorithm at", 1407238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 1408238106Sdes continue; 1409238106Sdes } 1410238106Sdes 1411238106Sdes /* is it new? if revocation bit set, find the unrevoked key */ 1412238106Sdes if(!find_key(tp, rr, &ta)) { 1413238106Sdes ldns_rr_list_deep_free(r); /* malloc fail in compare*/ 1414238106Sdes return 0; 1415238106Sdes } 1416238106Sdes if(!ta) { 1417238106Sdes ta = add_key(tp, rr); 1418238106Sdes *changed = 1; 1419238106Sdes /* first time seen, do we have DSes? if match: VALID */ 1420238106Sdes if(ta && tp->ds_rrset && key_matches_a_ds(env, ve, 1421238106Sdes dnskey_rrset, i, tp->ds_rrset)) { 1422238106Sdes verbose_key(ta, VERB_ALGO, "verified by DS"); 1423238106Sdes ta->s = AUTR_STATE_VALID; 1424238106Sdes } 1425238106Sdes } 1426238106Sdes if(!ta) { 1427238106Sdes ldns_rr_list_deep_free(r); 1428238106Sdes return 0; 1429238106Sdes } 1430238106Sdes seen_trustanchor(ta, 1); 1431238106Sdes verbose_key(ta, VERB_ALGO, "in DNS response"); 1432238106Sdes } 1433238106Sdes set_tp_times(tp, min_expiry(env, r), key_ttl(dnskey_rrset), changed); 1434238106Sdes ldns_rr_list_deep_free(r); 1435238106Sdes return 1; 1436238106Sdes} 1437238106Sdes 1438238106Sdes/** 1439238106Sdes * Check if the holddown time has already exceeded 1440238106Sdes * setting: add-holddown: add holddown timer 1441238106Sdes * setting: del-holddown: del holddown timer 1442238106Sdes * @param env: environment with current time 1443238106Sdes * @param ta: trust anchor to check for. 1444238106Sdes * @param holddown: the timer value 1445238106Sdes * @return number of seconds the holddown has passed. 1446238106Sdes */ 1447238106Sdesstatic int 1448238106Sdescheck_holddown(struct module_env* env, struct autr_ta* ta, 1449238106Sdes unsigned int holddown) 1450238106Sdes{ 1451238106Sdes unsigned int elapsed; 1452238106Sdes if((unsigned)*env->now < (unsigned)ta->last_change) { 1453238106Sdes log_warn("time goes backwards. delaying key holddown"); 1454238106Sdes return 0; 1455238106Sdes } 1456238106Sdes elapsed = (unsigned)*env->now - (unsigned)ta->last_change; 1457238106Sdes if (elapsed > holddown) { 1458238106Sdes return (int) (elapsed-holddown); 1459238106Sdes } 1460238106Sdes verbose_key(ta, VERB_ALGO, "holddown time %d seconds to go", 1461238106Sdes (int) (holddown-elapsed)); 1462238106Sdes return 0; 1463238106Sdes} 1464238106Sdes 1465238106Sdes 1466238106Sdes/** Set last_change to now */ 1467238106Sdesstatic void 1468238106Sdesreset_holddown(struct module_env* env, struct autr_ta* ta, int* changed) 1469238106Sdes{ 1470238106Sdes ta->last_change = *env->now; 1471238106Sdes *changed = 1; 1472238106Sdes} 1473238106Sdes 1474238106Sdes/** Set the state for this trust anchor */ 1475238106Sdesstatic void 1476238106Sdesset_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed, 1477238106Sdes autr_state_t s) 1478238106Sdes{ 1479238106Sdes verbose_key(ta, VERB_ALGO, "update: %s to %s", 1480238106Sdes trustanchor_state2str(ta->s), trustanchor_state2str(s)); 1481238106Sdes ta->s = s; 1482238106Sdes reset_holddown(env, ta, changed); 1483238106Sdes} 1484238106Sdes 1485238106Sdes 1486238106Sdes/** Event: NewKey */ 1487238106Sdesstatic void 1488238106Sdesdo_newkey(struct module_env* env, struct autr_ta* anchor, int* c) 1489238106Sdes{ 1490238106Sdes if (anchor->s == AUTR_STATE_START) 1491238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND); 1492238106Sdes} 1493238106Sdes 1494238106Sdes/** Event: AddTime */ 1495238106Sdesstatic void 1496238106Sdesdo_addtime(struct module_env* env, struct autr_ta* anchor, int* c) 1497238106Sdes{ 1498238106Sdes /* This not according to RFC, this is 30 days, but the RFC demands 1499238106Sdes * MAX(30days, TTL expire time of first DNSKEY set with this key), 1500238106Sdes * The value may be too small if a very large TTL was used. */ 1501238106Sdes int exceeded = check_holddown(env, anchor, env->cfg->add_holddown); 1502238106Sdes if (exceeded && anchor->s == AUTR_STATE_ADDPEND) { 1503238106Sdes verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded " 1504238106Sdes "%d seconds ago, and pending-count %d", exceeded, 1505238106Sdes anchor->pending_count); 1506238106Sdes if(anchor->pending_count >= MIN_PENDINGCOUNT) { 1507238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1508238106Sdes anchor->pending_count = 0; 1509238106Sdes return; 1510238106Sdes } 1511238106Sdes verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check " 1512238106Sdes "failed (pending count: %d)", anchor->pending_count); 1513238106Sdes } 1514238106Sdes} 1515238106Sdes 1516238106Sdes/** Event: RemTime */ 1517238106Sdesstatic void 1518238106Sdesdo_remtime(struct module_env* env, struct autr_ta* anchor, int* c) 1519238106Sdes{ 1520238106Sdes int exceeded = check_holddown(env, anchor, env->cfg->del_holddown); 1521238106Sdes if(exceeded && anchor->s == AUTR_STATE_REVOKED) { 1522238106Sdes verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded " 1523238106Sdes "%d seconds ago", exceeded); 1524238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED); 1525238106Sdes } 1526238106Sdes} 1527238106Sdes 1528238106Sdes/** Event: KeyRem */ 1529238106Sdesstatic void 1530238106Sdesdo_keyrem(struct module_env* env, struct autr_ta* anchor, int* c) 1531238106Sdes{ 1532238106Sdes if(anchor->s == AUTR_STATE_ADDPEND) { 1533238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_START); 1534238106Sdes anchor->pending_count = 0; 1535238106Sdes } else if(anchor->s == AUTR_STATE_VALID) 1536238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING); 1537238106Sdes} 1538238106Sdes 1539238106Sdes/** Event: KeyPres */ 1540238106Sdesstatic void 1541238106Sdesdo_keypres(struct module_env* env, struct autr_ta* anchor, int* c) 1542238106Sdes{ 1543238106Sdes if(anchor->s == AUTR_STATE_MISSING) 1544238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1545238106Sdes} 1546238106Sdes 1547238106Sdes/* Event: Revoked */ 1548238106Sdesstatic void 1549238106Sdesdo_revoked(struct module_env* env, struct autr_ta* anchor, int* c) 1550238106Sdes{ 1551238106Sdes if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) { 1552238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED); 1553238106Sdes verbose_key(anchor, VERB_ALGO, "old id, prior to revocation"); 1554238106Sdes revoke_dnskey(anchor, 0); 1555238106Sdes verbose_key(anchor, VERB_ALGO, "new id, after revocation"); 1556238106Sdes } 1557238106Sdes} 1558238106Sdes 1559238106Sdes/** Do statestable transition matrix for anchor */ 1560238106Sdesstatic void 1561238106Sdesanchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c) 1562238106Sdes{ 1563238106Sdes log_assert(anchor); 1564238106Sdes switch(anchor->s) { 1565238106Sdes /* START */ 1566238106Sdes case AUTR_STATE_START: 1567238106Sdes /* NewKey: ADDPEND */ 1568238106Sdes if (anchor->fetched) 1569238106Sdes do_newkey(env, anchor, c); 1570238106Sdes break; 1571238106Sdes /* ADDPEND */ 1572238106Sdes case AUTR_STATE_ADDPEND: 1573238106Sdes /* KeyRem: START */ 1574238106Sdes if (!anchor->fetched) 1575238106Sdes do_keyrem(env, anchor, c); 1576238106Sdes /* AddTime: VALID */ 1577238106Sdes else do_addtime(env, anchor, c); 1578238106Sdes break; 1579238106Sdes /* VALID */ 1580238106Sdes case AUTR_STATE_VALID: 1581238106Sdes /* RevBit: REVOKED */ 1582238106Sdes if (anchor->revoked) 1583238106Sdes do_revoked(env, anchor, c); 1584238106Sdes /* KeyRem: MISSING */ 1585238106Sdes else if (!anchor->fetched) 1586238106Sdes do_keyrem(env, anchor, c); 1587238106Sdes else if(!anchor->last_change) { 1588238106Sdes verbose_key(anchor, VERB_ALGO, "first seen"); 1589238106Sdes reset_holddown(env, anchor, c); 1590238106Sdes } 1591238106Sdes break; 1592238106Sdes /* MISSING */ 1593238106Sdes case AUTR_STATE_MISSING: 1594238106Sdes /* RevBit: REVOKED */ 1595238106Sdes if (anchor->revoked) 1596238106Sdes do_revoked(env, anchor, c); 1597238106Sdes /* KeyPres */ 1598238106Sdes else if (anchor->fetched) 1599238106Sdes do_keypres(env, anchor, c); 1600238106Sdes break; 1601238106Sdes /* REVOKED */ 1602238106Sdes case AUTR_STATE_REVOKED: 1603238106Sdes if (anchor->fetched) 1604238106Sdes reset_holddown(env, anchor, c); 1605238106Sdes /* RemTime: REMOVED */ 1606238106Sdes else do_remtime(env, anchor, c); 1607238106Sdes break; 1608238106Sdes /* REMOVED */ 1609238106Sdes case AUTR_STATE_REMOVED: 1610238106Sdes default: 1611238106Sdes break; 1612238106Sdes } 1613238106Sdes} 1614238106Sdes 1615238106Sdes/** if ZSK init then trust KSKs */ 1616238106Sdesstatic int 1617238106Sdesinit_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed) 1618238106Sdes{ 1619238106Sdes /* search for VALID ZSKs */ 1620238106Sdes struct autr_ta* anchor; 1621238106Sdes int validzsk = 0; 1622238106Sdes int validksk = 0; 1623238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1624238106Sdes /* last_change test makes sure it was manually configured */ 1625238106Sdes if (ldns_rr_get_type(anchor->rr) == LDNS_RR_TYPE_DNSKEY && 1626238106Sdes anchor->last_change == 0 && 1627238106Sdes !rr_is_dnskey_sep(anchor->rr) && 1628238106Sdes anchor->s == AUTR_STATE_VALID) 1629238106Sdes validzsk++; 1630238106Sdes } 1631238106Sdes if(validzsk == 0) 1632238106Sdes return 0; 1633238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1634238106Sdes if (rr_is_dnskey_sep(anchor->rr) && 1635238106Sdes anchor->s == AUTR_STATE_ADDPEND) { 1636238106Sdes verbose_key(anchor, VERB_ALGO, "trust KSK from " 1637238106Sdes "ZSK(config)"); 1638238106Sdes set_trustanchor_state(env, anchor, changed, 1639238106Sdes AUTR_STATE_VALID); 1640238106Sdes validksk++; 1641238106Sdes } 1642238106Sdes } 1643238106Sdes return validksk; 1644238106Sdes} 1645238106Sdes 1646238106Sdes/** Remove missing trustanchors so the list does not grow forever */ 1647238106Sdesstatic void 1648238106Sdesremove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, 1649238106Sdes int* changed) 1650238106Sdes{ 1651238106Sdes struct autr_ta* anchor; 1652238106Sdes int exceeded; 1653238106Sdes int valid = 0; 1654238106Sdes /* see if we have anchors that are valid */ 1655238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1656238106Sdes /* Only do KSKs */ 1657238106Sdes if (!rr_is_dnskey_sep(anchor->rr)) 1658238106Sdes continue; 1659238106Sdes if (anchor->s == AUTR_STATE_VALID) 1660238106Sdes valid++; 1661238106Sdes } 1662238106Sdes /* if there are no SEP Valid anchors, see if we started out with 1663238106Sdes * a ZSK (last-change=0) anchor, which is VALID and there are KSKs 1664238106Sdes * now that can be made valid. Do this immediately because there 1665238106Sdes * is no guarantee that the ZSKs get announced long enough. Usually 1666238106Sdes * this is immediately after init with a ZSK trusted, unless the domain 1667238106Sdes * was not advertising any KSKs at all. In which case we perfectly 1668238106Sdes * track the zero number of KSKs. */ 1669238106Sdes if(valid == 0) { 1670238106Sdes valid = init_zsk_to_ksk(env, tp, changed); 1671238106Sdes if(valid == 0) 1672238106Sdes return; 1673238106Sdes } 1674238106Sdes 1675238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1676238106Sdes /* ignore ZSKs if newly added */ 1677238106Sdes if(anchor->s == AUTR_STATE_START) 1678238106Sdes continue; 1679238106Sdes /* remove ZSKs if a KSK is present */ 1680238106Sdes if (!rr_is_dnskey_sep(anchor->rr)) { 1681238106Sdes if(valid > 0) { 1682238106Sdes verbose_key(anchor, VERB_ALGO, "remove ZSK " 1683238106Sdes "[%d key(s) VALID]", valid); 1684238106Sdes set_trustanchor_state(env, anchor, changed, 1685238106Sdes AUTR_STATE_REMOVED); 1686238106Sdes } 1687238106Sdes continue; 1688238106Sdes } 1689238106Sdes /* Only do MISSING keys */ 1690238106Sdes if (anchor->s != AUTR_STATE_MISSING) 1691238106Sdes continue; 1692238106Sdes if(env->cfg->keep_missing == 0) 1693238106Sdes continue; /* keep forever */ 1694238106Sdes 1695238106Sdes exceeded = check_holddown(env, anchor, env->cfg->keep_missing); 1696238106Sdes /* If keep_missing has exceeded and we still have more than 1697238106Sdes * one valid KSK: remove missing trust anchor */ 1698238106Sdes if (exceeded && valid > 0) { 1699238106Sdes verbose_key(anchor, VERB_ALGO, "keep-missing time " 1700238106Sdes "exceeded %d seconds ago, [%d key(s) VALID]", 1701238106Sdes exceeded, valid); 1702238106Sdes set_trustanchor_state(env, anchor, changed, 1703238106Sdes AUTR_STATE_REMOVED); 1704238106Sdes } 1705238106Sdes } 1706238106Sdes} 1707238106Sdes 1708238106Sdes/** Do the statetable from RFC5011 transition matrix */ 1709238106Sdesstatic int 1710238106Sdesdo_statetable(struct module_env* env, struct trust_anchor* tp, int* changed) 1711238106Sdes{ 1712238106Sdes struct autr_ta* anchor; 1713238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1714238106Sdes /* Only do KSKs */ 1715238106Sdes if(!rr_is_dnskey_sep(anchor->rr)) 1716238106Sdes continue; 1717238106Sdes anchor_state_update(env, anchor, changed); 1718238106Sdes } 1719238106Sdes remove_missing_trustanchors(env, tp, changed); 1720238106Sdes return 1; 1721238106Sdes} 1722238106Sdes 1723238106Sdes/** See if time alone makes ADDPEND to VALID transition */ 1724238106Sdesstatic void 1725238106Sdesautr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c) 1726238106Sdes{ 1727238106Sdes struct autr_ta* anchor; 1728238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1729238106Sdes if(rr_is_dnskey_sep(anchor->rr) && 1730238106Sdes anchor->s == AUTR_STATE_ADDPEND) 1731238106Sdes do_addtime(env, anchor, c); 1732238106Sdes } 1733238106Sdes} 1734238106Sdes 1735238106Sdes/** cleanup key list */ 1736238106Sdesstatic void 1737238106Sdesautr_cleanup_keys(struct trust_anchor* tp) 1738238106Sdes{ 1739238106Sdes struct autr_ta* p, **prevp; 1740238106Sdes prevp = &tp->autr->keys; 1741238106Sdes p = tp->autr->keys; 1742238106Sdes while(p) { 1743238106Sdes /* do we want to remove this key? */ 1744238106Sdes if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED || 1745238106Sdes ldns_rr_get_type(p->rr) != LDNS_RR_TYPE_DNSKEY) { 1746238106Sdes struct autr_ta* np = p->next; 1747238106Sdes /* remove */ 1748238106Sdes ldns_rr_free(p->rr); 1749238106Sdes free(p); 1750238106Sdes /* snip and go to next item */ 1751238106Sdes *prevp = np; 1752238106Sdes p = np; 1753238106Sdes continue; 1754238106Sdes } 1755238106Sdes /* remove pending counts if no longer pending */ 1756238106Sdes if(p->s != AUTR_STATE_ADDPEND) 1757238106Sdes p->pending_count = 0; 1758238106Sdes prevp = &p->next; 1759238106Sdes p = p->next; 1760238106Sdes } 1761238106Sdes} 1762238106Sdes 1763238106Sdes/** calculate next probe time */ 1764238106Sdesstatic time_t 1765238106Sdescalc_next_probe(struct module_env* env, uint32_t wait) 1766238106Sdes{ 1767238106Sdes /* make it random, 90-100% */ 1768238106Sdes uint32_t rnd, rest; 1769238106Sdes if(wait < 3600) 1770238106Sdes wait = 3600; 1771238106Sdes rnd = wait/10; 1772238106Sdes rest = wait-rnd; 1773238106Sdes rnd = (uint32_t)ub_random_max(env->rnd, (long int)rnd); 1774238106Sdes return (time_t)(*env->now + rest + rnd); 1775238106Sdes} 1776238106Sdes 1777238106Sdes/** what is first probe time (anchors must be locked) */ 1778238106Sdesstatic time_t 1779238106Sdeswait_probe_time(struct val_anchors* anchors) 1780238106Sdes{ 1781238106Sdes rbnode_t* t = rbtree_first(&anchors->autr->probe); 1782238106Sdes if(t != RBTREE_NULL) 1783238106Sdes return ((struct trust_anchor*)t->key)->autr->next_probe_time; 1784238106Sdes return 0; 1785238106Sdes} 1786238106Sdes 1787238106Sdes/** reset worker timer */ 1788238106Sdesstatic void 1789238106Sdesreset_worker_timer(struct module_env* env) 1790238106Sdes{ 1791238106Sdes struct timeval tv; 1792238106Sdes#ifndef S_SPLINT_S 1793238106Sdes uint32_t next = (uint32_t)wait_probe_time(env->anchors); 1794238106Sdes /* in case this is libunbound, no timer */ 1795238106Sdes if(!env->probe_timer) 1796238106Sdes return; 1797238106Sdes if(next > *env->now) 1798238106Sdes tv.tv_sec = (time_t)(next - *env->now); 1799238106Sdes else tv.tv_sec = 0; 1800238106Sdes#endif 1801238106Sdes tv.tv_usec = 0; 1802238106Sdes comm_timer_set(env->probe_timer, &tv); 1803238106Sdes verbose(VERB_ALGO, "scheduled next probe in %d sec", (int)tv.tv_sec); 1804238106Sdes} 1805238106Sdes 1806238106Sdes/** set next probe for trust anchor */ 1807238106Sdesstatic int 1808238106Sdesset_next_probe(struct module_env* env, struct trust_anchor* tp, 1809238106Sdes struct ub_packed_rrset_key* dnskey_rrset) 1810238106Sdes{ 1811238106Sdes struct trust_anchor key, *tp2; 1812238106Sdes time_t mold, mnew; 1813238106Sdes /* use memory allocated in rrset for temporary name storage */ 1814238106Sdes key.node.key = &key; 1815238106Sdes key.name = dnskey_rrset->rk.dname; 1816238106Sdes key.namelen = dnskey_rrset->rk.dname_len; 1817238106Sdes key.namelabs = dname_count_labels(key.name); 1818238106Sdes key.dclass = tp->dclass; 1819238106Sdes lock_basic_unlock(&tp->lock); 1820238106Sdes 1821238106Sdes /* fetch tp again and lock anchors, so that we can modify the trees */ 1822238106Sdes lock_basic_lock(&env->anchors->lock); 1823238106Sdes tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key); 1824238106Sdes if(!tp2) { 1825238106Sdes verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe"); 1826238106Sdes lock_basic_unlock(&env->anchors->lock); 1827238106Sdes return 0; 1828238106Sdes } 1829238106Sdes log_assert(tp == tp2); 1830238106Sdes lock_basic_lock(&tp->lock); 1831238106Sdes 1832238106Sdes /* schedule */ 1833238106Sdes mold = wait_probe_time(env->anchors); 1834238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, tp); 1835238106Sdes tp->autr->next_probe_time = calc_next_probe(env, 1836238106Sdes tp->autr->query_interval); 1837238106Sdes (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 1838238106Sdes mnew = wait_probe_time(env->anchors); 1839238106Sdes 1840238106Sdes lock_basic_unlock(&env->anchors->lock); 1841238106Sdes verbose(VERB_ALGO, "next probe set in %d seconds", 1842238106Sdes (int)tp->autr->next_probe_time - (int)*env->now); 1843238106Sdes if(mold != mnew) { 1844238106Sdes reset_worker_timer(env); 1845238106Sdes } 1846238106Sdes return 1; 1847238106Sdes} 1848238106Sdes 1849238106Sdes/** Revoke and Delete a trust point */ 1850238106Sdesstatic void 1851238106Sdesautr_tp_remove(struct module_env* env, struct trust_anchor* tp, 1852238106Sdes struct ub_packed_rrset_key* dnskey_rrset) 1853238106Sdes{ 1854249141Sdes struct trust_anchor* del_tp; 1855238106Sdes struct trust_anchor key; 1856238106Sdes struct autr_point_data pd; 1857238106Sdes time_t mold, mnew; 1858238106Sdes 1859238106Sdes log_nametypeclass(VERB_OPS, "trust point was revoked", 1860238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 1861238106Sdes tp->autr->revoked = 1; 1862238106Sdes 1863238106Sdes /* use space allocated for dnskey_rrset to save name of anchor */ 1864238106Sdes memset(&key, 0, sizeof(key)); 1865238106Sdes memset(&pd, 0, sizeof(pd)); 1866238106Sdes key.autr = &pd; 1867238106Sdes key.node.key = &key; 1868238106Sdes pd.pnode.key = &key; 1869238106Sdes pd.next_probe_time = tp->autr->next_probe_time; 1870238106Sdes key.name = dnskey_rrset->rk.dname; 1871238106Sdes key.namelen = tp->namelen; 1872238106Sdes key.namelabs = tp->namelabs; 1873238106Sdes key.dclass = tp->dclass; 1874238106Sdes 1875238106Sdes /* unlock */ 1876238106Sdes lock_basic_unlock(&tp->lock); 1877238106Sdes 1878238106Sdes /* take from tree. It could be deleted by someone else,hence (void). */ 1879238106Sdes lock_basic_lock(&env->anchors->lock); 1880249141Sdes del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key); 1881238106Sdes mold = wait_probe_time(env->anchors); 1882238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, &key); 1883238106Sdes mnew = wait_probe_time(env->anchors); 1884238106Sdes anchors_init_parents_locked(env->anchors); 1885238106Sdes lock_basic_unlock(&env->anchors->lock); 1886238106Sdes 1887249141Sdes /* if !del_tp then the trust point is no longer present in the tree, 1888249141Sdes * it was deleted by someone else, who will write the zonefile and 1889249141Sdes * clean up the structure */ 1890249141Sdes if(del_tp) { 1891249141Sdes /* save on disk */ 1892249141Sdes del_tp->autr->next_probe_time = 0; /* no more probing for it */ 1893249141Sdes autr_write_file(env, del_tp); 1894238106Sdes 1895249141Sdes /* delete */ 1896249141Sdes autr_point_delete(del_tp); 1897249141Sdes } 1898238106Sdes if(mold != mnew) { 1899238106Sdes reset_worker_timer(env); 1900238106Sdes } 1901238106Sdes} 1902238106Sdes 1903238106Sdesint autr_process_prime(struct module_env* env, struct val_env* ve, 1904238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset) 1905238106Sdes{ 1906238106Sdes int changed = 0; 1907238106Sdes log_assert(tp && tp->autr); 1908238106Sdes /* autotrust update trust anchors */ 1909238106Sdes /* the tp is locked, and stays locked unless it is deleted */ 1910238106Sdes 1911238106Sdes /* we could just catch the anchor here while another thread 1912238106Sdes * is busy deleting it. Just unlock and let the other do its job */ 1913238106Sdes if(tp->autr->revoked) { 1914238106Sdes log_nametypeclass(VERB_ALGO, "autotrust not processed, " 1915238106Sdes "trust point revoked", tp->name, 1916238106Sdes LDNS_RR_TYPE_DNSKEY, tp->dclass); 1917238106Sdes lock_basic_unlock(&tp->lock); 1918238106Sdes return 0; /* it is revoked */ 1919238106Sdes } 1920238106Sdes 1921238106Sdes /* query_dnskeys(): */ 1922238106Sdes tp->autr->last_queried = *env->now; 1923238106Sdes 1924238106Sdes log_nametypeclass(VERB_ALGO, "autotrust process for", 1925238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 1926238106Sdes /* see if time alone makes some keys valid */ 1927238106Sdes autr_holddown_exceed(env, tp, &changed); 1928238106Sdes if(changed) { 1929238106Sdes verbose(VERB_ALGO, "autotrust: morekeys, reassemble"); 1930238106Sdes if(!autr_assemble(tp)) { 1931238106Sdes log_err("malloc failure assembling autotrust keys"); 1932238106Sdes return 1; /* unchanged */ 1933238106Sdes } 1934238106Sdes } 1935238106Sdes /* did we get any data? */ 1936238106Sdes if(!dnskey_rrset) { 1937238106Sdes verbose(VERB_ALGO, "autotrust: no dnskey rrset"); 1938238106Sdes /* no update of query_failed, because then we would have 1939238106Sdes * to write to disk. But we cannot because we maybe are 1940238106Sdes * still 'initialising' with DS records, that we cannot write 1941238106Sdes * in the full format (which only contains KSKs). */ 1942238106Sdes return 1; /* trust point exists */ 1943238106Sdes } 1944238106Sdes /* check for revoked keys to remove immediately */ 1945238106Sdes check_contains_revoked(env, ve, tp, dnskey_rrset, &changed); 1946238106Sdes if(changed) { 1947238106Sdes verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); 1948238106Sdes if(!autr_assemble(tp)) { 1949238106Sdes log_err("malloc failure assembling autotrust keys"); 1950238106Sdes return 1; /* unchanged */ 1951238106Sdes } 1952238106Sdes if(!tp->ds_rrset && !tp->dnskey_rrset) { 1953238106Sdes /* no more keys, all are revoked */ 1954238106Sdes /* this is a success for this probe attempt */ 1955238106Sdes tp->autr->last_success = *env->now; 1956238106Sdes autr_tp_remove(env, tp, dnskey_rrset); 1957238106Sdes return 0; /* trust point removed */ 1958238106Sdes } 1959238106Sdes } 1960238106Sdes /* verify the dnskey rrset and see if it is valid. */ 1961238106Sdes if(!verify_dnskey(env, ve, tp, dnskey_rrset)) { 1962238106Sdes verbose(VERB_ALGO, "autotrust: dnskey did not verify."); 1963238106Sdes /* only increase failure count if this is not the first prime, 1964238106Sdes * this means there was a previous succesful probe */ 1965238106Sdes if(tp->autr->last_success) { 1966238106Sdes tp->autr->query_failed += 1; 1967238106Sdes autr_write_file(env, tp); 1968238106Sdes } 1969238106Sdes return 1; /* trust point exists */ 1970238106Sdes } 1971238106Sdes 1972238106Sdes tp->autr->last_success = *env->now; 1973238106Sdes tp->autr->query_failed = 0; 1974238106Sdes 1975238106Sdes /* Add new trust anchors to the data structure 1976238106Sdes * - note which trust anchors are seen this probe. 1977238106Sdes * Set trustpoint query_interval and retry_time. 1978238106Sdes * - find minimum rrsig expiration interval 1979238106Sdes */ 1980238106Sdes if(!update_events(env, ve, tp, dnskey_rrset, &changed)) { 1981238106Sdes log_err("malloc failure in autotrust update_events. " 1982238106Sdes "trust point unchanged."); 1983238106Sdes return 1; /* trust point unchanged, so exists */ 1984238106Sdes } 1985238106Sdes 1986238106Sdes /* - for every SEP key do the 5011 statetable. 1987238106Sdes * - remove missing trustanchors (if veryold and we have new anchors). 1988238106Sdes */ 1989238106Sdes if(!do_statetable(env, tp, &changed)) { 1990238106Sdes log_err("malloc failure in autotrust do_statetable. " 1991238106Sdes "trust point unchanged."); 1992238106Sdes return 1; /* trust point unchanged, so exists */ 1993238106Sdes } 1994238106Sdes 1995238106Sdes autr_cleanup_keys(tp); 1996238106Sdes if(!set_next_probe(env, tp, dnskey_rrset)) 1997238106Sdes return 0; /* trust point does not exist */ 1998238106Sdes autr_write_file(env, tp); 1999238106Sdes if(changed) { 2000238106Sdes verbose(VERB_ALGO, "autotrust: changed, reassemble"); 2001238106Sdes if(!autr_assemble(tp)) { 2002238106Sdes log_err("malloc failure assembling autotrust keys"); 2003238106Sdes return 1; /* unchanged */ 2004238106Sdes } 2005238106Sdes if(!tp->ds_rrset && !tp->dnskey_rrset) { 2006238106Sdes /* no more keys, all are revoked */ 2007238106Sdes autr_tp_remove(env, tp, dnskey_rrset); 2008238106Sdes return 0; /* trust point removed */ 2009238106Sdes } 2010238106Sdes } else verbose(VERB_ALGO, "autotrust: no changes"); 2011238106Sdes 2012238106Sdes return 1; /* trust point exists */ 2013238106Sdes} 2014238106Sdes 2015238106Sdes/** debug print a trust anchor key */ 2016238106Sdesstatic void 2017238106Sdesautr_debug_print_ta(struct autr_ta* ta) 2018238106Sdes{ 2019238106Sdes char buf[32]; 2020238106Sdes char* str = ldns_rr2str(ta->rr); 2021238106Sdes if(!str) { 2022238106Sdes log_info("out of memory in debug_print_ta"); 2023238106Sdes return; 2024238106Sdes } 2025238106Sdes if(str && str[0]) str[strlen(str)-1]=0; /* remove newline */ 2026238106Sdes ctime_r(&ta->last_change, buf); 2027238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2028238106Sdes log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s", 2029238106Sdes trustanchor_state2str(ta->s), str, ta->s, ta->pending_count, 2030238106Sdes ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf); 2031238106Sdes free(str); 2032238106Sdes} 2033238106Sdes 2034238106Sdes/** debug print a trust point */ 2035238106Sdesstatic void 2036238106Sdesautr_debug_print_tp(struct trust_anchor* tp) 2037238106Sdes{ 2038238106Sdes struct autr_ta* ta; 2039238106Sdes char buf[257]; 2040238106Sdes if(!tp->autr) 2041238106Sdes return; 2042238106Sdes dname_str(tp->name, buf); 2043238106Sdes log_info("trust point %s : %d", buf, (int)tp->dclass); 2044238106Sdes log_info("assembled %d DS and %d DNSKEYs", 2045238106Sdes (int)tp->numDS, (int)tp->numDNSKEY); 2046238106Sdes if(0) { /* turned off because it prints to stderr */ 2047238106Sdes ldns_buffer* bf = ldns_buffer_new(70000); 2048238106Sdes ldns_rr_list* list; 2049238106Sdes if(tp->ds_rrset) { 2050238106Sdes list = packed_rrset_to_rr_list(tp->ds_rrset, bf); 2051238106Sdes ldns_rr_list_print(stderr, list); 2052238106Sdes ldns_rr_list_deep_free(list); 2053238106Sdes } 2054238106Sdes if(tp->dnskey_rrset) { 2055238106Sdes list = packed_rrset_to_rr_list(tp->dnskey_rrset, bf); 2056238106Sdes ldns_rr_list_print(stderr, list); 2057238106Sdes ldns_rr_list_deep_free(list); 2058238106Sdes } 2059238106Sdes ldns_buffer_free(bf); 2060238106Sdes } 2061238106Sdes log_info("file %s", tp->autr->file); 2062238106Sdes ctime_r(&tp->autr->last_queried, buf); 2063238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2064238106Sdes log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); 2065238106Sdes ctime_r(&tp->autr->last_success, buf); 2066238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2067238106Sdes log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf); 2068238106Sdes ctime_r(&tp->autr->next_probe_time, buf); 2069238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2070238106Sdes log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time, 2071238106Sdes buf); 2072238106Sdes log_info("query_interval: %u", (unsigned)tp->autr->query_interval); 2073238106Sdes log_info("retry_time: %u", (unsigned)tp->autr->retry_time); 2074238106Sdes log_info("query_failed: %u", (unsigned)tp->autr->query_failed); 2075238106Sdes 2076238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 2077238106Sdes autr_debug_print_ta(ta); 2078238106Sdes } 2079238106Sdes} 2080238106Sdes 2081238106Sdesvoid 2082238106Sdesautr_debug_print(struct val_anchors* anchors) 2083238106Sdes{ 2084238106Sdes struct trust_anchor* tp; 2085238106Sdes lock_basic_lock(&anchors->lock); 2086238106Sdes RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) { 2087238106Sdes lock_basic_lock(&tp->lock); 2088238106Sdes autr_debug_print_tp(tp); 2089238106Sdes lock_basic_unlock(&tp->lock); 2090238106Sdes } 2091238106Sdes lock_basic_unlock(&anchors->lock); 2092238106Sdes} 2093238106Sdes 2094238106Sdesvoid probe_answer_cb(void* arg, int ATTR_UNUSED(rcode), 2095238106Sdes ldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), 2096238106Sdes char* ATTR_UNUSED(why_bogus)) 2097238106Sdes{ 2098238106Sdes /* retry was set before the query was done, 2099238106Sdes * re-querytime is set when query succeeded, but that may not 2100238106Sdes * have reset this timer because the query could have been 2101238106Sdes * handled by another thread. In that case, this callback would 2102238106Sdes * get called after the original timeout is done. 2103238106Sdes * By not resetting the timer, it may probe more often, but not 2104238106Sdes * less often. 2105238106Sdes * Unless the new lookup resulted in smaller TTLs and thus smaller 2106238106Sdes * timeout values. In that case one old TTL could be mistakenly done. 2107238106Sdes */ 2108238106Sdes struct module_env* env = (struct module_env*)arg; 2109238106Sdes verbose(VERB_ALGO, "autotrust probe answer cb"); 2110238106Sdes reset_worker_timer(env); 2111238106Sdes} 2112238106Sdes 2113238106Sdes/** probe a trust anchor DNSKEY and unlocks tp */ 2114238106Sdesstatic void 2115238106Sdesprobe_anchor(struct module_env* env, struct trust_anchor* tp) 2116238106Sdes{ 2117238106Sdes struct query_info qinfo; 2118238106Sdes uint16_t qflags = BIT_RD; 2119238106Sdes struct edns_data edns; 2120238106Sdes ldns_buffer* buf = env->scratch_buffer; 2121238106Sdes qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen); 2122238106Sdes if(!qinfo.qname) { 2123238106Sdes log_err("out of memory making 5011 probe"); 2124238106Sdes return; 2125238106Sdes } 2126238106Sdes qinfo.qname_len = tp->namelen; 2127238106Sdes qinfo.qtype = LDNS_RR_TYPE_DNSKEY; 2128238106Sdes qinfo.qclass = tp->dclass; 2129238106Sdes log_query_info(VERB_ALGO, "autotrust probe", &qinfo); 2130238106Sdes verbose(VERB_ALGO, "retry probe set in %d seconds", 2131238106Sdes (int)tp->autr->next_probe_time - (int)*env->now); 2132238106Sdes edns.edns_present = 1; 2133238106Sdes edns.ext_rcode = 0; 2134238106Sdes edns.edns_version = 0; 2135238106Sdes edns.bits = EDNS_DO; 2136238106Sdes if(ldns_buffer_capacity(buf) < 65535) 2137238106Sdes edns.udp_size = (uint16_t)ldns_buffer_capacity(buf); 2138238106Sdes else edns.udp_size = 65535; 2139238106Sdes 2140238106Sdes /* can't hold the lock while mesh_run is processing */ 2141238106Sdes lock_basic_unlock(&tp->lock); 2142238106Sdes 2143238106Sdes /* delete the DNSKEY from rrset and key cache so an active probe 2144238106Sdes * is done. First the rrset so another thread does not use it 2145238106Sdes * to recreate the key entry in a race condition. */ 2146238106Sdes rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len, 2147238106Sdes qinfo.qtype, qinfo.qclass, 0); 2148238106Sdes key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len, 2149238106Sdes qinfo.qclass); 2150238106Sdes 2151238106Sdes if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 2152238106Sdes &probe_answer_cb, env)) { 2153238106Sdes log_err("out of memory making 5011 probe"); 2154238106Sdes } 2155238106Sdes} 2156238106Sdes 2157238106Sdes/** fetch first to-probe trust-anchor and lock it and set retrytime */ 2158238106Sdesstatic struct trust_anchor* 2159238106Sdestodo_probe(struct module_env* env, uint32_t* next) 2160238106Sdes{ 2161238106Sdes struct trust_anchor* tp; 2162238106Sdes rbnode_t* el; 2163238106Sdes /* get first one */ 2164238106Sdes lock_basic_lock(&env->anchors->lock); 2165238106Sdes if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { 2166238106Sdes /* in case of revoked anchors */ 2167238106Sdes lock_basic_unlock(&env->anchors->lock); 2168238106Sdes return NULL; 2169238106Sdes } 2170238106Sdes tp = (struct trust_anchor*)el->key; 2171238106Sdes lock_basic_lock(&tp->lock); 2172238106Sdes 2173238106Sdes /* is it eligible? */ 2174238106Sdes if((uint32_t)tp->autr->next_probe_time > *env->now) { 2175238106Sdes /* no more to probe */ 2176238106Sdes *next = (uint32_t)tp->autr->next_probe_time - *env->now; 2177238106Sdes lock_basic_unlock(&tp->lock); 2178238106Sdes lock_basic_unlock(&env->anchors->lock); 2179238106Sdes return NULL; 2180238106Sdes } 2181238106Sdes 2182238106Sdes /* reset its next probe time */ 2183238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, tp); 2184238106Sdes tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time); 2185238106Sdes (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 2186238106Sdes lock_basic_unlock(&env->anchors->lock); 2187238106Sdes 2188238106Sdes return tp; 2189238106Sdes} 2190238106Sdes 2191238106Sdesuint32_t 2192238106Sdesautr_probe_timer(struct module_env* env) 2193238106Sdes{ 2194238106Sdes struct trust_anchor* tp; 2195238106Sdes uint32_t next_probe = 3600; 2196238106Sdes int num = 0; 2197238106Sdes verbose(VERB_ALGO, "autotrust probe timer callback"); 2198238106Sdes /* while there are still anchors to probe */ 2199238106Sdes while( (tp = todo_probe(env, &next_probe)) ) { 2200238106Sdes /* make a probe for this anchor */ 2201238106Sdes probe_anchor(env, tp); 2202238106Sdes num++; 2203238106Sdes } 2204238106Sdes regional_free_all(env->scratch); 2205238106Sdes if(num == 0) 2206238106Sdes return 0; /* no trust points to probe */ 2207238106Sdes verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); 2208238106Sdes return next_probe; 2209238106Sdes} 2210