1933707f3Ssthen /* 2933707f3Ssthen * validator/autotrust.c - RFC5011 trust anchor management for unbound. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2009, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * Contains autotrust implementation. The implementation was taken from 40933707f3Ssthen * the autotrust daemon (BSD licensed), written by Matthijs Mekking. 41933707f3Ssthen * It was modified to fit into unbound. The state table process is the same. 42933707f3Ssthen */ 43933707f3Ssthen #include "config.h" 44933707f3Ssthen #include "validator/autotrust.h" 45933707f3Ssthen #include "validator/val_anchor.h" 46933707f3Ssthen #include "validator/val_utils.h" 47933707f3Ssthen #include "validator/val_sigcrypt.h" 48933707f3Ssthen #include "util/data/dname.h" 49933707f3Ssthen #include "util/data/packed_rrset.h" 50933707f3Ssthen #include "util/log.h" 51933707f3Ssthen #include "util/module.h" 52933707f3Ssthen #include "util/net_help.h" 53933707f3Ssthen #include "util/config_file.h" 54933707f3Ssthen #include "util/regional.h" 55933707f3Ssthen #include "util/random.h" 56933707f3Ssthen #include "util/data/msgparse.h" 57933707f3Ssthen #include "services/mesh.h" 58933707f3Ssthen #include "services/cache/rrset.h" 59933707f3Ssthen #include "validator/val_kcache.h" 60fdfb4ba6Ssthen #include "sldns/sbuffer.h" 61fdfb4ba6Ssthen #include "sldns/wire2str.h" 62fdfb4ba6Ssthen #include "sldns/str2wire.h" 63fdfb4ba6Ssthen #include "sldns/keyraw.h" 64fdfb4ba6Ssthen #include "sldns/rrdef.h" 655d76a658Ssthen #include <stdarg.h> 665d76a658Ssthen #include <ctype.h> 67933707f3Ssthen 68933707f3Ssthen /** number of times a key must be seen before it can become valid */ 69933707f3Ssthen #define MIN_PENDINGCOUNT 2 70933707f3Ssthen 71933707f3Ssthen /** Event: Revoked */ 72933707f3Ssthen static void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c); 73933707f3Ssthen 74933707f3Ssthen struct autr_global_data* autr_global_create(void) 75933707f3Ssthen { 76933707f3Ssthen struct autr_global_data* global; 77933707f3Ssthen global = (struct autr_global_data*)malloc(sizeof(*global)); 78933707f3Ssthen if(!global) 79933707f3Ssthen return NULL; 80933707f3Ssthen rbtree_init(&global->probe, &probetree_cmp); 81933707f3Ssthen return global; 82933707f3Ssthen } 83933707f3Ssthen 84933707f3Ssthen void autr_global_delete(struct autr_global_data* global) 85933707f3Ssthen { 86933707f3Ssthen if(!global) 87933707f3Ssthen return; 88933707f3Ssthen /* elements deleted by parent */ 89933707f3Ssthen free(global); 90933707f3Ssthen } 91933707f3Ssthen 92933707f3Ssthen int probetree_cmp(const void* x, const void* y) 93933707f3Ssthen { 94933707f3Ssthen struct trust_anchor* a = (struct trust_anchor*)x; 95933707f3Ssthen struct trust_anchor* b = (struct trust_anchor*)y; 96933707f3Ssthen log_assert(a->autr && b->autr); 97933707f3Ssthen if(a->autr->next_probe_time < b->autr->next_probe_time) 98933707f3Ssthen return -1; 99933707f3Ssthen if(a->autr->next_probe_time > b->autr->next_probe_time) 100933707f3Ssthen return 1; 101933707f3Ssthen /* time is equal, sort on trust point identity */ 102933707f3Ssthen return anchor_cmp(x, y); 103933707f3Ssthen } 104933707f3Ssthen 105933707f3Ssthen size_t 106933707f3Ssthen autr_get_num_anchors(struct val_anchors* anchors) 107933707f3Ssthen { 108933707f3Ssthen size_t res = 0; 109933707f3Ssthen if(!anchors) 110933707f3Ssthen return 0; 111933707f3Ssthen lock_basic_lock(&anchors->lock); 112933707f3Ssthen if(anchors->autr) 113933707f3Ssthen res = anchors->autr->probe.count; 114933707f3Ssthen lock_basic_unlock(&anchors->lock); 115933707f3Ssthen return res; 116933707f3Ssthen } 117933707f3Ssthen 118933707f3Ssthen /** Position in string */ 119933707f3Ssthen static int 120933707f3Ssthen position_in_string(char *str, const char* sub) 121933707f3Ssthen { 122933707f3Ssthen char* pos = strstr(str, sub); 123933707f3Ssthen if(pos) 124933707f3Ssthen return (int)(pos-str)+(int)strlen(sub); 125933707f3Ssthen return -1; 126933707f3Ssthen } 127933707f3Ssthen 128933707f3Ssthen /** Debug routine to print pretty key information */ 129933707f3Ssthen static void 130933707f3Ssthen verbose_key(struct autr_ta* ta, enum verbosity_value level, 131933707f3Ssthen const char* format, ...) ATTR_FORMAT(printf, 3, 4); 132933707f3Ssthen 133933707f3Ssthen /** 134933707f3Ssthen * Implementation of debug pretty key print 135933707f3Ssthen * @param ta: trust anchor key with DNSKEY data. 136933707f3Ssthen * @param level: verbosity level to print at. 137933707f3Ssthen * @param format: printf style format string. 138933707f3Ssthen */ 139933707f3Ssthen static void 140933707f3Ssthen verbose_key(struct autr_ta* ta, enum verbosity_value level, 141933707f3Ssthen const char* format, ...) 142933707f3Ssthen { 143933707f3Ssthen va_list args; 144933707f3Ssthen va_start(args, format); 145933707f3Ssthen if(verbosity >= level) { 1465d76a658Ssthen char* str = sldns_wire2str_dname(ta->rr, ta->dname_len); 1475d76a658Ssthen int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 1485d76a658Ssthen ta->rr, ta->rr_len, ta->dname_len), 1495d76a658Ssthen sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 1505d76a658Ssthen ta->dname_len)); 151933707f3Ssthen char msg[MAXSYSLOGMSGLEN]; 152933707f3Ssthen vsnprintf(msg, sizeof(msg), format, args); 153933707f3Ssthen verbose(level, "%s key %d %s", str?str:"??", keytag, msg); 154933707f3Ssthen free(str); 155933707f3Ssthen } 156933707f3Ssthen va_end(args); 157933707f3Ssthen } 158933707f3Ssthen 159933707f3Ssthen /** 160933707f3Ssthen * Parse comments 161933707f3Ssthen * @param str: to parse 162933707f3Ssthen * @param ta: trust key autotrust metadata 163933707f3Ssthen * @return false on failure. 164933707f3Ssthen */ 165933707f3Ssthen static int 166933707f3Ssthen parse_comments(char* str, struct autr_ta* ta) 167933707f3Ssthen { 168933707f3Ssthen int len = (int)strlen(str), pos = 0, timestamp = 0; 169933707f3Ssthen char* comment = (char*) malloc(sizeof(char)*len+1); 170933707f3Ssthen char* comments = comment; 171933707f3Ssthen if(!comment) { 172933707f3Ssthen log_err("malloc failure in parse"); 173933707f3Ssthen return 0; 174933707f3Ssthen } 175933707f3Ssthen /* skip over whitespace and data at start of line */ 176933707f3Ssthen while (*str != '\0' && *str != ';') 177933707f3Ssthen str++; 178933707f3Ssthen if (*str == ';') 179933707f3Ssthen str++; 180933707f3Ssthen /* copy comments */ 181933707f3Ssthen while (*str != '\0') 182933707f3Ssthen { 183933707f3Ssthen *comments = *str; 184933707f3Ssthen comments++; 185933707f3Ssthen str++; 186933707f3Ssthen } 187933707f3Ssthen *comments = '\0'; 188933707f3Ssthen 189933707f3Ssthen comments = comment; 190933707f3Ssthen 191933707f3Ssthen /* read state */ 192933707f3Ssthen pos = position_in_string(comments, "state="); 193933707f3Ssthen if (pos >= (int) strlen(comments)) 194933707f3Ssthen { 195933707f3Ssthen log_err("parse error"); 196933707f3Ssthen free(comment); 197933707f3Ssthen return 0; 198933707f3Ssthen } 199933707f3Ssthen if (pos <= 0) 200933707f3Ssthen ta->s = AUTR_STATE_VALID; 201933707f3Ssthen else 202933707f3Ssthen { 203933707f3Ssthen int s = (int) comments[pos] - '0'; 204933707f3Ssthen switch(s) 205933707f3Ssthen { 206933707f3Ssthen case AUTR_STATE_START: 207933707f3Ssthen case AUTR_STATE_ADDPEND: 208933707f3Ssthen case AUTR_STATE_VALID: 209933707f3Ssthen case AUTR_STATE_MISSING: 210933707f3Ssthen case AUTR_STATE_REVOKED: 211933707f3Ssthen case AUTR_STATE_REMOVED: 212933707f3Ssthen ta->s = s; 213933707f3Ssthen break; 214933707f3Ssthen default: 215933707f3Ssthen verbose_key(ta, VERB_OPS, "has undefined " 216933707f3Ssthen "state, considered NewKey"); 217933707f3Ssthen ta->s = AUTR_STATE_START; 218933707f3Ssthen break; 219933707f3Ssthen } 220933707f3Ssthen } 221933707f3Ssthen /* read pending count */ 222933707f3Ssthen pos = position_in_string(comments, "count="); 223933707f3Ssthen if (pos >= (int) strlen(comments)) 224933707f3Ssthen { 225933707f3Ssthen log_err("parse error"); 226933707f3Ssthen free(comment); 227933707f3Ssthen return 0; 228933707f3Ssthen } 229933707f3Ssthen if (pos <= 0) 230933707f3Ssthen ta->pending_count = 0; 231933707f3Ssthen else 232933707f3Ssthen { 233933707f3Ssthen comments += pos; 234933707f3Ssthen ta->pending_count = (uint8_t)atoi(comments); 235933707f3Ssthen } 236933707f3Ssthen 237933707f3Ssthen /* read last change */ 238933707f3Ssthen pos = position_in_string(comments, "lastchange="); 239933707f3Ssthen if (pos >= (int) strlen(comments)) 240933707f3Ssthen { 241933707f3Ssthen log_err("parse error"); 242933707f3Ssthen free(comment); 243933707f3Ssthen return 0; 244933707f3Ssthen } 245933707f3Ssthen if (pos >= 0) 246933707f3Ssthen { 247933707f3Ssthen comments += pos; 248933707f3Ssthen timestamp = atoi(comments); 249933707f3Ssthen } 250933707f3Ssthen if (pos < 0 || !timestamp) 251933707f3Ssthen ta->last_change = 0; 252933707f3Ssthen else 253229e174cSsthen ta->last_change = (time_t)timestamp; 254933707f3Ssthen 255933707f3Ssthen free(comment); 256933707f3Ssthen return 1; 257933707f3Ssthen } 258933707f3Ssthen 259933707f3Ssthen /** Check if a line contains data (besides comments) */ 260933707f3Ssthen static int 261933707f3Ssthen str_contains_data(char* str, char comment) 262933707f3Ssthen { 263933707f3Ssthen while (*str != '\0') { 264933707f3Ssthen if (*str == comment || *str == '\n') 265933707f3Ssthen return 0; 266933707f3Ssthen if (*str != ' ' && *str != '\t') 267933707f3Ssthen return 1; 268933707f3Ssthen str++; 269933707f3Ssthen } 270933707f3Ssthen return 0; 271933707f3Ssthen } 272933707f3Ssthen 2735d76a658Ssthen /** Get DNSKEY flags 2745d76a658Ssthen * rdata without rdatalen in front of it. */ 275933707f3Ssthen static int 2765d76a658Ssthen dnskey_flags(uint16_t t, uint8_t* rdata, size_t len) 277933707f3Ssthen { 2785d76a658Ssthen uint16_t f; 2795d76a658Ssthen if(t != LDNS_RR_TYPE_DNSKEY) 280933707f3Ssthen return 0; 2815d76a658Ssthen if(len < 2) 2825d76a658Ssthen return 0; 2835d76a658Ssthen memmove(&f, rdata, 2); 2845d76a658Ssthen f = ntohs(f); 2855d76a658Ssthen return (int)f; 286933707f3Ssthen } 287933707f3Ssthen 2885d76a658Ssthen /** Check if KSK DNSKEY. 2895d76a658Ssthen * pass rdata without rdatalen in front of it */ 290933707f3Ssthen static int 2915d76a658Ssthen rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len) 292933707f3Ssthen { 2935d76a658Ssthen return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP); 294933707f3Ssthen } 295933707f3Ssthen 2965d76a658Ssthen /** Check if TA is KSK DNSKEY */ 297933707f3Ssthen static int 2985d76a658Ssthen ta_is_dnskey_sep(struct autr_ta* ta) 299933707f3Ssthen { 3005d76a658Ssthen return (dnskey_flags( 3015d76a658Ssthen sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len), 3025d76a658Ssthen sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len), 3035d76a658Ssthen sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) 3045d76a658Ssthen ) & DNSKEY_BIT_SEP); 3055d76a658Ssthen } 3065d76a658Ssthen 3075d76a658Ssthen /** Check if REVOKED DNSKEY 3085d76a658Ssthen * pass rdata without rdatalen in front of it */ 3095d76a658Ssthen static int 3105d76a658Ssthen rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len) 3115d76a658Ssthen { 3125d76a658Ssthen return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY); 313933707f3Ssthen } 314933707f3Ssthen 315933707f3Ssthen /** create ta */ 316933707f3Ssthen static struct autr_ta* 3175d76a658Ssthen autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len) 318933707f3Ssthen { 319933707f3Ssthen struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta)); 320933707f3Ssthen if(!ta) { 3215d76a658Ssthen free(rr); 322933707f3Ssthen return NULL; 323933707f3Ssthen } 324933707f3Ssthen ta->rr = rr; 3255d76a658Ssthen ta->rr_len = rr_len; 3265d76a658Ssthen ta->dname_len = dname_len; 327933707f3Ssthen return ta; 328933707f3Ssthen } 329933707f3Ssthen 330933707f3Ssthen /** create tp */ 331933707f3Ssthen static struct trust_anchor* 3325d76a658Ssthen autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len, 3335d76a658Ssthen uint16_t dc) 334933707f3Ssthen { 335933707f3Ssthen struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp)); 336933707f3Ssthen if(!tp) return NULL; 3375d76a658Ssthen tp->name = memdup(own, own_len); 338933707f3Ssthen if(!tp->name) { 339933707f3Ssthen free(tp); 340933707f3Ssthen return NULL; 341933707f3Ssthen } 3425d76a658Ssthen tp->namelen = own_len; 343933707f3Ssthen tp->namelabs = dname_count_labels(tp->name); 344933707f3Ssthen tp->node.key = tp; 345933707f3Ssthen tp->dclass = dc; 346933707f3Ssthen tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr)); 347933707f3Ssthen if(!tp->autr) { 348933707f3Ssthen free(tp->name); 349933707f3Ssthen free(tp); 350933707f3Ssthen return NULL; 351933707f3Ssthen } 352933707f3Ssthen tp->autr->pnode.key = tp; 353933707f3Ssthen 354933707f3Ssthen lock_basic_lock(&anchors->lock); 355933707f3Ssthen if(!rbtree_insert(anchors->tree, &tp->node)) { 356f46c52bfSsthen char buf[LDNS_MAX_DOMAINLEN+1]; 357933707f3Ssthen lock_basic_unlock(&anchors->lock); 358f46c52bfSsthen dname_str(tp->name, buf); 359f46c52bfSsthen log_err("trust anchor for '%s' presented twice", buf); 360933707f3Ssthen free(tp->name); 361933707f3Ssthen free(tp->autr); 362933707f3Ssthen free(tp); 363933707f3Ssthen return NULL; 364933707f3Ssthen } 365933707f3Ssthen if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) { 366f46c52bfSsthen char buf[LDNS_MAX_DOMAINLEN+1]; 367933707f3Ssthen (void)rbtree_delete(anchors->tree, tp); 368933707f3Ssthen lock_basic_unlock(&anchors->lock); 369f46c52bfSsthen dname_str(tp->name, buf); 370f46c52bfSsthen log_err("trust anchor for '%s' in probetree twice", buf); 371933707f3Ssthen free(tp->name); 372933707f3Ssthen free(tp->autr); 373933707f3Ssthen free(tp); 374933707f3Ssthen return NULL; 375933707f3Ssthen } 376933707f3Ssthen lock_basic_init(&tp->lock); 377933707f3Ssthen lock_protect(&tp->lock, tp, sizeof(*tp)); 378933707f3Ssthen lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr)); 379ebf5bb73Ssthen lock_basic_unlock(&anchors->lock); 380933707f3Ssthen return tp; 381933707f3Ssthen } 382933707f3Ssthen 383933707f3Ssthen /** delete assembled rrsets */ 384933707f3Ssthen static void 385933707f3Ssthen autr_rrset_delete(struct ub_packed_rrset_key* r) 386933707f3Ssthen { 387933707f3Ssthen if(r) { 388933707f3Ssthen free(r->rk.dname); 389933707f3Ssthen free(r->entry.data); 390933707f3Ssthen free(r); 391933707f3Ssthen } 392933707f3Ssthen } 393933707f3Ssthen 394933707f3Ssthen void autr_point_delete(struct trust_anchor* tp) 395933707f3Ssthen { 396933707f3Ssthen if(!tp) 397933707f3Ssthen return; 398933707f3Ssthen lock_unprotect(&tp->lock, tp); 399933707f3Ssthen lock_unprotect(&tp->lock, tp->autr); 400933707f3Ssthen lock_basic_destroy(&tp->lock); 401933707f3Ssthen autr_rrset_delete(tp->ds_rrset); 402933707f3Ssthen autr_rrset_delete(tp->dnskey_rrset); 403933707f3Ssthen if(tp->autr) { 404933707f3Ssthen struct autr_ta* p = tp->autr->keys, *np; 405933707f3Ssthen while(p) { 406933707f3Ssthen np = p->next; 4075d76a658Ssthen free(p->rr); 408933707f3Ssthen free(p); 409933707f3Ssthen p = np; 410933707f3Ssthen } 411933707f3Ssthen free(tp->autr->file); 412933707f3Ssthen free(tp->autr); 413933707f3Ssthen } 414933707f3Ssthen free(tp->name); 415933707f3Ssthen free(tp); 416933707f3Ssthen } 417933707f3Ssthen 418933707f3Ssthen /** find or add a new trust point for autotrust */ 419933707f3Ssthen static struct trust_anchor* 4205d76a658Ssthen find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, 4215d76a658Ssthen size_t dname_len) 422933707f3Ssthen { 423933707f3Ssthen struct trust_anchor* tp; 4245d76a658Ssthen tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len, 4255d76a658Ssthen sldns_wirerr_get_class(rr, rr_len, dname_len)); 426933707f3Ssthen if(tp) { 427933707f3Ssthen if(!tp->autr) { 428933707f3Ssthen log_err("anchor cannot be with and without autotrust"); 429933707f3Ssthen lock_basic_unlock(&tp->lock); 430933707f3Ssthen return NULL; 431933707f3Ssthen } 432933707f3Ssthen return tp; 433933707f3Ssthen } 4345d76a658Ssthen tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr, 4355d76a658Ssthen rr_len, dname_len)); 43677079be7Ssthen if(!tp) 43777079be7Ssthen return NULL; 438933707f3Ssthen lock_basic_lock(&tp->lock); 439933707f3Ssthen return tp; 440933707f3Ssthen } 441933707f3Ssthen 442933707f3Ssthen /** Add trust anchor from RR */ 443933707f3Ssthen static struct autr_ta* 4445d76a658Ssthen add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, 4455d76a658Ssthen size_t dname_len, struct trust_anchor** tp) 446933707f3Ssthen { 4475d76a658Ssthen struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len); 448933707f3Ssthen if(!ta) 449933707f3Ssthen return NULL; 4505d76a658Ssthen *tp = find_add_tp(anchors, rr, rr_len, dname_len); 451933707f3Ssthen if(!*tp) { 4525d76a658Ssthen free(ta->rr); 453933707f3Ssthen free(ta); 454933707f3Ssthen return NULL; 455933707f3Ssthen } 456933707f3Ssthen /* add ta to tp */ 457933707f3Ssthen ta->next = (*tp)->autr->keys; 458933707f3Ssthen (*tp)->autr->keys = ta; 459933707f3Ssthen lock_basic_unlock(&(*tp)->lock); 460933707f3Ssthen return ta; 461933707f3Ssthen } 462933707f3Ssthen 463933707f3Ssthen /** 464933707f3Ssthen * Add new trust anchor from a string in file. 465933707f3Ssthen * @param anchors: all anchors 466933707f3Ssthen * @param str: string with anchor and comments, if any comments. 467933707f3Ssthen * @param tp: trust point returned. 468933707f3Ssthen * @param origin: what to use for @ 4695d76a658Ssthen * @param origin_len: length of origin 470933707f3Ssthen * @param prev: previous rr name 4715d76a658Ssthen * @param prev_len: length of prev 472933707f3Ssthen * @param skip: if true, the result is NULL, but not an error, skip it. 473933707f3Ssthen * @return new key in trust point. 474933707f3Ssthen */ 475933707f3Ssthen static struct autr_ta* 476933707f3Ssthen add_trustanchor_frm_str(struct val_anchors* anchors, char* str, 4775d76a658Ssthen struct trust_anchor** tp, uint8_t* origin, size_t origin_len, 4785d76a658Ssthen uint8_t** prev, size_t* prev_len, int* skip) 479933707f3Ssthen { 4805d76a658Ssthen uint8_t rr[LDNS_RR_BUF_SIZE]; 4815d76a658Ssthen size_t rr_len = sizeof(rr), dname_len; 4825d76a658Ssthen uint8_t* drr; 4835d76a658Ssthen int lstatus; 484933707f3Ssthen if (!str_contains_data(str, ';')) { 485933707f3Ssthen *skip = 1; 486933707f3Ssthen return NULL; /* empty line */ 487933707f3Ssthen } 4885d76a658Ssthen if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len, 4895d76a658Ssthen 0, origin, origin_len, *prev, *prev_len))) 490933707f3Ssthen { 4915d76a658Ssthen log_err("ldns error while converting string to RR at%d: %s: %s", 4925d76a658Ssthen LDNS_WIREPARSE_OFFSET(lstatus), 4935d76a658Ssthen sldns_get_errorstr_parse(lstatus), str); 494933707f3Ssthen return NULL; 495933707f3Ssthen } 4965d76a658Ssthen free(*prev); 4975d76a658Ssthen *prev = memdup(rr, dname_len); 4985d76a658Ssthen *prev_len = dname_len; 4995d76a658Ssthen if(!*prev) { 5005d76a658Ssthen log_err("malloc failure in add_trustanchor"); 5015d76a658Ssthen return NULL; 5025d76a658Ssthen } 5035d76a658Ssthen if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY && 5045d76a658Ssthen sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) { 505933707f3Ssthen *skip = 1; 506933707f3Ssthen return NULL; /* only DS and DNSKEY allowed */ 507933707f3Ssthen } 5085d76a658Ssthen drr = memdup(rr, rr_len); 5095d76a658Ssthen if(!drr) { 5105d76a658Ssthen log_err("malloc failure in add trustanchor"); 5115d76a658Ssthen return NULL; 5125d76a658Ssthen } 5135d76a658Ssthen return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp); 514933707f3Ssthen } 515933707f3Ssthen 516933707f3Ssthen /** 517933707f3Ssthen * Load single anchor 518933707f3Ssthen * @param anchors: all points. 519933707f3Ssthen * @param str: comments line 520933707f3Ssthen * @param fname: filename 521229e174cSsthen * @param origin: the $ORIGIN. 5225d76a658Ssthen * @param origin_len: length of origin 523933707f3Ssthen * @param prev: passed to ldns. 5245d76a658Ssthen * @param prev_len: length of prev 525933707f3Ssthen * @param skip: if true, the result is NULL, but not an error, skip it. 526933707f3Ssthen * @return false on failure, otherwise the tp read. 527933707f3Ssthen */ 528933707f3Ssthen static struct trust_anchor* 529933707f3Ssthen load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, 5305d76a658Ssthen uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, 5315d76a658Ssthen int* skip) 532933707f3Ssthen { 533933707f3Ssthen struct autr_ta* ta = NULL; 534933707f3Ssthen struct trust_anchor* tp = NULL; 535933707f3Ssthen 5365d76a658Ssthen ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len, 5375d76a658Ssthen prev, prev_len, skip); 538933707f3Ssthen if(!ta) 539933707f3Ssthen return NULL; 540933707f3Ssthen lock_basic_lock(&tp->lock); 541933707f3Ssthen if(!parse_comments(str, ta)) { 542933707f3Ssthen lock_basic_unlock(&tp->lock); 543933707f3Ssthen return NULL; 544933707f3Ssthen } 545933707f3Ssthen if(!tp->autr->file) { 546933707f3Ssthen tp->autr->file = strdup(fname); 547933707f3Ssthen if(!tp->autr->file) { 548933707f3Ssthen lock_basic_unlock(&tp->lock); 549933707f3Ssthen log_err("malloc failure"); 550933707f3Ssthen return NULL; 551933707f3Ssthen } 552933707f3Ssthen } 553933707f3Ssthen lock_basic_unlock(&tp->lock); 554933707f3Ssthen return tp; 555933707f3Ssthen } 556933707f3Ssthen 5575d76a658Ssthen /** iterator for DSes from keylist. return true if a next element exists */ 5585d76a658Ssthen static int 5595d76a658Ssthen assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len, 5605d76a658Ssthen size_t* dname_len) 5615d76a658Ssthen { 5625d76a658Ssthen while(*list) { 5635d76a658Ssthen if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, 5645d76a658Ssthen (*list)->dname_len) == LDNS_RR_TYPE_DS) { 5655d76a658Ssthen *rr = (*list)->rr; 5665d76a658Ssthen *rr_len = (*list)->rr_len; 5675d76a658Ssthen *dname_len = (*list)->dname_len; 5685d76a658Ssthen *list = (*list)->next; 5695d76a658Ssthen return 1; 5705d76a658Ssthen } 5715d76a658Ssthen *list = (*list)->next; 5725d76a658Ssthen } 5735d76a658Ssthen return 0; 5745d76a658Ssthen } 5755d76a658Ssthen 5765d76a658Ssthen /** iterator for DNSKEYs from keylist. return true if a next element exists */ 5775d76a658Ssthen static int 5785d76a658Ssthen assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len, 5795d76a658Ssthen size_t* dname_len) 5805d76a658Ssthen { 5815d76a658Ssthen while(*list) { 5825d76a658Ssthen if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, 5835d76a658Ssthen (*list)->dname_len) != LDNS_RR_TYPE_DS && 5845d76a658Ssthen ((*list)->s == AUTR_STATE_VALID || 5855d76a658Ssthen (*list)->s == AUTR_STATE_MISSING)) { 5865d76a658Ssthen *rr = (*list)->rr; 5875d76a658Ssthen *rr_len = (*list)->rr_len; 5885d76a658Ssthen *dname_len = (*list)->dname_len; 5895d76a658Ssthen *list = (*list)->next; 5905d76a658Ssthen return 1; 5915d76a658Ssthen } 5925d76a658Ssthen *list = (*list)->next; 5935d76a658Ssthen } 5945d76a658Ssthen return 0; 5955d76a658Ssthen } 5965d76a658Ssthen 5975d76a658Ssthen /** see if iterator-list has any elements in it, or it is empty */ 5985d76a658Ssthen static int 5995d76a658Ssthen assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*, 6005d76a658Ssthen size_t*), struct autr_ta* list) 6015d76a658Ssthen { 6025d76a658Ssthen uint8_t* rr = NULL; 6035d76a658Ssthen size_t rr_len = 0, dname_len = 0; 6045d76a658Ssthen return iter(&list, &rr, &rr_len, &dname_len); 6055d76a658Ssthen } 6065d76a658Ssthen 6075d76a658Ssthen /** number of elements in iterator list */ 6085d76a658Ssthen static size_t 6095d76a658Ssthen assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*, 6105d76a658Ssthen size_t*), struct autr_ta* list) 6115d76a658Ssthen { 6125d76a658Ssthen uint8_t* rr = NULL; 6135d76a658Ssthen size_t i = 0, rr_len = 0, dname_len = 0; 6145d76a658Ssthen while(iter(&list, &rr, &rr_len, &dname_len)) { 6155d76a658Ssthen i++; 6165d76a658Ssthen } 6175d76a658Ssthen return i; 6185d76a658Ssthen } 6195d76a658Ssthen 6205d76a658Ssthen /** 6215d76a658Ssthen * Create a ub_packed_rrset_key allocated on the heap. 6225d76a658Ssthen * It therefore does not have the correct ID value, and cannot be used 6235d76a658Ssthen * inside the cache. It can be used in storage outside of the cache. 6245d76a658Ssthen * Keys for the cache have to be obtained from alloc.h . 6255d76a658Ssthen * @param iter: iterator over the elements in the list. It filters elements. 6265d76a658Ssthen * @param list: the list. 6275d76a658Ssthen * @return key allocated or NULL on failure. 6285d76a658Ssthen */ 6295d76a658Ssthen static struct ub_packed_rrset_key* 6305d76a658Ssthen ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*, 6315d76a658Ssthen size_t*), struct autr_ta* list) 6325d76a658Ssthen { 6335d76a658Ssthen uint8_t* rr = NULL; 6345d76a658Ssthen size_t rr_len = 0, dname_len = 0; 6355d76a658Ssthen struct ub_packed_rrset_key* k; 6365d76a658Ssthen if(!iter(&list, &rr, &rr_len, &dname_len)) 6375d76a658Ssthen return NULL; 6385d76a658Ssthen k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k)); 6395d76a658Ssthen if(!k) 6405d76a658Ssthen return NULL; 6415d76a658Ssthen k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); 6425d76a658Ssthen k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); 6435d76a658Ssthen k->rk.dname_len = dname_len; 6445d76a658Ssthen k->rk.dname = memdup(rr, dname_len); 6455d76a658Ssthen if(!k->rk.dname) { 6465d76a658Ssthen free(k); 6475d76a658Ssthen return NULL; 6485d76a658Ssthen } 6495d76a658Ssthen return k; 6505d76a658Ssthen } 6515d76a658Ssthen 6525d76a658Ssthen /** 6535d76a658Ssthen * Create packed_rrset data on the heap. 6545d76a658Ssthen * @param iter: iterator over the elements in the list. It filters elements. 6555d76a658Ssthen * @param list: the list. 6565d76a658Ssthen * @return data allocated or NULL on failure. 6575d76a658Ssthen */ 6585d76a658Ssthen static struct packed_rrset_data* 6595d76a658Ssthen packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*, 6605d76a658Ssthen size_t*), struct autr_ta* list) 6615d76a658Ssthen { 6625d76a658Ssthen uint8_t* rr = NULL; 6635d76a658Ssthen size_t rr_len = 0, dname_len = 0; 6645d76a658Ssthen struct packed_rrset_data* data; 6655d76a658Ssthen size_t count=0, rrsig_count=0, len=0, i, total; 6665d76a658Ssthen uint8_t* nextrdata; 6675d76a658Ssthen struct autr_ta* list_i; 6685d76a658Ssthen time_t ttl = 0; 6695d76a658Ssthen 6705d76a658Ssthen list_i = list; 6715d76a658Ssthen while(iter(&list_i, &rr, &rr_len, &dname_len)) { 6725d76a658Ssthen if(sldns_wirerr_get_type(rr, rr_len, dname_len) == 6735d76a658Ssthen LDNS_RR_TYPE_RRSIG) 6745d76a658Ssthen rrsig_count++; 6755d76a658Ssthen else count++; 6765d76a658Ssthen /* sizeof the rdlength + rdatalen */ 6775d76a658Ssthen len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); 6785d76a658Ssthen ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len); 6795d76a658Ssthen } 6805d76a658Ssthen if(count == 0 && rrsig_count == 0) 6815d76a658Ssthen return NULL; 6825d76a658Ssthen 6835d76a658Ssthen /* allocate */ 6845d76a658Ssthen total = count + rrsig_count; 6855d76a658Ssthen len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) + 6865d76a658Ssthen sizeof(uint8_t*)); 6875d76a658Ssthen data = (struct packed_rrset_data*)calloc(1, len); 6885d76a658Ssthen if(!data) 6895d76a658Ssthen return NULL; 6905d76a658Ssthen 6915d76a658Ssthen /* fill it */ 6925d76a658Ssthen data->ttl = ttl; 6935d76a658Ssthen data->count = count; 6945d76a658Ssthen data->rrsig_count = rrsig_count; 6955d76a658Ssthen data->rr_len = (size_t*)((uint8_t*)data + 6965d76a658Ssthen sizeof(struct packed_rrset_data)); 6975d76a658Ssthen data->rr_data = (uint8_t**)&(data->rr_len[total]); 6985d76a658Ssthen data->rr_ttl = (time_t*)&(data->rr_data[total]); 6995d76a658Ssthen nextrdata = (uint8_t*)&(data->rr_ttl[total]); 7005d76a658Ssthen 7015d76a658Ssthen /* fill out len, ttl, fields */ 7025d76a658Ssthen list_i = list; 7035d76a658Ssthen i = 0; 7045d76a658Ssthen while(iter(&list_i, &rr, &rr_len, &dname_len)) { 7055d76a658Ssthen data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, 7065d76a658Ssthen dname_len); 7075d76a658Ssthen if(data->rr_ttl[i] < data->ttl) 7085d76a658Ssthen data->ttl = data->rr_ttl[i]; 7095d76a658Ssthen data->rr_len[i] = 2 /* the rdlength */ + 7105d76a658Ssthen sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); 7115d76a658Ssthen i++; 7125d76a658Ssthen } 7135d76a658Ssthen 7145d76a658Ssthen /* fixup rest of ptrs */ 7155d76a658Ssthen for(i=0; i<total; i++) { 7165d76a658Ssthen data->rr_data[i] = nextrdata; 7175d76a658Ssthen nextrdata += data->rr_len[i]; 7185d76a658Ssthen } 7195d76a658Ssthen 7205d76a658Ssthen /* copy data in there */ 7215d76a658Ssthen list_i = list; 7225d76a658Ssthen i = 0; 7235d76a658Ssthen while(iter(&list_i, &rr, &rr_len, &dname_len)) { 724452a1548Ssthen log_assert(data->rr_data[i]); 7255d76a658Ssthen memmove(data->rr_data[i], 7265d76a658Ssthen sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), 7275d76a658Ssthen data->rr_len[i]); 7285d76a658Ssthen i++; 7295d76a658Ssthen } 7305d76a658Ssthen 7315d76a658Ssthen if(data->rrsig_count && data->count == 0) { 7325d76a658Ssthen data->count = data->rrsig_count; /* rrset type is RRSIG */ 7335d76a658Ssthen data->rrsig_count = 0; 7345d76a658Ssthen } 7355d76a658Ssthen return data; 7365d76a658Ssthen } 7375d76a658Ssthen 738933707f3Ssthen /** 739933707f3Ssthen * Assemble the trust anchors into DS and DNSKEY packed rrsets. 740933707f3Ssthen * Uses only VALID and MISSING DNSKEYs. 7415d76a658Ssthen * Read the sldns_rrs and builds packed rrsets 742933707f3Ssthen * @param tp: the trust point. Must be locked. 743933707f3Ssthen * @return false on malloc failure. 744933707f3Ssthen */ 745933707f3Ssthen static int 746933707f3Ssthen autr_assemble(struct trust_anchor* tp) 747933707f3Ssthen { 748933707f3Ssthen struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL; 749933707f3Ssthen 750933707f3Ssthen /* make packed rrset keys - malloced with no ID number, they 751933707f3Ssthen * are not in the cache */ 752933707f3Ssthen /* make packed rrset data (if there is a key) */ 7535d76a658Ssthen if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) { 7545d76a658Ssthen ubds = ub_packed_rrset_heap_key( 7555d76a658Ssthen assemble_iterate_ds, tp->autr->keys); 756933707f3Ssthen if(!ubds) 757933707f3Ssthen goto error_cleanup; 7585d76a658Ssthen ubds->entry.data = packed_rrset_heap_data( 7595d76a658Ssthen assemble_iterate_ds, tp->autr->keys); 760933707f3Ssthen if(!ubds->entry.data) 761933707f3Ssthen goto error_cleanup; 762933707f3Ssthen } 7635d76a658Ssthen 7645d76a658Ssthen /* make packed DNSKEY data */ 7655d76a658Ssthen if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) { 7665d76a658Ssthen ubdnskey = ub_packed_rrset_heap_key( 7675d76a658Ssthen assemble_iterate_dnskey, tp->autr->keys); 768933707f3Ssthen if(!ubdnskey) 769933707f3Ssthen goto error_cleanup; 7705d76a658Ssthen ubdnskey->entry.data = packed_rrset_heap_data( 7715d76a658Ssthen assemble_iterate_dnskey, tp->autr->keys); 772933707f3Ssthen if(!ubdnskey->entry.data) { 773933707f3Ssthen error_cleanup: 774933707f3Ssthen autr_rrset_delete(ubds); 775933707f3Ssthen autr_rrset_delete(ubdnskey); 776933707f3Ssthen return 0; 777933707f3Ssthen } 778933707f3Ssthen } 7795d76a658Ssthen 780933707f3Ssthen /* we have prepared the new keys so nothing can go wrong any more. 781933707f3Ssthen * And we are sure we cannot be left without trustanchor after 782933707f3Ssthen * any errors. Put in the new keys and remove old ones. */ 783933707f3Ssthen 784933707f3Ssthen /* free the old data */ 785933707f3Ssthen autr_rrset_delete(tp->ds_rrset); 786933707f3Ssthen autr_rrset_delete(tp->dnskey_rrset); 787933707f3Ssthen 788933707f3Ssthen /* assign the data to replace the old */ 789933707f3Ssthen tp->ds_rrset = ubds; 790933707f3Ssthen tp->dnskey_rrset = ubdnskey; 7915d76a658Ssthen tp->numDS = assemble_iterate_count(assemble_iterate_ds, 7925d76a658Ssthen tp->autr->keys); 7935d76a658Ssthen tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey, 7945d76a658Ssthen tp->autr->keys); 795933707f3Ssthen return 1; 796933707f3Ssthen } 797933707f3Ssthen 798933707f3Ssthen /** parse integer */ 799933707f3Ssthen static unsigned int 800933707f3Ssthen parse_int(char* line, int* ret) 801933707f3Ssthen { 802933707f3Ssthen char *e; 803933707f3Ssthen unsigned int x = (unsigned int)strtol(line, &e, 10); 804933707f3Ssthen if(line == e) { 805933707f3Ssthen *ret = -1; /* parse error */ 806933707f3Ssthen return 0; 807933707f3Ssthen } 808933707f3Ssthen *ret = 1; /* matched */ 809933707f3Ssthen return x; 810933707f3Ssthen } 811933707f3Ssthen 812933707f3Ssthen /** parse id sequence for anchor */ 813933707f3Ssthen static struct trust_anchor* 814933707f3Ssthen parse_id(struct val_anchors* anchors, char* line) 815933707f3Ssthen { 816933707f3Ssthen struct trust_anchor *tp; 817933707f3Ssthen int r; 818933707f3Ssthen uint16_t dclass; 8195d76a658Ssthen uint8_t* dname; 8205d76a658Ssthen size_t dname_len; 821933707f3Ssthen /* read the owner name */ 822933707f3Ssthen char* next = strchr(line, ' '); 823933707f3Ssthen if(!next) 824933707f3Ssthen return NULL; 825933707f3Ssthen next[0] = 0; 8265d76a658Ssthen dname = sldns_str2wire_dname(line, &dname_len); 8275d76a658Ssthen if(!dname) 828933707f3Ssthen return NULL; 829933707f3Ssthen 830933707f3Ssthen /* read the class */ 831933707f3Ssthen dclass = parse_int(next+1, &r); 832933707f3Ssthen if(r == -1) { 8335d76a658Ssthen free(dname); 834933707f3Ssthen return NULL; 835933707f3Ssthen } 836933707f3Ssthen 837933707f3Ssthen /* find the trust point */ 8385d76a658Ssthen tp = autr_tp_create(anchors, dname, dname_len, dclass); 8395d76a658Ssthen free(dname); 840933707f3Ssthen return tp; 841933707f3Ssthen } 842933707f3Ssthen 843933707f3Ssthen /** 844933707f3Ssthen * Parse variable from trustanchor header 845933707f3Ssthen * @param line: to parse 846933707f3Ssthen * @param anchors: the anchor is added to this, if "id:" is seen. 847933707f3Ssthen * @param anchor: the anchor as result value or previously returned anchor 848933707f3Ssthen * value to read the variable lines into. 849933707f3Ssthen * @return: 0 no match, -1 failed syntax error, +1 success line read. 850933707f3Ssthen * +2 revoked trust anchor file. 851933707f3Ssthen */ 852933707f3Ssthen static int 853933707f3Ssthen parse_var_line(char* line, struct val_anchors* anchors, 854933707f3Ssthen struct trust_anchor** anchor) 855933707f3Ssthen { 856933707f3Ssthen struct trust_anchor* tp = *anchor; 857933707f3Ssthen int r = 0; 858933707f3Ssthen if(strncmp(line, ";;id: ", 6) == 0) { 859933707f3Ssthen *anchor = parse_id(anchors, line+6); 860933707f3Ssthen if(!*anchor) return -1; 861933707f3Ssthen else return 1; 862933707f3Ssthen } else if(strncmp(line, ";;REVOKED", 9) == 0) { 863933707f3Ssthen if(tp) { 864933707f3Ssthen log_err("REVOKED statement must be at start of file"); 865933707f3Ssthen return -1; 866933707f3Ssthen } 867933707f3Ssthen return 2; 868933707f3Ssthen } else if(strncmp(line, ";;last_queried: ", 16) == 0) { 869933707f3Ssthen if(!tp) return -1; 870933707f3Ssthen lock_basic_lock(&tp->lock); 871933707f3Ssthen tp->autr->last_queried = (time_t)parse_int(line+16, &r); 872933707f3Ssthen lock_basic_unlock(&tp->lock); 873933707f3Ssthen } else if(strncmp(line, ";;last_success: ", 16) == 0) { 874933707f3Ssthen if(!tp) return -1; 875933707f3Ssthen lock_basic_lock(&tp->lock); 876933707f3Ssthen tp->autr->last_success = (time_t)parse_int(line+16, &r); 877933707f3Ssthen lock_basic_unlock(&tp->lock); 878933707f3Ssthen } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) { 879933707f3Ssthen if(!tp) return -1; 880933707f3Ssthen lock_basic_lock(&anchors->lock); 881933707f3Ssthen lock_basic_lock(&tp->lock); 882933707f3Ssthen (void)rbtree_delete(&anchors->autr->probe, tp); 883933707f3Ssthen tp->autr->next_probe_time = (time_t)parse_int(line+19, &r); 884933707f3Ssthen (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode); 885933707f3Ssthen lock_basic_unlock(&tp->lock); 886933707f3Ssthen lock_basic_unlock(&anchors->lock); 887933707f3Ssthen } else if(strncmp(line, ";;query_failed: ", 16) == 0) { 888933707f3Ssthen if(!tp) return -1; 889933707f3Ssthen lock_basic_lock(&tp->lock); 890933707f3Ssthen tp->autr->query_failed = (uint8_t)parse_int(line+16, &r); 891933707f3Ssthen lock_basic_unlock(&tp->lock); 892933707f3Ssthen } else if(strncmp(line, ";;query_interval: ", 18) == 0) { 893933707f3Ssthen if(!tp) return -1; 894933707f3Ssthen lock_basic_lock(&tp->lock); 895229e174cSsthen tp->autr->query_interval = (time_t)parse_int(line+18, &r); 896933707f3Ssthen lock_basic_unlock(&tp->lock); 897933707f3Ssthen } else if(strncmp(line, ";;retry_time: ", 14) == 0) { 898933707f3Ssthen if(!tp) return -1; 899933707f3Ssthen lock_basic_lock(&tp->lock); 900229e174cSsthen tp->autr->retry_time = (time_t)parse_int(line+14, &r); 901933707f3Ssthen lock_basic_unlock(&tp->lock); 902933707f3Ssthen } 903933707f3Ssthen return r; 904933707f3Ssthen } 905933707f3Ssthen 906933707f3Ssthen /** handle origin lines */ 907933707f3Ssthen static int 9085d76a658Ssthen handle_origin(char* line, uint8_t** origin, size_t* origin_len) 909933707f3Ssthen { 9105d76a658Ssthen size_t len = 0; 91198f3ca02Sbrad while(isspace((unsigned char)*line)) 912933707f3Ssthen line++; 913933707f3Ssthen if(strncmp(line, "$ORIGIN", 7) != 0) 914933707f3Ssthen return 0; 9155d76a658Ssthen free(*origin); 916933707f3Ssthen line += 7; 91798f3ca02Sbrad while(isspace((unsigned char)*line)) 918933707f3Ssthen line++; 9195d76a658Ssthen *origin = sldns_str2wire_dname(line, &len); 9205d76a658Ssthen *origin_len = len; 921933707f3Ssthen if(!*origin) 922933707f3Ssthen log_warn("malloc failure or parse error in $ORIGIN"); 923933707f3Ssthen return 1; 924933707f3Ssthen } 925933707f3Ssthen 926933707f3Ssthen /** Read one line and put multiline RRs onto one line string */ 927933707f3Ssthen static int 928933707f3Ssthen read_multiline(char* buf, size_t len, FILE* in, int* linenr) 929933707f3Ssthen { 930933707f3Ssthen char* pos = buf; 931933707f3Ssthen size_t left = len; 932933707f3Ssthen int depth = 0; 933933707f3Ssthen buf[len-1] = 0; 934933707f3Ssthen while(left > 0 && fgets(pos, (int)left, in) != NULL) { 935933707f3Ssthen size_t i, poslen = strlen(pos); 936933707f3Ssthen (*linenr)++; 937933707f3Ssthen 938933707f3Ssthen /* check what the new depth is after the line */ 939933707f3Ssthen /* this routine cannot handle braces inside quotes, 940933707f3Ssthen say for TXT records, but this routine only has to read keys */ 941933707f3Ssthen for(i=0; i<poslen; i++) { 942933707f3Ssthen if(pos[i] == '(') { 943933707f3Ssthen depth++; 944933707f3Ssthen } else if(pos[i] == ')') { 945933707f3Ssthen if(depth == 0) { 946933707f3Ssthen log_err("mismatch: too many ')'"); 947933707f3Ssthen return -1; 948933707f3Ssthen } 949933707f3Ssthen depth--; 950933707f3Ssthen } else if(pos[i] == ';') { 951933707f3Ssthen break; 952933707f3Ssthen } 953933707f3Ssthen } 954933707f3Ssthen 955933707f3Ssthen /* normal oneline or last line: keeps newline and comments */ 956933707f3Ssthen if(depth == 0) { 957933707f3Ssthen return 1; 958933707f3Ssthen } 959933707f3Ssthen 960933707f3Ssthen /* more lines expected, snip off comments and newline */ 961933707f3Ssthen if(poslen>0) 962933707f3Ssthen pos[poslen-1] = 0; /* strip newline */ 963933707f3Ssthen if(strchr(pos, ';')) 964933707f3Ssthen strchr(pos, ';')[0] = 0; /* strip comments */ 965933707f3Ssthen 966933707f3Ssthen /* move to paste other lines behind this one */ 967933707f3Ssthen poslen = strlen(pos); 968933707f3Ssthen pos += poslen; 969933707f3Ssthen left -= poslen; 970933707f3Ssthen /* the newline is changed into a space */ 971933707f3Ssthen if(left <= 2 /* space and eos */) { 972933707f3Ssthen log_err("line too long"); 973933707f3Ssthen return -1; 974933707f3Ssthen } 975933707f3Ssthen pos[0] = ' '; 976933707f3Ssthen pos[1] = 0; 977933707f3Ssthen pos += 1; 978933707f3Ssthen left -= 1; 979933707f3Ssthen } 980933707f3Ssthen if(depth != 0) { 981933707f3Ssthen log_err("mismatch: too many '('"); 982933707f3Ssthen return -1; 983933707f3Ssthen } 984933707f3Ssthen if(pos != buf) 985933707f3Ssthen return 1; 986933707f3Ssthen return 0; 987933707f3Ssthen } 988933707f3Ssthen 989933707f3Ssthen int autr_read_file(struct val_anchors* anchors, const char* nm) 990933707f3Ssthen { 991933707f3Ssthen /* the file descriptor */ 992933707f3Ssthen FILE* fd; 993933707f3Ssthen /* keep track of line numbers */ 994933707f3Ssthen int line_nr = 0; 995933707f3Ssthen /* single line */ 996933707f3Ssthen char line[10240]; 997933707f3Ssthen /* trust point being read */ 998933707f3Ssthen struct trust_anchor *tp = NULL, *tp2; 999933707f3Ssthen int r; 1000933707f3Ssthen /* for $ORIGIN parsing */ 10015d76a658Ssthen uint8_t *origin=NULL, *prev=NULL; 10025d76a658Ssthen size_t origin_len=0, prev_len=0; 1003933707f3Ssthen 1004933707f3Ssthen if (!(fd = fopen(nm, "r"))) { 1005933707f3Ssthen log_err("unable to open %s for reading: %s", 1006933707f3Ssthen nm, strerror(errno)); 1007933707f3Ssthen return 0; 1008933707f3Ssthen } 1009933707f3Ssthen verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); 1010933707f3Ssthen while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { 1011933707f3Ssthen if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { 1012933707f3Ssthen log_err("could not parse auto-trust-anchor-file " 1013933707f3Ssthen "%s line %d", nm, line_nr); 1014933707f3Ssthen fclose(fd); 10155d76a658Ssthen free(origin); 10165d76a658Ssthen free(prev); 1017933707f3Ssthen return 0; 1018933707f3Ssthen } else if(r == 1) { 1019933707f3Ssthen continue; 1020933707f3Ssthen } else if(r == 2) { 1021933707f3Ssthen log_warn("trust anchor %s has been revoked", nm); 1022933707f3Ssthen fclose(fd); 10235d76a658Ssthen free(origin); 10245d76a658Ssthen free(prev); 1025933707f3Ssthen return 1; 1026933707f3Ssthen } 1027933707f3Ssthen if (!str_contains_data(line, ';')) 1028933707f3Ssthen continue; /* empty lines allowed */ 10295d76a658Ssthen if(handle_origin(line, &origin, &origin_len)) 1030933707f3Ssthen continue; 1031933707f3Ssthen r = 0; 10325d76a658Ssthen if(!(tp2=load_trustanchor(anchors, line, nm, origin, 10335d76a658Ssthen origin_len, &prev, &prev_len, &r))) { 1034933707f3Ssthen if(!r) log_err("failed to load trust anchor from %s " 1035933707f3Ssthen "at line %i, skipping", nm, line_nr); 1036933707f3Ssthen /* try to do the rest */ 1037933707f3Ssthen continue; 1038933707f3Ssthen } 1039933707f3Ssthen if(tp && tp != tp2) { 1040933707f3Ssthen log_err("file %s has mismatching data inside: " 1041933707f3Ssthen "the file may only contain keys for one name, " 1042933707f3Ssthen "remove keys for other domain names", nm); 1043933707f3Ssthen fclose(fd); 10445d76a658Ssthen free(origin); 10455d76a658Ssthen free(prev); 1046933707f3Ssthen return 0; 1047933707f3Ssthen } 1048933707f3Ssthen tp = tp2; 1049933707f3Ssthen } 1050933707f3Ssthen fclose(fd); 10515d76a658Ssthen free(origin); 10525d76a658Ssthen free(prev); 1053933707f3Ssthen if(!tp) { 1054933707f3Ssthen log_err("failed to read %s", nm); 1055933707f3Ssthen return 0; 1056933707f3Ssthen } 1057933707f3Ssthen 1058933707f3Ssthen /* now assemble the data into DNSKEY and DS packed rrsets */ 1059933707f3Ssthen lock_basic_lock(&tp->lock); 1060933707f3Ssthen if(!autr_assemble(tp)) { 1061933707f3Ssthen lock_basic_unlock(&tp->lock); 1062933707f3Ssthen log_err("malloc failure assembling %s", nm); 1063933707f3Ssthen return 0; 1064933707f3Ssthen } 1065933707f3Ssthen lock_basic_unlock(&tp->lock); 1066933707f3Ssthen return 1; 1067933707f3Ssthen } 1068933707f3Ssthen 1069933707f3Ssthen /** string for a trustanchor state */ 1070933707f3Ssthen static const char* 107177079be7Ssthen trustanchor_state2str(autr_state_type s) 1072933707f3Ssthen { 1073933707f3Ssthen switch (s) { 1074933707f3Ssthen case AUTR_STATE_START: return " START "; 1075933707f3Ssthen case AUTR_STATE_ADDPEND: return " ADDPEND "; 1076933707f3Ssthen case AUTR_STATE_VALID: return " VALID "; 1077933707f3Ssthen case AUTR_STATE_MISSING: return " MISSING "; 1078933707f3Ssthen case AUTR_STATE_REVOKED: return " REVOKED "; 1079933707f3Ssthen case AUTR_STATE_REMOVED: return " REMOVED "; 1080933707f3Ssthen } 1081933707f3Ssthen return " UNKNOWN "; 1082933707f3Ssthen } 1083933707f3Ssthen 1084191f22c6Ssthen /** ctime r for autotrust */ 1085191f22c6Ssthen static char* autr_ctime_r(time_t* t, char* s) 1086191f22c6Ssthen { 1087191f22c6Ssthen ctime_r(t, s); 1088191f22c6Ssthen #ifdef USE_WINSOCK 1089191f22c6Ssthen if(strlen(s) > 10 && s[7]==' ' && s[8]=='0') 1090191f22c6Ssthen s[8]=' '; /* fix error in windows ctime */ 1091191f22c6Ssthen #endif 1092191f22c6Ssthen return s; 1093191f22c6Ssthen } 1094191f22c6Ssthen 1095933707f3Ssthen /** print ID to file */ 1096933707f3Ssthen static int 10975d76a658Ssthen print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass) 1098933707f3Ssthen { 10995d76a658Ssthen char* s = sldns_wire2str_dname(nm, nmlen); 11005d76a658Ssthen if(!s) { 11015d76a658Ssthen log_err("malloc failure in write to %s", fname); 1102933707f3Ssthen return 0; 1103933707f3Ssthen } 11045d76a658Ssthen if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) { 11055d76a658Ssthen log_err("could not write to %s: %s", fname, strerror(errno)); 11065d76a658Ssthen free(s); 11075d76a658Ssthen return 0; 11085d76a658Ssthen } 11095d76a658Ssthen free(s); 1110933707f3Ssthen return 1; 1111933707f3Ssthen } 1112933707f3Ssthen 1113933707f3Ssthen static int 11145d76a658Ssthen autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) 1115933707f3Ssthen { 1116933707f3Ssthen char tmi[32]; 1117933707f3Ssthen struct autr_ta* ta; 1118933707f3Ssthen char* str; 1119933707f3Ssthen 1120933707f3Ssthen /* write pretty header */ 1121933707f3Ssthen if(fprintf(out, "; autotrust trust anchor file\n") < 0) { 1122933707f3Ssthen log_err("could not write to %s: %s", fn, strerror(errno)); 1123933707f3Ssthen return 0; 1124933707f3Ssthen } 1125933707f3Ssthen if(tp->autr->revoked) { 1126933707f3Ssthen if(fprintf(out, ";;REVOKED\n") < 0 || 1127933707f3Ssthen fprintf(out, "; The zone has all keys revoked, and is\n" 1128933707f3Ssthen "; considered as if it has no trust anchors.\n" 1129933707f3Ssthen "; the remainder of the file is the last probe.\n" 1130933707f3Ssthen "; to restart the trust anchor, overwrite this file.\n" 1131933707f3Ssthen "; with one containing valid DNSKEYs or DSes.\n") < 0) { 1132933707f3Ssthen log_err("could not write to %s: %s", fn, strerror(errno)); 1133933707f3Ssthen return 0; 1134933707f3Ssthen } 1135933707f3Ssthen } 11365d76a658Ssthen if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) { 1137933707f3Ssthen return 0; 1138933707f3Ssthen } 1139933707f3Ssthen if(fprintf(out, ";;last_queried: %u ;;%s", 1140933707f3Ssthen (unsigned int)tp->autr->last_queried, 1141191f22c6Ssthen autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 || 1142933707f3Ssthen fprintf(out, ";;last_success: %u ;;%s", 1143933707f3Ssthen (unsigned int)tp->autr->last_success, 1144191f22c6Ssthen autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 || 1145933707f3Ssthen fprintf(out, ";;next_probe_time: %u ;;%s", 1146933707f3Ssthen (unsigned int)tp->autr->next_probe_time, 1147191f22c6Ssthen autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || 1148933707f3Ssthen fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0 1149933707f3Ssthen || fprintf(out, ";;query_interval: %d\n", 1150933707f3Ssthen (int)tp->autr->query_interval) < 0 || 1151933707f3Ssthen fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) { 1152933707f3Ssthen log_err("could not write to %s: %s", fn, strerror(errno)); 1153933707f3Ssthen return 0; 1154933707f3Ssthen } 1155933707f3Ssthen 1156933707f3Ssthen /* write anchors */ 1157933707f3Ssthen for(ta=tp->autr->keys; ta; ta=ta->next) { 1158933707f3Ssthen /* by default do not store START and REMOVED keys */ 1159933707f3Ssthen if(ta->s == AUTR_STATE_START) 1160933707f3Ssthen continue; 1161933707f3Ssthen if(ta->s == AUTR_STATE_REMOVED) 1162933707f3Ssthen continue; 1163933707f3Ssthen /* only store keys */ 11645d76a658Ssthen if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) 11655d76a658Ssthen != LDNS_RR_TYPE_DNSKEY) 1166933707f3Ssthen continue; 11675d76a658Ssthen str = sldns_wire2str_rr(ta->rr, ta->rr_len); 1168933707f3Ssthen if(!str || !str[0]) { 1169933707f3Ssthen free(str); 1170933707f3Ssthen log_err("malloc failure writing %s", fn); 1171933707f3Ssthen return 0; 1172933707f3Ssthen } 1173933707f3Ssthen str[strlen(str)-1] = 0; /* remove newline */ 1174933707f3Ssthen if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d " 1175933707f3Ssthen ";;lastchange=%u ;;%s", str, (int)ta->s, 1176933707f3Ssthen trustanchor_state2str(ta->s), (int)ta->pending_count, 1177933707f3Ssthen (unsigned int)ta->last_change, 1178191f22c6Ssthen autr_ctime_r(&(ta->last_change), tmi)) < 0) { 1179933707f3Ssthen log_err("could not write to %s: %s", fn, strerror(errno)); 1180933707f3Ssthen free(str); 1181933707f3Ssthen return 0; 1182933707f3Ssthen } 1183933707f3Ssthen free(str); 1184933707f3Ssthen } 1185933707f3Ssthen return 1; 1186933707f3Ssthen } 1187933707f3Ssthen 1188933707f3Ssthen void autr_write_file(struct module_env* env, struct trust_anchor* tp) 1189933707f3Ssthen { 1190933707f3Ssthen FILE* out; 1191933707f3Ssthen char* fname = tp->autr->file; 1192ebf5bb73Ssthen #ifndef S_SPLINT_S 11938240c1b9Ssthen long long llvalue; 1194ebf5bb73Ssthen #endif 1195933707f3Ssthen char tempf[2048]; 1196933707f3Ssthen log_assert(tp->autr); 1197229e174cSsthen if(!env) { 1198229e174cSsthen log_err("autr_write_file: Module environment is NULL."); 1199229e174cSsthen return; 1200229e174cSsthen } 12018240c1b9Ssthen /* unique name with pid number, thread number, and struct pointer 12028240c1b9Ssthen * (the pointer uniquifies for multiple libunbound contexts) */ 1203ebf5bb73Ssthen #ifndef S_SPLINT_S 12048240c1b9Ssthen #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX) 12058240c1b9Ssthen /* avoid warning about upcast on 32bit systems */ 12068240c1b9Ssthen llvalue = (unsigned long)tp; 12078240c1b9Ssthen #else 12088240c1b9Ssthen llvalue = (unsigned long long)tp; 12098240c1b9Ssthen #endif 12100bdb4f62Ssthen snprintf(tempf, sizeof(tempf), "%s.%d-%d-" ARG_LL "x", fname, (int)getpid(), 12118240c1b9Ssthen env->worker?*(int*)env->worker:0, llvalue); 1212ebf5bb73Ssthen #endif /* S_SPLINT_S */ 1213933707f3Ssthen verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf); 1214933707f3Ssthen out = fopen(tempf, "w"); 1215933707f3Ssthen if(!out) { 1216fdfb4ba6Ssthen fatal_exit("could not open autotrust file for writing, %s: %s", 1217933707f3Ssthen tempf, strerror(errno)); 1218933707f3Ssthen return; 1219933707f3Ssthen } 12205d76a658Ssthen if(!autr_write_contents(out, tempf, tp)) { 1221933707f3Ssthen /* failed to write contents (completely) */ 1222933707f3Ssthen fclose(out); 1223933707f3Ssthen unlink(tempf); 1224fdfb4ba6Ssthen fatal_exit("could not completely write: %s", fname); 1225933707f3Ssthen return; 1226933707f3Ssthen } 122724893edcSsthen if(fflush(out) != 0) 122824893edcSsthen log_err("could not fflush(%s): %s", fname, strerror(errno)); 122924893edcSsthen #ifdef HAVE_FSYNC 123024893edcSsthen if(fsync(fileno(out)) != 0) 123124893edcSsthen log_err("could not fsync(%s): %s", fname, strerror(errno)); 123224893edcSsthen #else 123377079be7Ssthen FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); 123424893edcSsthen #endif 12355d76a658Ssthen if(fclose(out) != 0) { 1236fdfb4ba6Ssthen fatal_exit("could not complete write: %s: %s", 12375d76a658Ssthen fname, strerror(errno)); 12385d76a658Ssthen unlink(tempf); 12395d76a658Ssthen return; 12405d76a658Ssthen } 1241933707f3Ssthen /* success; overwrite actual file */ 1242933707f3Ssthen verbose(VERB_ALGO, "autotrust: replaced %s", fname); 1243d8d14d0cSsthen #ifdef UB_ON_WINDOWS 1244d8d14d0cSsthen (void)unlink(fname); /* windows does not replace file with rename() */ 1245d8d14d0cSsthen #endif 1246933707f3Ssthen if(rename(tempf, fname) < 0) { 1247fdfb4ba6Ssthen fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno)); 1248933707f3Ssthen } 1249933707f3Ssthen } 1250933707f3Ssthen 1251933707f3Ssthen /** 1252933707f3Ssthen * Verify if dnskey works for trust point 1253933707f3Ssthen * @param env: environment (with time) for verification 1254933707f3Ssthen * @param ve: validator environment (with options) for verification. 1255933707f3Ssthen * @param tp: trust point to verify with 1256933707f3Ssthen * @param rrset: DNSKEY rrset to verify. 1257bdfc4d55Sflorian * @param qstate: qstate with region. 1258933707f3Ssthen * @return false on failure, true if verification successful. 1259933707f3Ssthen */ 1260933707f3Ssthen static int 1261933707f3Ssthen verify_dnskey(struct module_env* env, struct val_env* ve, 1262bdfc4d55Sflorian struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, 1263bdfc4d55Sflorian struct module_qstate* qstate) 1264933707f3Ssthen { 1265*98bc733bSsthen char reasonbuf[256]; 1266933707f3Ssthen char* reason = NULL; 1267933707f3Ssthen uint8_t sigalg[ALGO_NEEDS_MAX+1]; 1268a961b961Ssthen int downprot = env->cfg->harden_algo_downgrade; 1269933707f3Ssthen enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, 1270bdfc4d55Sflorian tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason, 1271*98bc733bSsthen NULL, qstate, reasonbuf, sizeof(reasonbuf)); 1272933707f3Ssthen /* sigalg is ignored, it returns algorithms signalled to exist, but 1273933707f3Ssthen * in 5011 there are no other rrsets to check. if downprot is 1274933707f3Ssthen * enabled, then it checks that the DNSKEY is signed with all 1275933707f3Ssthen * algorithms available in the trust store. */ 1276933707f3Ssthen verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s", 1277933707f3Ssthen sec_status_to_string(sec)); 1278933707f3Ssthen return sec == sec_status_secure; 1279933707f3Ssthen } 1280933707f3Ssthen 12815d76a658Ssthen static int32_t 12825d76a658Ssthen rrsig_get_expiry(uint8_t* d, size_t len) 12835d76a658Ssthen { 12845d76a658Ssthen /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */ 12855d76a658Ssthen if(len < 2+8+4) 12865d76a658Ssthen return 0; 12875d76a658Ssthen return sldns_read_uint32(d+2+8); 12885d76a658Ssthen } 12895d76a658Ssthen 1290933707f3Ssthen /** Find minimum expiration interval from signatures */ 1291229e174cSsthen static time_t 12925d76a658Ssthen min_expiry(struct module_env* env, struct packed_rrset_data* dd) 1293933707f3Ssthen { 1294933707f3Ssthen size_t i; 1295229e174cSsthen int32_t t, r = 15 * 24 * 3600; /* 15 days max */ 12965d76a658Ssthen for(i=dd->count; i<dd->count+dd->rrsig_count; i++) { 12975d76a658Ssthen t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]); 1298229e174cSsthen if((int32_t)t - (int32_t)*env->now > 0) { 12995d76a658Ssthen t -= (int32_t)*env->now; 1300933707f3Ssthen if(t < r) 1301933707f3Ssthen r = t; 1302933707f3Ssthen } 1303933707f3Ssthen } 1304229e174cSsthen return (time_t)r; 1305933707f3Ssthen } 1306933707f3Ssthen 1307933707f3Ssthen /** Is rr self-signed revoked key */ 1308933707f3Ssthen static int 1309933707f3Ssthen rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, 1310bdfc4d55Sflorian struct ub_packed_rrset_key* dnskey_rrset, size_t i, 1311bdfc4d55Sflorian struct module_qstate* qstate) 1312933707f3Ssthen { 1313933707f3Ssthen enum sec_status sec; 1314933707f3Ssthen char* reason = NULL; 1315933707f3Ssthen verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", 1316933707f3Ssthen (int)i); 1317933707f3Ssthen /* no algorithm downgrade protection necessary, if it is selfsigned 1318933707f3Ssthen * revoked it can be removed. */ 1319933707f3Ssthen sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, 13200bdb4f62Ssthen &reason, NULL, LDNS_SECTION_ANSWER, qstate); 1321933707f3Ssthen return (sec == sec_status_secure); 1322933707f3Ssthen } 1323933707f3Ssthen 1324933707f3Ssthen /** Set fetched value */ 1325933707f3Ssthen static void 1326933707f3Ssthen seen_trustanchor(struct autr_ta* ta, uint8_t seen) 1327933707f3Ssthen { 1328933707f3Ssthen ta->fetched = seen; 1329933707f3Ssthen if(ta->pending_count < 250) /* no numerical overflow, please */ 1330933707f3Ssthen ta->pending_count++; 1331933707f3Ssthen } 1332933707f3Ssthen 1333933707f3Ssthen /** set revoked value */ 1334933707f3Ssthen static void 1335933707f3Ssthen seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked) 1336933707f3Ssthen { 1337933707f3Ssthen ta->revoked = revoked; 1338933707f3Ssthen } 1339933707f3Ssthen 1340933707f3Ssthen /** revoke a trust anchor */ 1341933707f3Ssthen static void 1342933707f3Ssthen revoke_dnskey(struct autr_ta* ta, int off) 1343933707f3Ssthen { 1344933707f3Ssthen uint16_t flags; 13455d76a658Ssthen uint8_t* data; 13465d76a658Ssthen if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) != 13475d76a658Ssthen LDNS_RR_TYPE_DNSKEY) 1348933707f3Ssthen return; 13495d76a658Ssthen if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2) 13505d76a658Ssthen return; 13515d76a658Ssthen data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len); 13525d76a658Ssthen flags = sldns_read_uint16(data); 1353933707f3Ssthen if (off && (flags&LDNS_KEY_REVOKE_KEY)) 1354933707f3Ssthen flags ^= LDNS_KEY_REVOKE_KEY; /* flip */ 1355933707f3Ssthen else 1356933707f3Ssthen flags |= LDNS_KEY_REVOKE_KEY; 13575d76a658Ssthen sldns_write_uint16(data, flags); 1358933707f3Ssthen } 1359933707f3Ssthen 13605d76a658Ssthen /** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */ 1361933707f3Ssthen static int 13625d76a658Ssthen dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len) 1363933707f3Ssthen { 13645d76a658Ssthen size_t i; 13655d76a658Ssthen if(a_len != b_len) 13665d76a658Ssthen return -1; 1367933707f3Ssthen /* compare RRs RDATA byte for byte. */ 13685d76a658Ssthen for(i = 0; i < a_len; i++) 1369933707f3Ssthen { 13705d76a658Ssthen uint8_t rdf1, rdf2; 13715d76a658Ssthen rdf1 = a[i]; 13725d76a658Ssthen rdf2 = b[i]; 13735d76a658Ssthen if(i==1) { 1374933707f3Ssthen /* this is the second part of the flags field */ 13755d76a658Ssthen rdf1 |= LDNS_KEY_REVOKE_KEY; 13765d76a658Ssthen rdf2 |= LDNS_KEY_REVOKE_KEY; 1377933707f3Ssthen } 13785d76a658Ssthen if (rdf1 < rdf2) return -1; 13795d76a658Ssthen else if (rdf1 > rdf2) return 1; 1380933707f3Ssthen } 1381933707f3Ssthen return 0; 1382933707f3Ssthen } 1383933707f3Ssthen 13845d76a658Ssthen 13855d76a658Ssthen /** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */ 1386933707f3Ssthen static int 13875d76a658Ssthen ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len) 1388933707f3Ssthen { 13895d76a658Ssthen if(!a) return -1; 13905d76a658Ssthen else if(!b) return -1; 13915d76a658Ssthen else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t) 13925d76a658Ssthen return (int)sldns_wirerr_get_type(a->rr, a->rr_len, 13935d76a658Ssthen a->dname_len) - (int)t; 13945d76a658Ssthen else if(t == LDNS_RR_TYPE_DNSKEY) { 13955d76a658Ssthen return dnskey_compare_skip_revbit( 13965d76a658Ssthen sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len), 13975d76a658Ssthen sldns_wirerr_get_rdatalen(a->rr, a->rr_len, 13985d76a658Ssthen a->dname_len), b, b_len); 1399933707f3Ssthen } 14005d76a658Ssthen else if(t == LDNS_RR_TYPE_DS) { 14015d76a658Ssthen if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) != 14025d76a658Ssthen b_len) 14035d76a658Ssthen return -1; 14045d76a658Ssthen return memcmp(sldns_wirerr_get_rdata(a->rr, 14055d76a658Ssthen a->rr_len, a->dname_len), b, b_len); 1406933707f3Ssthen } 14075d76a658Ssthen return -1; 1408933707f3Ssthen } 1409933707f3Ssthen 1410933707f3Ssthen /** 1411933707f3Ssthen * Find key 1412933707f3Ssthen * @param tp: to search in 14135d76a658Ssthen * @param t: rr type of the rdata. 14145d76a658Ssthen * @param rdata: to look for (no rdatalen in it) 14155d76a658Ssthen * @param rdata_len: length of rdata 1416933707f3Ssthen * @param result: returns NULL or the ta key looked for. 1417933707f3Ssthen * @return false on malloc failure during search. if true examine result. 1418933707f3Ssthen */ 1419933707f3Ssthen static int 14205d76a658Ssthen find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len, 14215d76a658Ssthen struct autr_ta** result) 1422933707f3Ssthen { 1423933707f3Ssthen struct autr_ta* ta; 14245d76a658Ssthen if(!tp || !rdata) { 14255d76a658Ssthen *result = NULL; 1426933707f3Ssthen return 0; 14275d76a658Ssthen } 1428933707f3Ssthen for(ta=tp->autr->keys; ta; ta=ta->next) { 14295d76a658Ssthen if(ta_compare(ta, t, rdata, rdata_len) == 0) { 1430933707f3Ssthen *result = ta; 1431933707f3Ssthen return 1; 1432933707f3Ssthen } 1433933707f3Ssthen } 1434933707f3Ssthen *result = NULL; 1435933707f3Ssthen return 1; 1436933707f3Ssthen } 1437933707f3Ssthen 14385d76a658Ssthen /** add key and clone RR and tp already locked. rdata without rdlen. */ 1439933707f3Ssthen static struct autr_ta* 14405d76a658Ssthen add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len) 1441933707f3Ssthen { 1442933707f3Ssthen struct autr_ta* ta; 14435d76a658Ssthen uint8_t* rr; 14445d76a658Ssthen size_t rr_len, dname_len; 14455d76a658Ssthen uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY); 14465d76a658Ssthen uint16_t rrclass = htons(LDNS_RR_CLASS_IN); 14475d76a658Ssthen uint16_t rdlen = htons(rdata_len); 14485d76a658Ssthen dname_len = tp->namelen; 14495d76a658Ssthen ttl = htonl(ttl); 14505d76a658Ssthen rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len; 14515d76a658Ssthen rr = (uint8_t*)malloc(rr_len); 14525d76a658Ssthen if(!rr) return NULL; 14535d76a658Ssthen memmove(rr, tp->name, tp->namelen); 14545d76a658Ssthen memmove(rr+dname_len, &rrtype, 2); 14555d76a658Ssthen memmove(rr+dname_len+2, &rrclass, 2); 14565d76a658Ssthen memmove(rr+dname_len+4, &ttl, 4); 14575d76a658Ssthen memmove(rr+dname_len+8, &rdlen, 2); 14585d76a658Ssthen memmove(rr+dname_len+10, rdata, rdata_len); 14595d76a658Ssthen ta = autr_ta_create(rr, rr_len, dname_len); 1460933707f3Ssthen if(!ta) { 14615d76a658Ssthen /* rr freed in autr_ta_create */ 1462933707f3Ssthen return NULL; 1463933707f3Ssthen } 1464933707f3Ssthen /* link in, tp already locked */ 1465933707f3Ssthen ta->next = tp->autr->keys; 1466933707f3Ssthen tp->autr->keys = ta; 1467933707f3Ssthen return ta; 1468933707f3Ssthen } 1469933707f3Ssthen 1470933707f3Ssthen /** get TTL from DNSKEY rrset */ 1471229e174cSsthen static time_t 1472933707f3Ssthen key_ttl(struct ub_packed_rrset_key* k) 1473933707f3Ssthen { 1474933707f3Ssthen struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1475933707f3Ssthen return d->ttl; 1476933707f3Ssthen } 1477933707f3Ssthen 1478933707f3Ssthen /** update the time values for the trustpoint */ 1479933707f3Ssthen static void 1480229e174cSsthen set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, 1481229e174cSsthen time_t origttl, int* changed) 1482933707f3Ssthen { 1483229e174cSsthen time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; 1484933707f3Ssthen 1485933707f3Ssthen /* x = MIN(15days, ttl/2, expire/2) */ 1486933707f3Ssthen x = 15 * 24 * 3600; 1487933707f3Ssthen if(origttl/2 < x) 1488933707f3Ssthen x = origttl/2; 1489933707f3Ssthen if(rrsig_exp_interval/2 < x) 1490933707f3Ssthen x = rrsig_exp_interval/2; 1491933707f3Ssthen /* MAX(1hr, x) */ 1492a961b961Ssthen if(!autr_permit_small_holddown) { 1493933707f3Ssthen if(x < 3600) 1494933707f3Ssthen tp->autr->query_interval = 3600; 1495933707f3Ssthen else tp->autr->query_interval = x; 1496a961b961Ssthen } else tp->autr->query_interval = x; 1497933707f3Ssthen 1498933707f3Ssthen /* x= MIN(1day, ttl/10, expire/10) */ 1499933707f3Ssthen x = 24 * 3600; 1500933707f3Ssthen if(origttl/10 < x) 1501933707f3Ssthen x = origttl/10; 1502933707f3Ssthen if(rrsig_exp_interval/10 < x) 1503933707f3Ssthen x = rrsig_exp_interval/10; 1504933707f3Ssthen /* MAX(1hr, x) */ 1505a961b961Ssthen if(!autr_permit_small_holddown) { 1506933707f3Ssthen if(x < 3600) 1507933707f3Ssthen tp->autr->retry_time = 3600; 1508933707f3Ssthen else tp->autr->retry_time = x; 1509a961b961Ssthen } else tp->autr->retry_time = x; 1510933707f3Ssthen 1511933707f3Ssthen if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { 1512933707f3Ssthen *changed = 1; 1513933707f3Ssthen verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl); 1514933707f3Ssthen verbose(VERB_ALGO, "rrsig_exp_interval is %d", 1515933707f3Ssthen (int)rrsig_exp_interval); 1516933707f3Ssthen verbose(VERB_ALGO, "query_interval: %d, retry_time: %d", 1517933707f3Ssthen (int)tp->autr->query_interval, 1518933707f3Ssthen (int)tp->autr->retry_time); 1519933707f3Ssthen } 1520933707f3Ssthen } 1521933707f3Ssthen 1522933707f3Ssthen /** init events to zero */ 1523933707f3Ssthen static void 1524933707f3Ssthen init_events(struct trust_anchor* tp) 1525933707f3Ssthen { 1526933707f3Ssthen struct autr_ta* ta; 1527933707f3Ssthen for(ta=tp->autr->keys; ta; ta=ta->next) { 1528933707f3Ssthen ta->fetched = 0; 1529933707f3Ssthen } 1530933707f3Ssthen } 1531933707f3Ssthen 1532933707f3Ssthen /** check for revoked keys without trusting any other information */ 1533933707f3Ssthen static void 1534933707f3Ssthen check_contains_revoked(struct module_env* env, struct val_env* ve, 1535933707f3Ssthen struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1536bdfc4d55Sflorian int* changed, struct module_qstate* qstate) 1537933707f3Ssthen { 15385d76a658Ssthen struct packed_rrset_data* dd = (struct packed_rrset_data*) 15395d76a658Ssthen dnskey_rrset->entry.data; 1540933707f3Ssthen size_t i; 15415d76a658Ssthen log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); 15425d76a658Ssthen for(i=0; i<dd->count; i++) { 1543933707f3Ssthen struct autr_ta* ta = NULL; 15445d76a658Ssthen if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), 15455d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2) || 15465d76a658Ssthen !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), 15475d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2)) 1548933707f3Ssthen continue; /* not a revoked KSK */ 15495d76a658Ssthen if(!find_key(tp, ntohs(dnskey_rrset->rk.type), 15505d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { 1551933707f3Ssthen log_err("malloc failure"); 1552933707f3Ssthen continue; /* malloc fail in compare*/ 1553933707f3Ssthen } 1554933707f3Ssthen if(!ta) 1555933707f3Ssthen continue; /* key not found */ 1556bdfc4d55Sflorian if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) { 1557933707f3Ssthen /* checked if there is an rrsig signed by this key. */ 15585d76a658Ssthen /* same keytag, but stored can be revoked already, so 15595d76a658Ssthen * compare keytags, with +0 or +128(REVOKE flag) */ 15605d76a658Ssthen log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 == 15615d76a658Ssthen sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 15625d76a658Ssthen ta->rr, ta->rr_len, ta->dname_len), 15635d76a658Ssthen sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 15645d76a658Ssthen ta->dname_len)) || 15655d76a658Ssthen dnskey_calc_keytag(dnskey_rrset, i) == 15665d76a658Ssthen sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 15675d76a658Ssthen ta->rr, ta->rr_len, ta->dname_len), 15685d76a658Ssthen sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 15695d76a658Ssthen ta->dname_len))); /* checks conversion*/ 1570933707f3Ssthen verbose_key(ta, VERB_ALGO, "is self-signed revoked"); 1571933707f3Ssthen if(!ta->revoked) 1572933707f3Ssthen *changed = 1; 1573933707f3Ssthen seen_revoked_trustanchor(ta, 1); 1574933707f3Ssthen do_revoked(env, ta, changed); 1575933707f3Ssthen } 1576933707f3Ssthen } 1577933707f3Ssthen } 1578933707f3Ssthen 1579933707f3Ssthen /** See if a DNSKEY is verified by one of the DSes */ 1580933707f3Ssthen static int 1581933707f3Ssthen key_matches_a_ds(struct module_env* env, struct val_env* ve, 1582933707f3Ssthen struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx, 1583933707f3Ssthen struct ub_packed_rrset_key* ds_rrset) 1584933707f3Ssthen { 1585933707f3Ssthen struct packed_rrset_data* dd = (struct packed_rrset_data*) 1586933707f3Ssthen ds_rrset->entry.data; 1587933707f3Ssthen size_t ds_idx, num = dd->count; 1588933707f3Ssthen int d = val_favorite_ds_algo(ds_rrset); 1589933707f3Ssthen char* reason = ""; 1590933707f3Ssthen for(ds_idx=0; ds_idx<num; ds_idx++) { 1591933707f3Ssthen if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) || 1592933707f3Ssthen !ds_key_algo_is_supported(ds_rrset, ds_idx) || 1593191f22c6Ssthen !dnskey_size_is_supported(dnskey_rrset, key_idx) || 1594933707f3Ssthen ds_get_digest_algo(ds_rrset, ds_idx) != d) 1595933707f3Ssthen continue; 1596933707f3Ssthen if(ds_get_key_algo(ds_rrset, ds_idx) 1597933707f3Ssthen != dnskey_get_algo(dnskey_rrset, key_idx) 1598933707f3Ssthen || dnskey_calc_keytag(dnskey_rrset, key_idx) 1599933707f3Ssthen != ds_get_keytag(ds_rrset, ds_idx)) { 1600933707f3Ssthen continue; 1601933707f3Ssthen } 1602933707f3Ssthen if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx, 1603933707f3Ssthen ds_rrset, ds_idx)) { 1604933707f3Ssthen verbose(VERB_ALGO, "DS match attempt failed"); 1605933707f3Ssthen continue; 1606933707f3Ssthen } 160774775603Ssthen /* match of hash is sufficient for bootstrap of trust point */ 160874775603Ssthen (void)reason; 160974775603Ssthen (void)ve; 161074775603Ssthen return 1; 161174775603Ssthen /* no need to check RRSIG, DS hash already matched with source 1612933707f3Ssthen if(dnskey_verify_rrset(env, ve, dnskey_rrset, 1613933707f3Ssthen dnskey_rrset, key_idx, &reason) == sec_status_secure) { 1614933707f3Ssthen return 1; 1615933707f3Ssthen } else { 1616933707f3Ssthen verbose(VERB_ALGO, "DS match failed because the key " 1617933707f3Ssthen "does not verify the keyset: %s", reason); 1618933707f3Ssthen } 161974775603Ssthen */ 1620933707f3Ssthen } 1621933707f3Ssthen return 0; 1622933707f3Ssthen } 1623933707f3Ssthen 1624933707f3Ssthen /** Set update events */ 1625933707f3Ssthen static int 1626933707f3Ssthen update_events(struct module_env* env, struct val_env* ve, 1627933707f3Ssthen struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1628933707f3Ssthen int* changed) 1629933707f3Ssthen { 16305d76a658Ssthen struct packed_rrset_data* dd = (struct packed_rrset_data*) 16315d76a658Ssthen dnskey_rrset->entry.data; 1632933707f3Ssthen size_t i; 16335d76a658Ssthen log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); 1634933707f3Ssthen init_events(tp); 16355d76a658Ssthen for(i=0; i<dd->count; i++) { 1636933707f3Ssthen struct autr_ta* ta = NULL; 16375d76a658Ssthen if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), 16385d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2)) 1639933707f3Ssthen continue; 16405d76a658Ssthen if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), 16415d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2)) { 1642933707f3Ssthen /* self-signed revoked keys already detected before, 1643933707f3Ssthen * other revoked keys are not 'added' again */ 1644933707f3Ssthen continue; 1645933707f3Ssthen } 1646933707f3Ssthen /* is a key of this type supported?. Note rr_list and 1647933707f3Ssthen * packed_rrset are in the same order. */ 1648191f22c6Ssthen if(!dnskey_algo_is_supported(dnskey_rrset, i) || 1649191f22c6Ssthen !dnskey_size_is_supported(dnskey_rrset, i)) { 1650933707f3Ssthen /* skip unknown algorithm key, it is useless to us */ 1651933707f3Ssthen log_nametypeclass(VERB_DETAIL, "trust point has " 1652933707f3Ssthen "unsupported algorithm at", 1653933707f3Ssthen tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 1654933707f3Ssthen continue; 1655933707f3Ssthen } 1656933707f3Ssthen 1657933707f3Ssthen /* is it new? if revocation bit set, find the unrevoked key */ 16585d76a658Ssthen if(!find_key(tp, ntohs(dnskey_rrset->rk.type), 16595d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { 1660933707f3Ssthen return 0; 1661933707f3Ssthen } 1662933707f3Ssthen if(!ta) { 16635d76a658Ssthen ta = add_key(tp, (uint32_t)dd->rr_ttl[i], 16645d76a658Ssthen dd->rr_data[i]+2, dd->rr_len[i]-2); 1665933707f3Ssthen *changed = 1; 1666933707f3Ssthen /* first time seen, do we have DSes? if match: VALID */ 1667933707f3Ssthen if(ta && tp->ds_rrset && key_matches_a_ds(env, ve, 1668933707f3Ssthen dnskey_rrset, i, tp->ds_rrset)) { 1669933707f3Ssthen verbose_key(ta, VERB_ALGO, "verified by DS"); 1670933707f3Ssthen ta->s = AUTR_STATE_VALID; 1671933707f3Ssthen } 1672933707f3Ssthen } 1673933707f3Ssthen if(!ta) { 1674933707f3Ssthen return 0; 1675933707f3Ssthen } 1676933707f3Ssthen seen_trustanchor(ta, 1); 1677933707f3Ssthen verbose_key(ta, VERB_ALGO, "in DNS response"); 1678933707f3Ssthen } 16795d76a658Ssthen set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed); 1680933707f3Ssthen return 1; 1681933707f3Ssthen } 1682933707f3Ssthen 1683933707f3Ssthen /** 1684933707f3Ssthen * Check if the holddown time has already exceeded 1685933707f3Ssthen * setting: add-holddown: add holddown timer 1686933707f3Ssthen * setting: del-holddown: del holddown timer 1687933707f3Ssthen * @param env: environment with current time 1688933707f3Ssthen * @param ta: trust anchor to check for. 1689933707f3Ssthen * @param holddown: the timer value 1690933707f3Ssthen * @return number of seconds the holddown has passed. 1691933707f3Ssthen */ 1692229e174cSsthen static time_t 1693933707f3Ssthen check_holddown(struct module_env* env, struct autr_ta* ta, 1694933707f3Ssthen unsigned int holddown) 1695933707f3Ssthen { 1696229e174cSsthen time_t elapsed; 1697229e174cSsthen if(*env->now < ta->last_change) { 1698933707f3Ssthen log_warn("time goes backwards. delaying key holddown"); 1699933707f3Ssthen return 0; 1700933707f3Ssthen } 1701229e174cSsthen elapsed = *env->now - ta->last_change; 1702229e174cSsthen if (elapsed > (time_t)holddown) { 1703229e174cSsthen return elapsed-(time_t)holddown; 1704933707f3Ssthen } 17055d76a658Ssthen verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go", 1706229e174cSsthen (long long) ((time_t)holddown-elapsed)); 1707933707f3Ssthen return 0; 1708933707f3Ssthen } 1709933707f3Ssthen 1710933707f3Ssthen 1711933707f3Ssthen /** Set last_change to now */ 1712933707f3Ssthen static void 1713933707f3Ssthen reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed) 1714933707f3Ssthen { 1715933707f3Ssthen ta->last_change = *env->now; 1716933707f3Ssthen *changed = 1; 1717933707f3Ssthen } 1718933707f3Ssthen 1719933707f3Ssthen /** Set the state for this trust anchor */ 1720933707f3Ssthen static void 1721933707f3Ssthen set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed, 172277079be7Ssthen autr_state_type s) 1723933707f3Ssthen { 1724933707f3Ssthen verbose_key(ta, VERB_ALGO, "update: %s to %s", 1725933707f3Ssthen trustanchor_state2str(ta->s), trustanchor_state2str(s)); 1726933707f3Ssthen ta->s = s; 1727933707f3Ssthen reset_holddown(env, ta, changed); 1728933707f3Ssthen } 1729933707f3Ssthen 1730933707f3Ssthen 1731933707f3Ssthen /** Event: NewKey */ 1732933707f3Ssthen static void 1733933707f3Ssthen do_newkey(struct module_env* env, struct autr_ta* anchor, int* c) 1734933707f3Ssthen { 1735933707f3Ssthen if (anchor->s == AUTR_STATE_START) 1736933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND); 1737933707f3Ssthen } 1738933707f3Ssthen 1739933707f3Ssthen /** Event: AddTime */ 1740933707f3Ssthen static void 1741933707f3Ssthen do_addtime(struct module_env* env, struct autr_ta* anchor, int* c) 1742933707f3Ssthen { 1743933707f3Ssthen /* This not according to RFC, this is 30 days, but the RFC demands 1744933707f3Ssthen * MAX(30days, TTL expire time of first DNSKEY set with this key), 1745933707f3Ssthen * The value may be too small if a very large TTL was used. */ 1746229e174cSsthen time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown); 1747933707f3Ssthen if (exceeded && anchor->s == AUTR_STATE_ADDPEND) { 1748933707f3Ssthen verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded " 17495d76a658Ssthen ARG_LL "d seconds ago, and pending-count %d", 1750229e174cSsthen (long long)exceeded, anchor->pending_count); 1751933707f3Ssthen if(anchor->pending_count >= MIN_PENDINGCOUNT) { 1752933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1753933707f3Ssthen anchor->pending_count = 0; 1754933707f3Ssthen return; 1755933707f3Ssthen } 1756933707f3Ssthen verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check " 1757933707f3Ssthen "failed (pending count: %d)", anchor->pending_count); 1758933707f3Ssthen } 1759933707f3Ssthen } 1760933707f3Ssthen 1761933707f3Ssthen /** Event: RemTime */ 1762933707f3Ssthen static void 1763933707f3Ssthen do_remtime(struct module_env* env, struct autr_ta* anchor, int* c) 1764933707f3Ssthen { 1765229e174cSsthen time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown); 1766933707f3Ssthen if(exceeded && anchor->s == AUTR_STATE_REVOKED) { 1767933707f3Ssthen verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded " 17685d76a658Ssthen ARG_LL "d seconds ago", (long long)exceeded); 1769933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED); 1770933707f3Ssthen } 1771933707f3Ssthen } 1772933707f3Ssthen 1773933707f3Ssthen /** Event: KeyRem */ 1774933707f3Ssthen static void 1775933707f3Ssthen do_keyrem(struct module_env* env, struct autr_ta* anchor, int* c) 1776933707f3Ssthen { 1777933707f3Ssthen if(anchor->s == AUTR_STATE_ADDPEND) { 1778933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_START); 1779933707f3Ssthen anchor->pending_count = 0; 1780933707f3Ssthen } else if(anchor->s == AUTR_STATE_VALID) 1781933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING); 1782933707f3Ssthen } 1783933707f3Ssthen 1784933707f3Ssthen /** Event: KeyPres */ 1785933707f3Ssthen static void 1786933707f3Ssthen do_keypres(struct module_env* env, struct autr_ta* anchor, int* c) 1787933707f3Ssthen { 1788933707f3Ssthen if(anchor->s == AUTR_STATE_MISSING) 1789933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1790933707f3Ssthen } 1791933707f3Ssthen 1792933707f3Ssthen /* Event: Revoked */ 1793933707f3Ssthen static void 1794933707f3Ssthen do_revoked(struct module_env* env, struct autr_ta* anchor, int* c) 1795933707f3Ssthen { 1796933707f3Ssthen if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) { 1797933707f3Ssthen set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED); 1798933707f3Ssthen verbose_key(anchor, VERB_ALGO, "old id, prior to revocation"); 1799933707f3Ssthen revoke_dnskey(anchor, 0); 1800933707f3Ssthen verbose_key(anchor, VERB_ALGO, "new id, after revocation"); 1801933707f3Ssthen } 1802933707f3Ssthen } 1803933707f3Ssthen 1804933707f3Ssthen /** Do statestable transition matrix for anchor */ 1805933707f3Ssthen static void 1806933707f3Ssthen anchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c) 1807933707f3Ssthen { 1808933707f3Ssthen log_assert(anchor); 1809933707f3Ssthen switch(anchor->s) { 1810933707f3Ssthen /* START */ 1811933707f3Ssthen case AUTR_STATE_START: 1812933707f3Ssthen /* NewKey: ADDPEND */ 1813933707f3Ssthen if (anchor->fetched) 1814933707f3Ssthen do_newkey(env, anchor, c); 1815933707f3Ssthen break; 1816933707f3Ssthen /* ADDPEND */ 1817933707f3Ssthen case AUTR_STATE_ADDPEND: 1818933707f3Ssthen /* KeyRem: START */ 1819933707f3Ssthen if (!anchor->fetched) 1820933707f3Ssthen do_keyrem(env, anchor, c); 1821933707f3Ssthen /* AddTime: VALID */ 1822933707f3Ssthen else do_addtime(env, anchor, c); 1823933707f3Ssthen break; 1824933707f3Ssthen /* VALID */ 1825933707f3Ssthen case AUTR_STATE_VALID: 1826933707f3Ssthen /* RevBit: REVOKED */ 1827933707f3Ssthen if (anchor->revoked) 1828933707f3Ssthen do_revoked(env, anchor, c); 1829933707f3Ssthen /* KeyRem: MISSING */ 1830933707f3Ssthen else if (!anchor->fetched) 1831933707f3Ssthen do_keyrem(env, anchor, c); 1832933707f3Ssthen else if(!anchor->last_change) { 1833933707f3Ssthen verbose_key(anchor, VERB_ALGO, "first seen"); 1834933707f3Ssthen reset_holddown(env, anchor, c); 1835933707f3Ssthen } 1836933707f3Ssthen break; 1837933707f3Ssthen /* MISSING */ 1838933707f3Ssthen case AUTR_STATE_MISSING: 1839933707f3Ssthen /* RevBit: REVOKED */ 1840933707f3Ssthen if (anchor->revoked) 1841933707f3Ssthen do_revoked(env, anchor, c); 1842933707f3Ssthen /* KeyPres */ 1843933707f3Ssthen else if (anchor->fetched) 1844933707f3Ssthen do_keypres(env, anchor, c); 1845933707f3Ssthen break; 1846933707f3Ssthen /* REVOKED */ 1847933707f3Ssthen case AUTR_STATE_REVOKED: 1848933707f3Ssthen if (anchor->fetched) 1849933707f3Ssthen reset_holddown(env, anchor, c); 1850933707f3Ssthen /* RemTime: REMOVED */ 1851933707f3Ssthen else do_remtime(env, anchor, c); 1852933707f3Ssthen break; 1853933707f3Ssthen /* REMOVED */ 1854933707f3Ssthen case AUTR_STATE_REMOVED: 1855933707f3Ssthen default: 1856933707f3Ssthen break; 1857933707f3Ssthen } 1858933707f3Ssthen } 1859933707f3Ssthen 1860933707f3Ssthen /** if ZSK init then trust KSKs */ 1861933707f3Ssthen static int 1862933707f3Ssthen init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed) 1863933707f3Ssthen { 1864933707f3Ssthen /* search for VALID ZSKs */ 1865933707f3Ssthen struct autr_ta* anchor; 1866933707f3Ssthen int validzsk = 0; 1867933707f3Ssthen int validksk = 0; 1868933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1869933707f3Ssthen /* last_change test makes sure it was manually configured */ 18705d76a658Ssthen if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len, 18715d76a658Ssthen anchor->dname_len) == LDNS_RR_TYPE_DNSKEY && 1872933707f3Ssthen anchor->last_change == 0 && 18735d76a658Ssthen !ta_is_dnskey_sep(anchor) && 1874933707f3Ssthen anchor->s == AUTR_STATE_VALID) 1875933707f3Ssthen validzsk++; 1876933707f3Ssthen } 1877933707f3Ssthen if(validzsk == 0) 1878933707f3Ssthen return 0; 1879933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 18805d76a658Ssthen if (ta_is_dnskey_sep(anchor) && 1881933707f3Ssthen anchor->s == AUTR_STATE_ADDPEND) { 1882933707f3Ssthen verbose_key(anchor, VERB_ALGO, "trust KSK from " 1883933707f3Ssthen "ZSK(config)"); 1884933707f3Ssthen set_trustanchor_state(env, anchor, changed, 1885933707f3Ssthen AUTR_STATE_VALID); 1886933707f3Ssthen validksk++; 1887933707f3Ssthen } 1888933707f3Ssthen } 1889933707f3Ssthen return validksk; 1890933707f3Ssthen } 1891933707f3Ssthen 1892933707f3Ssthen /** Remove missing trustanchors so the list does not grow forever */ 1893933707f3Ssthen static void 1894933707f3Ssthen remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, 1895933707f3Ssthen int* changed) 1896933707f3Ssthen { 1897933707f3Ssthen struct autr_ta* anchor; 1898229e174cSsthen time_t exceeded; 1899933707f3Ssthen int valid = 0; 1900933707f3Ssthen /* see if we have anchors that are valid */ 1901933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1902933707f3Ssthen /* Only do KSKs */ 19035d76a658Ssthen if (!ta_is_dnskey_sep(anchor)) 1904933707f3Ssthen continue; 1905933707f3Ssthen if (anchor->s == AUTR_STATE_VALID) 1906933707f3Ssthen valid++; 1907933707f3Ssthen } 1908933707f3Ssthen /* if there are no SEP Valid anchors, see if we started out with 1909933707f3Ssthen * a ZSK (last-change=0) anchor, which is VALID and there are KSKs 1910933707f3Ssthen * now that can be made valid. Do this immediately because there 1911933707f3Ssthen * is no guarantee that the ZSKs get announced long enough. Usually 1912933707f3Ssthen * this is immediately after init with a ZSK trusted, unless the domain 1913933707f3Ssthen * was not advertising any KSKs at all. In which case we perfectly 1914933707f3Ssthen * track the zero number of KSKs. */ 1915933707f3Ssthen if(valid == 0) { 1916933707f3Ssthen valid = init_zsk_to_ksk(env, tp, changed); 1917933707f3Ssthen if(valid == 0) 1918933707f3Ssthen return; 1919933707f3Ssthen } 1920933707f3Ssthen 1921933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1922933707f3Ssthen /* ignore ZSKs if newly added */ 1923933707f3Ssthen if(anchor->s == AUTR_STATE_START) 1924933707f3Ssthen continue; 1925933707f3Ssthen /* remove ZSKs if a KSK is present */ 19265d76a658Ssthen if (!ta_is_dnskey_sep(anchor)) { 1927933707f3Ssthen if(valid > 0) { 1928933707f3Ssthen verbose_key(anchor, VERB_ALGO, "remove ZSK " 1929933707f3Ssthen "[%d key(s) VALID]", valid); 1930933707f3Ssthen set_trustanchor_state(env, anchor, changed, 1931933707f3Ssthen AUTR_STATE_REMOVED); 1932933707f3Ssthen } 1933933707f3Ssthen continue; 1934933707f3Ssthen } 1935933707f3Ssthen /* Only do MISSING keys */ 1936933707f3Ssthen if (anchor->s != AUTR_STATE_MISSING) 1937933707f3Ssthen continue; 1938933707f3Ssthen if(env->cfg->keep_missing == 0) 1939933707f3Ssthen continue; /* keep forever */ 1940933707f3Ssthen 1941933707f3Ssthen exceeded = check_holddown(env, anchor, env->cfg->keep_missing); 1942933707f3Ssthen /* If keep_missing has exceeded and we still have more than 1943933707f3Ssthen * one valid KSK: remove missing trust anchor */ 1944933707f3Ssthen if (exceeded && valid > 0) { 1945933707f3Ssthen verbose_key(anchor, VERB_ALGO, "keep-missing time " 19465d76a658Ssthen "exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]", 1947229e174cSsthen (long long)exceeded, valid); 1948933707f3Ssthen set_trustanchor_state(env, anchor, changed, 1949933707f3Ssthen AUTR_STATE_REMOVED); 1950933707f3Ssthen } 1951933707f3Ssthen } 1952933707f3Ssthen } 1953933707f3Ssthen 1954933707f3Ssthen /** Do the statetable from RFC5011 transition matrix */ 1955933707f3Ssthen static int 1956933707f3Ssthen do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed) 1957933707f3Ssthen { 1958933707f3Ssthen struct autr_ta* anchor; 1959933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1960933707f3Ssthen /* Only do KSKs */ 19615d76a658Ssthen if(!ta_is_dnskey_sep(anchor)) 1962933707f3Ssthen continue; 1963933707f3Ssthen anchor_state_update(env, anchor, changed); 1964933707f3Ssthen } 1965933707f3Ssthen remove_missing_trustanchors(env, tp, changed); 1966933707f3Ssthen return 1; 1967933707f3Ssthen } 1968933707f3Ssthen 1969933707f3Ssthen /** See if time alone makes ADDPEND to VALID transition */ 1970933707f3Ssthen static void 1971933707f3Ssthen autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c) 1972933707f3Ssthen { 1973933707f3Ssthen struct autr_ta* anchor; 1974933707f3Ssthen for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 19755d76a658Ssthen if(ta_is_dnskey_sep(anchor) && 1976933707f3Ssthen anchor->s == AUTR_STATE_ADDPEND) 1977933707f3Ssthen do_addtime(env, anchor, c); 1978933707f3Ssthen } 1979933707f3Ssthen } 1980933707f3Ssthen 1981933707f3Ssthen /** cleanup key list */ 1982933707f3Ssthen static void 1983933707f3Ssthen autr_cleanup_keys(struct trust_anchor* tp) 1984933707f3Ssthen { 1985933707f3Ssthen struct autr_ta* p, **prevp; 1986933707f3Ssthen prevp = &tp->autr->keys; 1987933707f3Ssthen p = tp->autr->keys; 1988933707f3Ssthen while(p) { 1989933707f3Ssthen /* do we want to remove this key? */ 1990933707f3Ssthen if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED || 19915d76a658Ssthen sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len) 19925d76a658Ssthen != LDNS_RR_TYPE_DNSKEY) { 1993933707f3Ssthen struct autr_ta* np = p->next; 1994933707f3Ssthen /* remove */ 19955d76a658Ssthen free(p->rr); 1996933707f3Ssthen free(p); 1997933707f3Ssthen /* snip and go to next item */ 1998933707f3Ssthen *prevp = np; 1999933707f3Ssthen p = np; 2000933707f3Ssthen continue; 2001933707f3Ssthen } 2002933707f3Ssthen /* remove pending counts if no longer pending */ 2003933707f3Ssthen if(p->s != AUTR_STATE_ADDPEND) 2004933707f3Ssthen p->pending_count = 0; 2005933707f3Ssthen prevp = &p->next; 2006933707f3Ssthen p = p->next; 2007933707f3Ssthen } 2008933707f3Ssthen } 2009933707f3Ssthen 2010933707f3Ssthen /** calculate next probe time */ 2011933707f3Ssthen static time_t 2012229e174cSsthen calc_next_probe(struct module_env* env, time_t wait) 2013933707f3Ssthen { 2014933707f3Ssthen /* make it random, 90-100% */ 2015229e174cSsthen time_t rnd, rest; 2016a961b961Ssthen if(!autr_permit_small_holddown) { 2017933707f3Ssthen if(wait < 3600) 2018933707f3Ssthen wait = 3600; 2019a961b961Ssthen } else { 2020a961b961Ssthen if(wait == 0) wait = 1; 2021a961b961Ssthen } 2022933707f3Ssthen rnd = wait/10; 2023933707f3Ssthen rest = wait-rnd; 2024229e174cSsthen rnd = (time_t)ub_random_max(env->rnd, (long int)rnd); 2025933707f3Ssthen return (time_t)(*env->now + rest + rnd); 2026933707f3Ssthen } 2027933707f3Ssthen 2028933707f3Ssthen /** what is first probe time (anchors must be locked) */ 2029933707f3Ssthen static time_t 2030933707f3Ssthen wait_probe_time(struct val_anchors* anchors) 2031933707f3Ssthen { 203277079be7Ssthen rbnode_type* t = rbtree_first(&anchors->autr->probe); 2033933707f3Ssthen if(t != RBTREE_NULL) 2034933707f3Ssthen return ((struct trust_anchor*)t->key)->autr->next_probe_time; 2035933707f3Ssthen return 0; 2036933707f3Ssthen } 2037933707f3Ssthen 2038933707f3Ssthen /** reset worker timer */ 2039933707f3Ssthen static void 2040933707f3Ssthen reset_worker_timer(struct module_env* env) 2041933707f3Ssthen { 2042933707f3Ssthen struct timeval tv; 2043933707f3Ssthen #ifndef S_SPLINT_S 2044229e174cSsthen time_t next = (time_t)wait_probe_time(env->anchors); 2045933707f3Ssthen /* in case this is libunbound, no timer */ 2046933707f3Ssthen if(!env->probe_timer) 2047933707f3Ssthen return; 2048933707f3Ssthen if(next > *env->now) 2049933707f3Ssthen tv.tv_sec = (time_t)(next - *env->now); 2050933707f3Ssthen else tv.tv_sec = 0; 2051933707f3Ssthen #endif 2052933707f3Ssthen tv.tv_usec = 0; 2053933707f3Ssthen comm_timer_set(env->probe_timer, &tv); 20545d76a658Ssthen verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec); 2055933707f3Ssthen } 2056933707f3Ssthen 2057933707f3Ssthen /** set next probe for trust anchor */ 2058933707f3Ssthen static int 2059933707f3Ssthen set_next_probe(struct module_env* env, struct trust_anchor* tp, 2060933707f3Ssthen struct ub_packed_rrset_key* dnskey_rrset) 2061933707f3Ssthen { 2062933707f3Ssthen struct trust_anchor key, *tp2; 2063933707f3Ssthen time_t mold, mnew; 2064933707f3Ssthen /* use memory allocated in rrset for temporary name storage */ 2065933707f3Ssthen key.node.key = &key; 2066933707f3Ssthen key.name = dnskey_rrset->rk.dname; 2067933707f3Ssthen key.namelen = dnskey_rrset->rk.dname_len; 2068933707f3Ssthen key.namelabs = dname_count_labels(key.name); 2069933707f3Ssthen key.dclass = tp->dclass; 2070933707f3Ssthen lock_basic_unlock(&tp->lock); 2071933707f3Ssthen 2072933707f3Ssthen /* fetch tp again and lock anchors, so that we can modify the trees */ 2073933707f3Ssthen lock_basic_lock(&env->anchors->lock); 2074933707f3Ssthen tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key); 2075933707f3Ssthen if(!tp2) { 2076933707f3Ssthen verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe"); 2077933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2078933707f3Ssthen return 0; 2079933707f3Ssthen } 2080933707f3Ssthen log_assert(tp == tp2); 2081933707f3Ssthen lock_basic_lock(&tp->lock); 2082933707f3Ssthen 2083933707f3Ssthen /* schedule */ 2084933707f3Ssthen mold = wait_probe_time(env->anchors); 2085933707f3Ssthen (void)rbtree_delete(&env->anchors->autr->probe, tp); 2086933707f3Ssthen tp->autr->next_probe_time = calc_next_probe(env, 2087933707f3Ssthen tp->autr->query_interval); 2088933707f3Ssthen (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 2089933707f3Ssthen mnew = wait_probe_time(env->anchors); 2090933707f3Ssthen 2091933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2092933707f3Ssthen verbose(VERB_ALGO, "next probe set in %d seconds", 2093933707f3Ssthen (int)tp->autr->next_probe_time - (int)*env->now); 2094933707f3Ssthen if(mold != mnew) { 2095933707f3Ssthen reset_worker_timer(env); 2096933707f3Ssthen } 2097933707f3Ssthen return 1; 2098933707f3Ssthen } 2099933707f3Ssthen 2100933707f3Ssthen /** Revoke and Delete a trust point */ 2101933707f3Ssthen static void 2102933707f3Ssthen autr_tp_remove(struct module_env* env, struct trust_anchor* tp, 2103933707f3Ssthen struct ub_packed_rrset_key* dnskey_rrset) 2104933707f3Ssthen { 21053dcb24b8Ssthen struct trust_anchor* del_tp; 2106933707f3Ssthen struct trust_anchor key; 2107933707f3Ssthen struct autr_point_data pd; 2108933707f3Ssthen time_t mold, mnew; 2109933707f3Ssthen 2110933707f3Ssthen log_nametypeclass(VERB_OPS, "trust point was revoked", 2111933707f3Ssthen tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 2112933707f3Ssthen tp->autr->revoked = 1; 2113933707f3Ssthen 2114933707f3Ssthen /* use space allocated for dnskey_rrset to save name of anchor */ 2115933707f3Ssthen memset(&key, 0, sizeof(key)); 2116933707f3Ssthen memset(&pd, 0, sizeof(pd)); 2117933707f3Ssthen key.autr = &pd; 2118933707f3Ssthen key.node.key = &key; 2119933707f3Ssthen pd.pnode.key = &key; 2120933707f3Ssthen pd.next_probe_time = tp->autr->next_probe_time; 2121933707f3Ssthen key.name = dnskey_rrset->rk.dname; 2122933707f3Ssthen key.namelen = tp->namelen; 2123933707f3Ssthen key.namelabs = tp->namelabs; 2124933707f3Ssthen key.dclass = tp->dclass; 2125933707f3Ssthen 2126933707f3Ssthen /* unlock */ 2127933707f3Ssthen lock_basic_unlock(&tp->lock); 2128933707f3Ssthen 2129933707f3Ssthen /* take from tree. It could be deleted by someone else,hence (void). */ 2130933707f3Ssthen lock_basic_lock(&env->anchors->lock); 21313dcb24b8Ssthen del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key); 2132933707f3Ssthen mold = wait_probe_time(env->anchors); 2133933707f3Ssthen (void)rbtree_delete(&env->anchors->autr->probe, &key); 2134933707f3Ssthen mnew = wait_probe_time(env->anchors); 2135933707f3Ssthen anchors_init_parents_locked(env->anchors); 2136933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2137933707f3Ssthen 21383dcb24b8Ssthen /* if !del_tp then the trust point is no longer present in the tree, 21393dcb24b8Ssthen * it was deleted by someone else, who will write the zonefile and 21403dcb24b8Ssthen * clean up the structure */ 21413dcb24b8Ssthen if(del_tp) { 2142933707f3Ssthen /* save on disk */ 21433dcb24b8Ssthen del_tp->autr->next_probe_time = 0; /* no more probing for it */ 21443dcb24b8Ssthen autr_write_file(env, del_tp); 2145933707f3Ssthen 2146933707f3Ssthen /* delete */ 21473dcb24b8Ssthen autr_point_delete(del_tp); 21483dcb24b8Ssthen } 2149933707f3Ssthen if(mold != mnew) { 2150933707f3Ssthen reset_worker_timer(env); 2151933707f3Ssthen } 2152933707f3Ssthen } 2153933707f3Ssthen 2154933707f3Ssthen int autr_process_prime(struct module_env* env, struct val_env* ve, 2155bdfc4d55Sflorian struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 2156bdfc4d55Sflorian struct module_qstate* qstate) 2157933707f3Ssthen { 2158933707f3Ssthen int changed = 0; 2159933707f3Ssthen log_assert(tp && tp->autr); 2160933707f3Ssthen /* autotrust update trust anchors */ 2161933707f3Ssthen /* the tp is locked, and stays locked unless it is deleted */ 2162933707f3Ssthen 2163933707f3Ssthen /* we could just catch the anchor here while another thread 2164933707f3Ssthen * is busy deleting it. Just unlock and let the other do its job */ 2165933707f3Ssthen if(tp->autr->revoked) { 2166933707f3Ssthen log_nametypeclass(VERB_ALGO, "autotrust not processed, " 2167933707f3Ssthen "trust point revoked", tp->name, 2168933707f3Ssthen LDNS_RR_TYPE_DNSKEY, tp->dclass); 2169933707f3Ssthen lock_basic_unlock(&tp->lock); 2170933707f3Ssthen return 0; /* it is revoked */ 2171933707f3Ssthen } 2172933707f3Ssthen 2173933707f3Ssthen /* query_dnskeys(): */ 2174933707f3Ssthen tp->autr->last_queried = *env->now; 2175933707f3Ssthen 2176933707f3Ssthen log_nametypeclass(VERB_ALGO, "autotrust process for", 2177933707f3Ssthen tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 2178933707f3Ssthen /* see if time alone makes some keys valid */ 2179933707f3Ssthen autr_holddown_exceed(env, tp, &changed); 2180933707f3Ssthen if(changed) { 2181933707f3Ssthen verbose(VERB_ALGO, "autotrust: morekeys, reassemble"); 2182933707f3Ssthen if(!autr_assemble(tp)) { 2183933707f3Ssthen log_err("malloc failure assembling autotrust keys"); 2184933707f3Ssthen return 1; /* unchanged */ 2185933707f3Ssthen } 2186933707f3Ssthen } 2187933707f3Ssthen /* did we get any data? */ 2188933707f3Ssthen if(!dnskey_rrset) { 2189933707f3Ssthen verbose(VERB_ALGO, "autotrust: no dnskey rrset"); 2190933707f3Ssthen /* no update of query_failed, because then we would have 2191933707f3Ssthen * to write to disk. But we cannot because we maybe are 2192bdfc4d55Sflorian * still 'initializing' with DS records, that we cannot write 2193933707f3Ssthen * in the full format (which only contains KSKs). */ 2194933707f3Ssthen return 1; /* trust point exists */ 2195933707f3Ssthen } 2196933707f3Ssthen /* check for revoked keys to remove immediately */ 2197bdfc4d55Sflorian check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate); 2198933707f3Ssthen if(changed) { 2199933707f3Ssthen verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); 2200933707f3Ssthen if(!autr_assemble(tp)) { 2201933707f3Ssthen log_err("malloc failure assembling autotrust keys"); 2202933707f3Ssthen return 1; /* unchanged */ 2203933707f3Ssthen } 2204933707f3Ssthen if(!tp->ds_rrset && !tp->dnskey_rrset) { 2205933707f3Ssthen /* no more keys, all are revoked */ 2206933707f3Ssthen /* this is a success for this probe attempt */ 2207933707f3Ssthen tp->autr->last_success = *env->now; 2208933707f3Ssthen autr_tp_remove(env, tp, dnskey_rrset); 2209933707f3Ssthen return 0; /* trust point removed */ 2210933707f3Ssthen } 2211933707f3Ssthen } 2212933707f3Ssthen /* verify the dnskey rrset and see if it is valid. */ 2213bdfc4d55Sflorian if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) { 2214933707f3Ssthen verbose(VERB_ALGO, "autotrust: dnskey did not verify."); 2215933707f3Ssthen /* only increase failure count if this is not the first prime, 22164bfc71b0Ssthen * this means there was a previous successful probe */ 2217933707f3Ssthen if(tp->autr->last_success) { 2218933707f3Ssthen tp->autr->query_failed += 1; 2219933707f3Ssthen autr_write_file(env, tp); 2220933707f3Ssthen } 2221933707f3Ssthen return 1; /* trust point exists */ 2222933707f3Ssthen } 2223933707f3Ssthen 2224933707f3Ssthen tp->autr->last_success = *env->now; 2225933707f3Ssthen tp->autr->query_failed = 0; 2226933707f3Ssthen 2227933707f3Ssthen /* Add new trust anchors to the data structure 2228933707f3Ssthen * - note which trust anchors are seen this probe. 2229933707f3Ssthen * Set trustpoint query_interval and retry_time. 2230933707f3Ssthen * - find minimum rrsig expiration interval 2231933707f3Ssthen */ 2232933707f3Ssthen if(!update_events(env, ve, tp, dnskey_rrset, &changed)) { 2233933707f3Ssthen log_err("malloc failure in autotrust update_events. " 2234933707f3Ssthen "trust point unchanged."); 2235933707f3Ssthen return 1; /* trust point unchanged, so exists */ 2236933707f3Ssthen } 2237933707f3Ssthen 2238933707f3Ssthen /* - for every SEP key do the 5011 statetable. 2239933707f3Ssthen * - remove missing trustanchors (if veryold and we have new anchors). 2240933707f3Ssthen */ 2241933707f3Ssthen if(!do_statetable(env, tp, &changed)) { 2242933707f3Ssthen log_err("malloc failure in autotrust do_statetable. " 2243933707f3Ssthen "trust point unchanged."); 2244933707f3Ssthen return 1; /* trust point unchanged, so exists */ 2245933707f3Ssthen } 2246933707f3Ssthen 2247933707f3Ssthen autr_cleanup_keys(tp); 2248933707f3Ssthen if(!set_next_probe(env, tp, dnskey_rrset)) 2249933707f3Ssthen return 0; /* trust point does not exist */ 2250933707f3Ssthen autr_write_file(env, tp); 2251933707f3Ssthen if(changed) { 2252933707f3Ssthen verbose(VERB_ALGO, "autotrust: changed, reassemble"); 2253933707f3Ssthen if(!autr_assemble(tp)) { 2254933707f3Ssthen log_err("malloc failure assembling autotrust keys"); 2255933707f3Ssthen return 1; /* unchanged */ 2256933707f3Ssthen } 2257933707f3Ssthen if(!tp->ds_rrset && !tp->dnskey_rrset) { 2258933707f3Ssthen /* no more keys, all are revoked */ 2259933707f3Ssthen autr_tp_remove(env, tp, dnskey_rrset); 2260933707f3Ssthen return 0; /* trust point removed */ 2261933707f3Ssthen } 2262933707f3Ssthen } else verbose(VERB_ALGO, "autotrust: no changes"); 2263933707f3Ssthen 2264933707f3Ssthen return 1; /* trust point exists */ 2265933707f3Ssthen } 2266933707f3Ssthen 2267933707f3Ssthen /** debug print a trust anchor key */ 2268933707f3Ssthen static void 2269933707f3Ssthen autr_debug_print_ta(struct autr_ta* ta) 2270933707f3Ssthen { 2271933707f3Ssthen char buf[32]; 22725d76a658Ssthen char* str = sldns_wire2str_rr(ta->rr, ta->rr_len); 2273933707f3Ssthen if(!str) { 2274933707f3Ssthen log_info("out of memory in debug_print_ta"); 2275933707f3Ssthen return; 2276933707f3Ssthen } 2277ebf5bb73Ssthen if(str[0]) str[strlen(str)-1]=0; /* remove newline */ 2278191f22c6Ssthen (void)autr_ctime_r(&ta->last_change, buf); 2279933707f3Ssthen if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2280933707f3Ssthen log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s", 2281933707f3Ssthen trustanchor_state2str(ta->s), str, ta->s, ta->pending_count, 2282933707f3Ssthen ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf); 2283933707f3Ssthen free(str); 2284933707f3Ssthen } 2285933707f3Ssthen 2286933707f3Ssthen /** debug print a trust point */ 2287933707f3Ssthen static void 2288933707f3Ssthen autr_debug_print_tp(struct trust_anchor* tp) 2289933707f3Ssthen { 2290933707f3Ssthen struct autr_ta* ta; 2291933707f3Ssthen char buf[257]; 2292933707f3Ssthen if(!tp->autr) 2293933707f3Ssthen return; 2294933707f3Ssthen dname_str(tp->name, buf); 2295933707f3Ssthen log_info("trust point %s : %d", buf, (int)tp->dclass); 2296933707f3Ssthen log_info("assembled %d DS and %d DNSKEYs", 2297933707f3Ssthen (int)tp->numDS, (int)tp->numDNSKEY); 2298933707f3Ssthen if(tp->ds_rrset) { 2299ebf5bb73Ssthen log_packed_rrset(NO_VERBOSE, "DS:", tp->ds_rrset); 2300933707f3Ssthen } 2301933707f3Ssthen if(tp->dnskey_rrset) { 2302ebf5bb73Ssthen log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset); 2303933707f3Ssthen } 2304933707f3Ssthen log_info("file %s", tp->autr->file); 2305191f22c6Ssthen (void)autr_ctime_r(&tp->autr->last_queried, buf); 2306933707f3Ssthen if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2307933707f3Ssthen log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); 2308191f22c6Ssthen (void)autr_ctime_r(&tp->autr->last_success, buf); 2309933707f3Ssthen if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2310933707f3Ssthen log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf); 2311191f22c6Ssthen (void)autr_ctime_r(&tp->autr->next_probe_time, buf); 2312933707f3Ssthen if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2313933707f3Ssthen log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time, 2314933707f3Ssthen buf); 2315933707f3Ssthen log_info("query_interval: %u", (unsigned)tp->autr->query_interval); 2316933707f3Ssthen log_info("retry_time: %u", (unsigned)tp->autr->retry_time); 2317933707f3Ssthen log_info("query_failed: %u", (unsigned)tp->autr->query_failed); 2318933707f3Ssthen 2319933707f3Ssthen for(ta=tp->autr->keys; ta; ta=ta->next) { 2320933707f3Ssthen autr_debug_print_ta(ta); 2321933707f3Ssthen } 2322933707f3Ssthen } 2323933707f3Ssthen 2324933707f3Ssthen void 2325933707f3Ssthen autr_debug_print(struct val_anchors* anchors) 2326933707f3Ssthen { 2327933707f3Ssthen struct trust_anchor* tp; 2328933707f3Ssthen lock_basic_lock(&anchors->lock); 2329933707f3Ssthen RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) { 2330933707f3Ssthen lock_basic_lock(&tp->lock); 2331933707f3Ssthen autr_debug_print_tp(tp); 2332933707f3Ssthen lock_basic_unlock(&tp->lock); 2333933707f3Ssthen } 2334933707f3Ssthen lock_basic_unlock(&anchors->lock); 2335933707f3Ssthen } 2336933707f3Ssthen 2337933707f3Ssthen void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode), 23385d76a658Ssthen sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), 23392308e98cSsthen char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2340933707f3Ssthen { 2341933707f3Ssthen /* retry was set before the query was done, 2342933707f3Ssthen * re-querytime is set when query succeeded, but that may not 2343933707f3Ssthen * have reset this timer because the query could have been 2344933707f3Ssthen * handled by another thread. In that case, this callback would 2345933707f3Ssthen * get called after the original timeout is done. 2346933707f3Ssthen * By not resetting the timer, it may probe more often, but not 2347933707f3Ssthen * less often. 2348933707f3Ssthen * Unless the new lookup resulted in smaller TTLs and thus smaller 2349933707f3Ssthen * timeout values. In that case one old TTL could be mistakenly done. 2350933707f3Ssthen */ 2351933707f3Ssthen struct module_env* env = (struct module_env*)arg; 2352933707f3Ssthen verbose(VERB_ALGO, "autotrust probe answer cb"); 2353933707f3Ssthen reset_worker_timer(env); 2354933707f3Ssthen } 2355933707f3Ssthen 2356933707f3Ssthen /** probe a trust anchor DNSKEY and unlocks tp */ 2357933707f3Ssthen static void 2358933707f3Ssthen probe_anchor(struct module_env* env, struct trust_anchor* tp) 2359933707f3Ssthen { 2360933707f3Ssthen struct query_info qinfo; 2361933707f3Ssthen uint16_t qflags = BIT_RD; 2362933707f3Ssthen struct edns_data edns; 23635d76a658Ssthen sldns_buffer* buf = env->scratch_buffer; 2364933707f3Ssthen qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen); 2365933707f3Ssthen if(!qinfo.qname) { 2366933707f3Ssthen log_err("out of memory making 5011 probe"); 2367933707f3Ssthen return; 2368933707f3Ssthen } 2369933707f3Ssthen qinfo.qname_len = tp->namelen; 2370933707f3Ssthen qinfo.qtype = LDNS_RR_TYPE_DNSKEY; 2371933707f3Ssthen qinfo.qclass = tp->dclass; 237277079be7Ssthen qinfo.local_alias = NULL; 2373933707f3Ssthen log_query_info(VERB_ALGO, "autotrust probe", &qinfo); 2374933707f3Ssthen verbose(VERB_ALGO, "retry probe set in %d seconds", 2375933707f3Ssthen (int)tp->autr->next_probe_time - (int)*env->now); 2376933707f3Ssthen edns.edns_present = 1; 2377933707f3Ssthen edns.ext_rcode = 0; 2378933707f3Ssthen edns.edns_version = 0; 2379933707f3Ssthen edns.bits = EDNS_DO; 2380e21c60efSsthen edns.opt_list_in = NULL; 2381e21c60efSsthen edns.opt_list_out = NULL; 2382e21c60efSsthen edns.opt_list_inplace_cb_out = NULL; 23839982a05dSsthen edns.padding_block_size = 0; 23848b7325afSsthen edns.cookie_present = 0; 23858b7325afSsthen edns.cookie_valid = 0; 23865d76a658Ssthen if(sldns_buffer_capacity(buf) < 65535) 23875d76a658Ssthen edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); 2388933707f3Ssthen else edns.udp_size = 65535; 2389933707f3Ssthen 2390933707f3Ssthen /* can't hold the lock while mesh_run is processing */ 2391933707f3Ssthen lock_basic_unlock(&tp->lock); 2392933707f3Ssthen 2393933707f3Ssthen /* delete the DNSKEY from rrset and key cache so an active probe 2394933707f3Ssthen * is done. First the rrset so another thread does not use it 2395933707f3Ssthen * to recreate the key entry in a race condition. */ 2396933707f3Ssthen rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len, 2397933707f3Ssthen qinfo.qtype, qinfo.qclass, 0); 2398933707f3Ssthen key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len, 2399933707f3Ssthen qinfo.qclass); 2400933707f3Ssthen 2401933707f3Ssthen if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 24020bdb4f62Ssthen &probe_answer_cb, env, 0)) { 2403933707f3Ssthen log_err("out of memory making 5011 probe"); 2404933707f3Ssthen } 2405933707f3Ssthen } 2406933707f3Ssthen 2407933707f3Ssthen /** fetch first to-probe trust-anchor and lock it and set retrytime */ 2408933707f3Ssthen static struct trust_anchor* 2409229e174cSsthen todo_probe(struct module_env* env, time_t* next) 2410933707f3Ssthen { 2411933707f3Ssthen struct trust_anchor* tp; 241277079be7Ssthen rbnode_type* el; 2413933707f3Ssthen /* get first one */ 2414933707f3Ssthen lock_basic_lock(&env->anchors->lock); 2415933707f3Ssthen if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { 2416933707f3Ssthen /* in case of revoked anchors */ 2417933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2418a961b961Ssthen /* signal that there are no anchors to probe */ 2419a961b961Ssthen *next = 0; 2420933707f3Ssthen return NULL; 2421933707f3Ssthen } 2422933707f3Ssthen tp = (struct trust_anchor*)el->key; 2423933707f3Ssthen lock_basic_lock(&tp->lock); 2424933707f3Ssthen 2425933707f3Ssthen /* is it eligible? */ 2426229e174cSsthen if((time_t)tp->autr->next_probe_time > *env->now) { 2427933707f3Ssthen /* no more to probe */ 2428229e174cSsthen *next = (time_t)tp->autr->next_probe_time - *env->now; 2429933707f3Ssthen lock_basic_unlock(&tp->lock); 2430933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2431933707f3Ssthen return NULL; 2432933707f3Ssthen } 2433933707f3Ssthen 2434933707f3Ssthen /* reset its next probe time */ 2435933707f3Ssthen (void)rbtree_delete(&env->anchors->autr->probe, tp); 2436933707f3Ssthen tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time); 2437933707f3Ssthen (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 2438933707f3Ssthen lock_basic_unlock(&env->anchors->lock); 2439933707f3Ssthen 2440933707f3Ssthen return tp; 2441933707f3Ssthen } 2442933707f3Ssthen 2443229e174cSsthen time_t 2444933707f3Ssthen autr_probe_timer(struct module_env* env) 2445933707f3Ssthen { 2446933707f3Ssthen struct trust_anchor* tp; 2447229e174cSsthen time_t next_probe = 3600; 2448933707f3Ssthen int num = 0; 2449a961b961Ssthen if(autr_permit_small_holddown) next_probe = 1; 2450933707f3Ssthen verbose(VERB_ALGO, "autotrust probe timer callback"); 2451933707f3Ssthen /* while there are still anchors to probe */ 2452933707f3Ssthen while( (tp = todo_probe(env, &next_probe)) ) { 2453933707f3Ssthen /* make a probe for this anchor */ 2454933707f3Ssthen probe_anchor(env, tp); 2455933707f3Ssthen num++; 2456933707f3Ssthen } 2457933707f3Ssthen regional_free_all(env->scratch); 2458a961b961Ssthen if(next_probe == 0) 2459933707f3Ssthen return 0; /* no trust points to probe */ 2460933707f3Ssthen verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); 2461933707f3Ssthen return next_probe; 2462933707f3Ssthen } 2463