xref: /netbsd-src/external/bsd/unbound/dist/validator/autotrust.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
13b6c3722Schristos /*
23b6c3722Schristos  * validator/autotrust.c - RFC5011 trust anchor management for unbound.
33b6c3722Schristos  *
43b6c3722Schristos  * Copyright (c) 2009, NLnet Labs. All rights reserved.
53b6c3722Schristos  *
63b6c3722Schristos  * This software is open source.
73b6c3722Schristos  *
83b6c3722Schristos  * Redistribution and use in source and binary forms, with or without
93b6c3722Schristos  * modification, are permitted provided that the following conditions
103b6c3722Schristos  * are met:
113b6c3722Schristos  *
123b6c3722Schristos  * Redistributions of source code must retain the above copyright notice,
133b6c3722Schristos  * this list of conditions and the following disclaimer.
143b6c3722Schristos  *
153b6c3722Schristos  * Redistributions in binary form must reproduce the above copyright notice,
163b6c3722Schristos  * this list of conditions and the following disclaimer in the documentation
173b6c3722Schristos  * and/or other materials provided with the distribution.
183b6c3722Schristos  *
193b6c3722Schristos  * Neither the name of the NLNET LABS nor the names of its contributors may
203b6c3722Schristos  * be used to endorse or promote products derived from this software without
213b6c3722Schristos  * specific prior written permission.
223b6c3722Schristos  *
233b6c3722Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
243b6c3722Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253b6c3722Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
263b6c3722Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
273b6c3722Schristos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
283b6c3722Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
293b6c3722Schristos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
303b6c3722Schristos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
313b6c3722Schristos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323b6c3722Schristos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
333b6c3722Schristos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
343b6c3722Schristos  */
353b6c3722Schristos 
363b6c3722Schristos /**
373b6c3722Schristos  * \file
383b6c3722Schristos  *
393b6c3722Schristos  * Contains autotrust implementation. The implementation was taken from
403b6c3722Schristos  * the autotrust daemon (BSD licensed), written by Matthijs Mekking.
413b6c3722Schristos  * It was modified to fit into unbound. The state table process is the same.
423b6c3722Schristos  */
433b6c3722Schristos #include "config.h"
443b6c3722Schristos #include "validator/autotrust.h"
453b6c3722Schristos #include "validator/val_anchor.h"
463b6c3722Schristos #include "validator/val_utils.h"
473b6c3722Schristos #include "validator/val_sigcrypt.h"
483b6c3722Schristos #include "util/data/dname.h"
493b6c3722Schristos #include "util/data/packed_rrset.h"
503b6c3722Schristos #include "util/log.h"
513b6c3722Schristos #include "util/module.h"
523b6c3722Schristos #include "util/net_help.h"
533b6c3722Schristos #include "util/config_file.h"
543b6c3722Schristos #include "util/regional.h"
553b6c3722Schristos #include "util/random.h"
563b6c3722Schristos #include "util/data/msgparse.h"
573b6c3722Schristos #include "services/mesh.h"
583b6c3722Schristos #include "services/cache/rrset.h"
593b6c3722Schristos #include "validator/val_kcache.h"
603b6c3722Schristos #include "sldns/sbuffer.h"
613b6c3722Schristos #include "sldns/wire2str.h"
623b6c3722Schristos #include "sldns/str2wire.h"
633b6c3722Schristos #include "sldns/keyraw.h"
643b6c3722Schristos #include "sldns/rrdef.h"
653b6c3722Schristos #include <stdarg.h>
663b6c3722Schristos #include <ctype.h>
673b6c3722Schristos 
683b6c3722Schristos /** number of times a key must be seen before it can become valid */
693b6c3722Schristos #define MIN_PENDINGCOUNT 2
703b6c3722Schristos 
713b6c3722Schristos /** Event: Revoked */
723b6c3722Schristos static void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c);
733b6c3722Schristos 
autr_global_create(void)743b6c3722Schristos struct autr_global_data* autr_global_create(void)
753b6c3722Schristos {
763b6c3722Schristos 	struct autr_global_data* global;
773b6c3722Schristos 	global = (struct autr_global_data*)malloc(sizeof(*global));
783b6c3722Schristos 	if(!global)
793b6c3722Schristos 		return NULL;
803b6c3722Schristos 	rbtree_init(&global->probe, &probetree_cmp);
813b6c3722Schristos 	return global;
823b6c3722Schristos }
833b6c3722Schristos 
autr_global_delete(struct autr_global_data * global)843b6c3722Schristos void autr_global_delete(struct autr_global_data* global)
853b6c3722Schristos {
863b6c3722Schristos 	if(!global)
873b6c3722Schristos 		return;
883b6c3722Schristos 	/* elements deleted by parent */
893b6c3722Schristos 	free(global);
903b6c3722Schristos }
913b6c3722Schristos 
probetree_cmp(const void * x,const void * y)923b6c3722Schristos int probetree_cmp(const void* x, const void* y)
933b6c3722Schristos {
943b6c3722Schristos 	struct trust_anchor* a = (struct trust_anchor*)x;
953b6c3722Schristos 	struct trust_anchor* b = (struct trust_anchor*)y;
963b6c3722Schristos 	log_assert(a->autr && b->autr);
973b6c3722Schristos 	if(a->autr->next_probe_time < b->autr->next_probe_time)
983b6c3722Schristos 		return -1;
993b6c3722Schristos 	if(a->autr->next_probe_time > b->autr->next_probe_time)
1003b6c3722Schristos 		return 1;
1013b6c3722Schristos 	/* time is equal, sort on trust point identity */
1023b6c3722Schristos 	return anchor_cmp(x, y);
1033b6c3722Schristos }
1043b6c3722Schristos 
1053b6c3722Schristos size_t
autr_get_num_anchors(struct val_anchors * anchors)1063b6c3722Schristos autr_get_num_anchors(struct val_anchors* anchors)
1073b6c3722Schristos {
1083b6c3722Schristos 	size_t res = 0;
1093b6c3722Schristos 	if(!anchors)
1103b6c3722Schristos 		return 0;
1113b6c3722Schristos 	lock_basic_lock(&anchors->lock);
1123b6c3722Schristos 	if(anchors->autr)
1133b6c3722Schristos 		res = anchors->autr->probe.count;
1143b6c3722Schristos 	lock_basic_unlock(&anchors->lock);
1153b6c3722Schristos 	return res;
1163b6c3722Schristos }
1173b6c3722Schristos 
1183b6c3722Schristos /** Position in string */
1193b6c3722Schristos static int
position_in_string(char * str,const char * sub)1203b6c3722Schristos position_in_string(char *str, const char* sub)
1213b6c3722Schristos {
1223b6c3722Schristos 	char* pos = strstr(str, sub);
1233b6c3722Schristos 	if(pos)
1243b6c3722Schristos 		return (int)(pos-str)+(int)strlen(sub);
1253b6c3722Schristos 	return -1;
1263b6c3722Schristos }
1273b6c3722Schristos 
1283b6c3722Schristos /** Debug routine to print pretty key information */
1293b6c3722Schristos static void
1303b6c3722Schristos verbose_key(struct autr_ta* ta, enum verbosity_value level,
1313b6c3722Schristos 	const char* format, ...) ATTR_FORMAT(printf, 3, 4);
1323b6c3722Schristos 
1333b6c3722Schristos /**
1343b6c3722Schristos  * Implementation of debug pretty key print
1353b6c3722Schristos  * @param ta: trust anchor key with DNSKEY data.
1363b6c3722Schristos  * @param level: verbosity level to print at.
1373b6c3722Schristos  * @param format: printf style format string.
1383b6c3722Schristos  */
1393b6c3722Schristos static void
verbose_key(struct autr_ta * ta,enum verbosity_value level,const char * format,...)1403b6c3722Schristos verbose_key(struct autr_ta* ta, enum verbosity_value level,
1413b6c3722Schristos 	const char* format, ...)
1423b6c3722Schristos {
1433b6c3722Schristos 	va_list args;
1443b6c3722Schristos 	va_start(args, format);
1453b6c3722Schristos 	if(verbosity >= level) {
1463b6c3722Schristos 		char* str = sldns_wire2str_dname(ta->rr, ta->dname_len);
1473b6c3722Schristos 		int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
1483b6c3722Schristos 			ta->rr, ta->rr_len, ta->dname_len),
1493b6c3722Schristos 			sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
1503b6c3722Schristos 			ta->dname_len));
1513b6c3722Schristos 		char msg[MAXSYSLOGMSGLEN];
1523b6c3722Schristos 		vsnprintf(msg, sizeof(msg), format, args);
1533b6c3722Schristos 		verbose(level, "%s key %d %s", str?str:"??", keytag, msg);
1543b6c3722Schristos 		free(str);
1553b6c3722Schristos 	}
1563b6c3722Schristos 	va_end(args);
1573b6c3722Schristos }
1583b6c3722Schristos 
1593b6c3722Schristos /**
1603b6c3722Schristos  * Parse comments
1613b6c3722Schristos  * @param str: to parse
1623b6c3722Schristos  * @param ta: trust key autotrust metadata
1633b6c3722Schristos  * @return false on failure.
1643b6c3722Schristos  */
1653b6c3722Schristos static int
parse_comments(char * str,struct autr_ta * ta)1663b6c3722Schristos parse_comments(char* str, struct autr_ta* ta)
1673b6c3722Schristos {
1683b6c3722Schristos         int len = (int)strlen(str), pos = 0, timestamp = 0;
1693b6c3722Schristos         char* comment = (char*) malloc(sizeof(char)*len+1);
1703b6c3722Schristos         char* comments = comment;
1713b6c3722Schristos 	if(!comment) {
1723b6c3722Schristos 		log_err("malloc failure in parse");
1733b6c3722Schristos                 return 0;
1743b6c3722Schristos 	}
1753b6c3722Schristos 	/* skip over whitespace and data at start of line */
1763b6c3722Schristos         while (*str != '\0' && *str != ';')
1773b6c3722Schristos                 str++;
1783b6c3722Schristos         if (*str == ';')
1793b6c3722Schristos                 str++;
1803b6c3722Schristos         /* copy comments */
1813b6c3722Schristos         while (*str != '\0')
1823b6c3722Schristos         {
1833b6c3722Schristos                 *comments = *str;
1843b6c3722Schristos                 comments++;
1853b6c3722Schristos                 str++;
1863b6c3722Schristos         }
1873b6c3722Schristos         *comments = '\0';
1883b6c3722Schristos 
1893b6c3722Schristos         comments = comment;
1903b6c3722Schristos 
1913b6c3722Schristos         /* read state */
1923b6c3722Schristos         pos = position_in_string(comments, "state=");
1933b6c3722Schristos         if (pos >= (int) strlen(comments))
1943b6c3722Schristos         {
1953b6c3722Schristos 		log_err("parse error");
1963b6c3722Schristos                 free(comment);
1973b6c3722Schristos                 return 0;
1983b6c3722Schristos         }
1993b6c3722Schristos         if (pos <= 0)
2003b6c3722Schristos                 ta->s = AUTR_STATE_VALID;
2013b6c3722Schristos         else
2023b6c3722Schristos         {
2033b6c3722Schristos                 int s = (int) comments[pos] - '0';
2043b6c3722Schristos                 switch(s)
2053b6c3722Schristos                 {
2063b6c3722Schristos                         case AUTR_STATE_START:
2073b6c3722Schristos                         case AUTR_STATE_ADDPEND:
2083b6c3722Schristos                         case AUTR_STATE_VALID:
2093b6c3722Schristos                         case AUTR_STATE_MISSING:
2103b6c3722Schristos                         case AUTR_STATE_REVOKED:
2113b6c3722Schristos                         case AUTR_STATE_REMOVED:
2123b6c3722Schristos                                 ta->s = s;
2133b6c3722Schristos                                 break;
2143b6c3722Schristos                         default:
2153b6c3722Schristos 				verbose_key(ta, VERB_OPS, "has undefined "
2163b6c3722Schristos 					"state, considered NewKey");
2173b6c3722Schristos                                 ta->s = AUTR_STATE_START;
2183b6c3722Schristos                                 break;
2193b6c3722Schristos                 }
2203b6c3722Schristos         }
2213b6c3722Schristos         /* read pending count */
2223b6c3722Schristos         pos = position_in_string(comments, "count=");
2233b6c3722Schristos         if (pos >= (int) strlen(comments))
2243b6c3722Schristos         {
2253b6c3722Schristos 		log_err("parse error");
2263b6c3722Schristos                 free(comment);
2273b6c3722Schristos                 return 0;
2283b6c3722Schristos         }
2293b6c3722Schristos         if (pos <= 0)
2303b6c3722Schristos                 ta->pending_count = 0;
2313b6c3722Schristos         else
2323b6c3722Schristos         {
2333b6c3722Schristos                 comments += pos;
2343b6c3722Schristos                 ta->pending_count = (uint8_t)atoi(comments);
2353b6c3722Schristos         }
2363b6c3722Schristos 
2373b6c3722Schristos         /* read last change */
2383b6c3722Schristos         pos = position_in_string(comments, "lastchange=");
2393b6c3722Schristos         if (pos >= (int) strlen(comments))
2403b6c3722Schristos         {
2413b6c3722Schristos 		log_err("parse error");
2423b6c3722Schristos                 free(comment);
2433b6c3722Schristos                 return 0;
2443b6c3722Schristos         }
2453b6c3722Schristos         if (pos >= 0)
2463b6c3722Schristos         {
2473b6c3722Schristos                 comments += pos;
2483b6c3722Schristos                 timestamp = atoi(comments);
2493b6c3722Schristos         }
2503b6c3722Schristos         if (pos < 0 || !timestamp)
2513b6c3722Schristos 		ta->last_change = 0;
2523b6c3722Schristos         else
2533b6c3722Schristos                 ta->last_change = (time_t)timestamp;
2543b6c3722Schristos 
2553b6c3722Schristos         free(comment);
2563b6c3722Schristos         return 1;
2573b6c3722Schristos }
2583b6c3722Schristos 
2593b6c3722Schristos /** Check if a line contains data (besides comments) */
2603b6c3722Schristos static int
str_contains_data(char * str,char comment)2613b6c3722Schristos str_contains_data(char* str, char comment)
2623b6c3722Schristos {
2633b6c3722Schristos         while (*str != '\0') {
2643b6c3722Schristos                 if (*str == comment || *str == '\n')
2653b6c3722Schristos                         return 0;
2663b6c3722Schristos                 if (*str != ' ' && *str != '\t')
2673b6c3722Schristos                         return 1;
2683b6c3722Schristos                 str++;
2693b6c3722Schristos         }
2703b6c3722Schristos         return 0;
2713b6c3722Schristos }
2723b6c3722Schristos 
2733b6c3722Schristos /** Get DNSKEY flags
2743b6c3722Schristos  * rdata without rdatalen in front of it. */
2753b6c3722Schristos static int
dnskey_flags(uint16_t t,uint8_t * rdata,size_t len)2763b6c3722Schristos dnskey_flags(uint16_t t, uint8_t* rdata, size_t len)
2773b6c3722Schristos {
2783b6c3722Schristos 	uint16_t f;
2793b6c3722Schristos 	if(t != LDNS_RR_TYPE_DNSKEY)
2803b6c3722Schristos 		return 0;
2813b6c3722Schristos 	if(len < 2)
2823b6c3722Schristos 		return 0;
2833b6c3722Schristos 	memmove(&f, rdata, 2);
2843b6c3722Schristos 	f = ntohs(f);
2853b6c3722Schristos 	return (int)f;
2863b6c3722Schristos }
2873b6c3722Schristos 
2883b6c3722Schristos /** Check if KSK DNSKEY.
2893b6c3722Schristos  * pass rdata without rdatalen in front of it */
2903b6c3722Schristos static int
rr_is_dnskey_sep(uint16_t t,uint8_t * rdata,size_t len)2913b6c3722Schristos rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len)
2923b6c3722Schristos {
2933b6c3722Schristos 	return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP);
2943b6c3722Schristos }
2953b6c3722Schristos 
2963b6c3722Schristos /** Check if TA is KSK DNSKEY */
2973b6c3722Schristos static int
ta_is_dnskey_sep(struct autr_ta * ta)2983b6c3722Schristos ta_is_dnskey_sep(struct autr_ta* ta)
2993b6c3722Schristos {
3003b6c3722Schristos 	return (dnskey_flags(
3013b6c3722Schristos 		sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len),
3023b6c3722Schristos 		sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len),
3033b6c3722Schristos 		sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len)
3043b6c3722Schristos 		) & DNSKEY_BIT_SEP);
3053b6c3722Schristos }
3063b6c3722Schristos 
3073b6c3722Schristos /** Check if REVOKED DNSKEY
3083b6c3722Schristos  * pass rdata without rdatalen in front of it */
3093b6c3722Schristos static int
rr_is_dnskey_revoked(uint16_t t,uint8_t * rdata,size_t len)3103b6c3722Schristos rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len)
3113b6c3722Schristos {
3123b6c3722Schristos 	return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY);
3133b6c3722Schristos }
3143b6c3722Schristos 
3153b6c3722Schristos /** create ta */
3163b6c3722Schristos static struct autr_ta*
autr_ta_create(uint8_t * rr,size_t rr_len,size_t dname_len)3173b6c3722Schristos autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len)
3183b6c3722Schristos {
3193b6c3722Schristos 	struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta));
3203b6c3722Schristos 	if(!ta) {
3213b6c3722Schristos 		free(rr);
3223b6c3722Schristos 		return NULL;
3233b6c3722Schristos 	}
3243b6c3722Schristos 	ta->rr = rr;
3253b6c3722Schristos 	ta->rr_len = rr_len;
3263b6c3722Schristos 	ta->dname_len = dname_len;
3273b6c3722Schristos 	return ta;
3283b6c3722Schristos }
3293b6c3722Schristos 
3303b6c3722Schristos /** create tp */
3313b6c3722Schristos static struct trust_anchor*
autr_tp_create(struct val_anchors * anchors,uint8_t * own,size_t own_len,uint16_t dc)3323b6c3722Schristos autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len,
3333b6c3722Schristos 	uint16_t dc)
3343b6c3722Schristos {
3353b6c3722Schristos 	struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp));
3363b6c3722Schristos 	if(!tp) return NULL;
3373b6c3722Schristos 	tp->name = memdup(own, own_len);
3383b6c3722Schristos 	if(!tp->name) {
3393b6c3722Schristos 		free(tp);
3403b6c3722Schristos 		return NULL;
3413b6c3722Schristos 	}
3423b6c3722Schristos 	tp->namelen = own_len;
3433b6c3722Schristos 	tp->namelabs = dname_count_labels(tp->name);
3443b6c3722Schristos 	tp->node.key = tp;
3453b6c3722Schristos 	tp->dclass = dc;
3463b6c3722Schristos 	tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr));
3473b6c3722Schristos 	if(!tp->autr) {
3483b6c3722Schristos 		free(tp->name);
3493b6c3722Schristos 		free(tp);
3503b6c3722Schristos 		return NULL;
3513b6c3722Schristos 	}
3523b6c3722Schristos 	tp->autr->pnode.key = tp;
3533b6c3722Schristos 
3543b6c3722Schristos 	lock_basic_lock(&anchors->lock);
3553b6c3722Schristos 	if(!rbtree_insert(anchors->tree, &tp->node)) {
3563b6c3722Schristos 		lock_basic_unlock(&anchors->lock);
3573b6c3722Schristos 		log_err("trust anchor presented twice");
3583b6c3722Schristos 		free(tp->name);
3593b6c3722Schristos 		free(tp->autr);
3603b6c3722Schristos 		free(tp);
3613b6c3722Schristos 		return NULL;
3623b6c3722Schristos 	}
3633b6c3722Schristos 	if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) {
3643b6c3722Schristos 		(void)rbtree_delete(anchors->tree, tp);
3653b6c3722Schristos 		lock_basic_unlock(&anchors->lock);
3663b6c3722Schristos 		log_err("trust anchor in probetree twice");
3673b6c3722Schristos 		free(tp->name);
3683b6c3722Schristos 		free(tp->autr);
3693b6c3722Schristos 		free(tp);
3703b6c3722Schristos 		return NULL;
3713b6c3722Schristos 	}
3723b6c3722Schristos 	lock_basic_init(&tp->lock);
3733b6c3722Schristos 	lock_protect(&tp->lock, tp, sizeof(*tp));
3743b6c3722Schristos 	lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
37501049ae6Schristos 	lock_basic_unlock(&anchors->lock);
3763b6c3722Schristos 	return tp;
3773b6c3722Schristos }
3783b6c3722Schristos 
3793b6c3722Schristos /** delete assembled rrsets */
3803b6c3722Schristos static void
autr_rrset_delete(struct ub_packed_rrset_key * r)3813b6c3722Schristos autr_rrset_delete(struct ub_packed_rrset_key* r)
3823b6c3722Schristos {
3833b6c3722Schristos 	if(r) {
3843b6c3722Schristos 		free(r->rk.dname);
3853b6c3722Schristos 		free(r->entry.data);
3863b6c3722Schristos 		free(r);
3873b6c3722Schristos 	}
3883b6c3722Schristos }
3893b6c3722Schristos 
autr_point_delete(struct trust_anchor * tp)3903b6c3722Schristos void autr_point_delete(struct trust_anchor* tp)
3913b6c3722Schristos {
3923b6c3722Schristos 	if(!tp)
3933b6c3722Schristos 		return;
3943b6c3722Schristos 	lock_unprotect(&tp->lock, tp);
3953b6c3722Schristos 	lock_unprotect(&tp->lock, tp->autr);
3963b6c3722Schristos 	lock_basic_destroy(&tp->lock);
3973b6c3722Schristos 	autr_rrset_delete(tp->ds_rrset);
3983b6c3722Schristos 	autr_rrset_delete(tp->dnskey_rrset);
3993b6c3722Schristos 	if(tp->autr) {
4003b6c3722Schristos 		struct autr_ta* p = tp->autr->keys, *np;
4013b6c3722Schristos 		while(p) {
4023b6c3722Schristos 			np = p->next;
4033b6c3722Schristos 			free(p->rr);
4043b6c3722Schristos 			free(p);
4053b6c3722Schristos 			p = np;
4063b6c3722Schristos 		}
4073b6c3722Schristos 		free(tp->autr->file);
4083b6c3722Schristos 		free(tp->autr);
4093b6c3722Schristos 	}
4103b6c3722Schristos 	free(tp->name);
4113b6c3722Schristos 	free(tp);
4123b6c3722Schristos }
4133b6c3722Schristos 
4143b6c3722Schristos /** find or add a new trust point for autotrust */
4153b6c3722Schristos static struct trust_anchor*
find_add_tp(struct val_anchors * anchors,uint8_t * rr,size_t rr_len,size_t dname_len)4163b6c3722Schristos find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
4173b6c3722Schristos 	size_t dname_len)
4183b6c3722Schristos {
4193b6c3722Schristos 	struct trust_anchor* tp;
4203b6c3722Schristos 	tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len,
4213b6c3722Schristos 		sldns_wirerr_get_class(rr, rr_len, dname_len));
4223b6c3722Schristos 	if(tp) {
4233b6c3722Schristos 		if(!tp->autr) {
4243b6c3722Schristos 			log_err("anchor cannot be with and without autotrust");
4253b6c3722Schristos 			lock_basic_unlock(&tp->lock);
4263b6c3722Schristos 			return NULL;
4273b6c3722Schristos 		}
4283b6c3722Schristos 		return tp;
4293b6c3722Schristos 	}
4303b6c3722Schristos 	tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr,
4313b6c3722Schristos 		rr_len, dname_len));
4320cd9f4ecSchristos 	if(!tp)
4330cd9f4ecSchristos 		return NULL;
4343b6c3722Schristos 	lock_basic_lock(&tp->lock);
4353b6c3722Schristos 	return tp;
4363b6c3722Schristos }
4373b6c3722Schristos 
4383b6c3722Schristos /** Add trust anchor from RR */
4393b6c3722Schristos static struct autr_ta*
add_trustanchor_frm_rr(struct val_anchors * anchors,uint8_t * rr,size_t rr_len,size_t dname_len,struct trust_anchor ** tp)4403b6c3722Schristos add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
4413b6c3722Schristos         size_t dname_len, struct trust_anchor** tp)
4423b6c3722Schristos {
4433b6c3722Schristos 	struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len);
4443b6c3722Schristos 	if(!ta)
4453b6c3722Schristos 		return NULL;
4463b6c3722Schristos 	*tp = find_add_tp(anchors, rr, rr_len, dname_len);
4473b6c3722Schristos 	if(!*tp) {
4483b6c3722Schristos 		free(ta->rr);
4493b6c3722Schristos 		free(ta);
4503b6c3722Schristos 		return NULL;
4513b6c3722Schristos 	}
4523b6c3722Schristos 	/* add ta to tp */
4533b6c3722Schristos 	ta->next = (*tp)->autr->keys;
4543b6c3722Schristos 	(*tp)->autr->keys = ta;
4553b6c3722Schristos 	lock_basic_unlock(&(*tp)->lock);
4563b6c3722Schristos 	return ta;
4573b6c3722Schristos }
4583b6c3722Schristos 
4593b6c3722Schristos /**
4603b6c3722Schristos  * Add new trust anchor from a string in file.
4613b6c3722Schristos  * @param anchors: all anchors
4623b6c3722Schristos  * @param str: string with anchor and comments, if any comments.
4633b6c3722Schristos  * @param tp: trust point returned.
4643b6c3722Schristos  * @param origin: what to use for @
4653b6c3722Schristos  * @param origin_len: length of origin
4663b6c3722Schristos  * @param prev: previous rr name
4673b6c3722Schristos  * @param prev_len: length of prev
4683b6c3722Schristos  * @param skip: if true, the result is NULL, but not an error, skip it.
4693b6c3722Schristos  * @return new key in trust point.
4703b6c3722Schristos  */
4713b6c3722Schristos static struct autr_ta*
add_trustanchor_frm_str(struct val_anchors * anchors,char * str,struct trust_anchor ** tp,uint8_t * origin,size_t origin_len,uint8_t ** prev,size_t * prev_len,int * skip)4723b6c3722Schristos add_trustanchor_frm_str(struct val_anchors* anchors, char* str,
4733b6c3722Schristos 	struct trust_anchor** tp, uint8_t* origin, size_t origin_len,
4743b6c3722Schristos 	uint8_t** prev, size_t* prev_len, int* skip)
4753b6c3722Schristos {
4763b6c3722Schristos 	uint8_t rr[LDNS_RR_BUF_SIZE];
4773b6c3722Schristos 	size_t rr_len = sizeof(rr), dname_len;
4783b6c3722Schristos 	uint8_t* drr;
4793b6c3722Schristos 	int lstatus;
4803b6c3722Schristos         if (!str_contains_data(str, ';')) {
4813b6c3722Schristos 		*skip = 1;
4823b6c3722Schristos                 return NULL; /* empty line */
4833b6c3722Schristos 	}
4843b6c3722Schristos 	if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len,
4853b6c3722Schristos 		0, origin, origin_len, *prev, *prev_len)))
4863b6c3722Schristos 	{
4873b6c3722Schristos 		log_err("ldns error while converting string to RR at%d: %s: %s",
4883b6c3722Schristos 			LDNS_WIREPARSE_OFFSET(lstatus),
4893b6c3722Schristos 			sldns_get_errorstr_parse(lstatus), str);
4903b6c3722Schristos 		return NULL;
4913b6c3722Schristos 	}
4923b6c3722Schristos 	free(*prev);
4933b6c3722Schristos 	*prev = memdup(rr, dname_len);
4943b6c3722Schristos 	*prev_len = dname_len;
4953b6c3722Schristos 	if(!*prev) {
4963b6c3722Schristos 		log_err("malloc failure in add_trustanchor");
4973b6c3722Schristos 		return NULL;
4983b6c3722Schristos 	}
4993b6c3722Schristos 	if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY &&
5003b6c3722Schristos 		sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) {
5013b6c3722Schristos 		*skip = 1;
5023b6c3722Schristos 		return NULL; /* only DS and DNSKEY allowed */
5033b6c3722Schristos 	}
5043b6c3722Schristos 	drr = memdup(rr, rr_len);
5053b6c3722Schristos 	if(!drr) {
5063b6c3722Schristos 		log_err("malloc failure in add trustanchor");
5073b6c3722Schristos 		return NULL;
5083b6c3722Schristos 	}
5093b6c3722Schristos 	return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp);
5103b6c3722Schristos }
5113b6c3722Schristos 
5123b6c3722Schristos /**
5133b6c3722Schristos  * Load single anchor
5143b6c3722Schristos  * @param anchors: all points.
5153b6c3722Schristos  * @param str: comments line
5163b6c3722Schristos  * @param fname: filename
5173b6c3722Schristos  * @param origin: the $ORIGIN.
5183b6c3722Schristos  * @param origin_len: length of origin
5193b6c3722Schristos  * @param prev: passed to ldns.
5203b6c3722Schristos  * @param prev_len: length of prev
5213b6c3722Schristos  * @param skip: if true, the result is NULL, but not an error, skip it.
5223b6c3722Schristos  * @return false on failure, otherwise the tp read.
5233b6c3722Schristos  */
5243b6c3722Schristos static struct trust_anchor*
load_trustanchor(struct val_anchors * anchors,char * str,const char * fname,uint8_t * origin,size_t origin_len,uint8_t ** prev,size_t * prev_len,int * skip)5253b6c3722Schristos load_trustanchor(struct val_anchors* anchors, char* str, const char* fname,
5263b6c3722Schristos 	uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len,
5273b6c3722Schristos 	int* skip)
5283b6c3722Schristos {
5293b6c3722Schristos 	struct autr_ta* ta = NULL;
5303b6c3722Schristos 	struct trust_anchor* tp = NULL;
5313b6c3722Schristos 
5323b6c3722Schristos 	ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len,
5333b6c3722Schristos 		prev, prev_len, skip);
5343b6c3722Schristos 	if(!ta)
5353b6c3722Schristos 		return NULL;
5363b6c3722Schristos 	lock_basic_lock(&tp->lock);
5373b6c3722Schristos 	if(!parse_comments(str, ta)) {
5383b6c3722Schristos 		lock_basic_unlock(&tp->lock);
5393b6c3722Schristos 		return NULL;
5403b6c3722Schristos 	}
5413b6c3722Schristos 	if(!tp->autr->file) {
5423b6c3722Schristos 		tp->autr->file = strdup(fname);
5433b6c3722Schristos 		if(!tp->autr->file) {
5443b6c3722Schristos 			lock_basic_unlock(&tp->lock);
5453b6c3722Schristos 			log_err("malloc failure");
5463b6c3722Schristos 			return NULL;
5473b6c3722Schristos 		}
5483b6c3722Schristos 	}
5493b6c3722Schristos 	lock_basic_unlock(&tp->lock);
5503b6c3722Schristos         return tp;
5513b6c3722Schristos }
5523b6c3722Schristos 
5533b6c3722Schristos /** iterator for DSes from keylist. return true if a next element exists */
5543b6c3722Schristos static int
assemble_iterate_ds(struct autr_ta ** list,uint8_t ** rr,size_t * rr_len,size_t * dname_len)5553b6c3722Schristos assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
5563b6c3722Schristos 	size_t* dname_len)
5573b6c3722Schristos {
5583b6c3722Schristos 	while(*list) {
5593b6c3722Schristos 		if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
5603b6c3722Schristos 			(*list)->dname_len) == LDNS_RR_TYPE_DS) {
5613b6c3722Schristos 			*rr = (*list)->rr;
5623b6c3722Schristos 			*rr_len = (*list)->rr_len;
5633b6c3722Schristos 			*dname_len = (*list)->dname_len;
5643b6c3722Schristos 			*list = (*list)->next;
5653b6c3722Schristos 			return 1;
5663b6c3722Schristos 		}
5673b6c3722Schristos 		*list = (*list)->next;
5683b6c3722Schristos 	}
5693b6c3722Schristos 	return 0;
5703b6c3722Schristos }
5713b6c3722Schristos 
5723b6c3722Schristos /** iterator for DNSKEYs from keylist. return true if a next element exists */
5733b6c3722Schristos static int
assemble_iterate_dnskey(struct autr_ta ** list,uint8_t ** rr,size_t * rr_len,size_t * dname_len)5743b6c3722Schristos assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
5753b6c3722Schristos 	size_t* dname_len)
5763b6c3722Schristos {
5773b6c3722Schristos 	while(*list) {
5783b6c3722Schristos 		if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
5793b6c3722Schristos 		   (*list)->dname_len) != LDNS_RR_TYPE_DS &&
5803b6c3722Schristos 			((*list)->s == AUTR_STATE_VALID ||
5813b6c3722Schristos 			 (*list)->s == AUTR_STATE_MISSING)) {
5823b6c3722Schristos 			*rr = (*list)->rr;
5833b6c3722Schristos 			*rr_len = (*list)->rr_len;
5843b6c3722Schristos 			*dname_len = (*list)->dname_len;
5853b6c3722Schristos 			*list = (*list)->next;
5863b6c3722Schristos 			return 1;
5873b6c3722Schristos 		}
5883b6c3722Schristos 		*list = (*list)->next;
5893b6c3722Schristos 	}
5903b6c3722Schristos 	return 0;
5913b6c3722Schristos }
5923b6c3722Schristos 
5933b6c3722Schristos /** see if iterator-list has any elements in it, or it is empty */
5943b6c3722Schristos static int
assemble_iterate_hasfirst(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)5953b6c3722Schristos assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*,
5963b6c3722Schristos 	size_t*), struct autr_ta* list)
5973b6c3722Schristos {
5983b6c3722Schristos 	uint8_t* rr = NULL;
5993b6c3722Schristos 	size_t rr_len = 0, dname_len = 0;
6003b6c3722Schristos 	return iter(&list, &rr, &rr_len, &dname_len);
6013b6c3722Schristos }
6023b6c3722Schristos 
6033b6c3722Schristos /** number of elements in iterator list */
6043b6c3722Schristos static size_t
assemble_iterate_count(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6053b6c3722Schristos assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*,
6063b6c3722Schristos 	size_t*), struct autr_ta* list)
6073b6c3722Schristos {
6083b6c3722Schristos 	uint8_t* rr = NULL;
6093b6c3722Schristos 	size_t i = 0, rr_len = 0, dname_len = 0;
6103b6c3722Schristos 	while(iter(&list, &rr, &rr_len, &dname_len)) {
6113b6c3722Schristos 		i++;
6123b6c3722Schristos 	}
6133b6c3722Schristos 	return i;
6143b6c3722Schristos }
6153b6c3722Schristos 
6163b6c3722Schristos /**
6173b6c3722Schristos  * Create a ub_packed_rrset_key allocated on the heap.
6183b6c3722Schristos  * It therefore does not have the correct ID value, and cannot be used
6193b6c3722Schristos  * inside the cache.  It can be used in storage outside of the cache.
6203b6c3722Schristos  * Keys for the cache have to be obtained from alloc.h .
6213b6c3722Schristos  * @param iter: iterator over the elements in the list.  It filters elements.
6223b6c3722Schristos  * @param list: the list.
6233b6c3722Schristos  * @return key allocated or NULL on failure.
6243b6c3722Schristos  */
6253b6c3722Schristos static struct ub_packed_rrset_key*
ub_packed_rrset_heap_key(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6263b6c3722Schristos ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*,
6273b6c3722Schristos 	size_t*), struct autr_ta* list)
6283b6c3722Schristos {
6293b6c3722Schristos 	uint8_t* rr = NULL;
6303b6c3722Schristos 	size_t rr_len = 0, dname_len = 0;
6313b6c3722Schristos 	struct ub_packed_rrset_key* k;
6323b6c3722Schristos 	if(!iter(&list, &rr, &rr_len, &dname_len))
6333b6c3722Schristos 		return NULL;
6343b6c3722Schristos 	k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k));
6353b6c3722Schristos 	if(!k)
6363b6c3722Schristos 		return NULL;
6373b6c3722Schristos 	k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
6383b6c3722Schristos 	k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
6393b6c3722Schristos 	k->rk.dname_len = dname_len;
6403b6c3722Schristos 	k->rk.dname = memdup(rr, dname_len);
6413b6c3722Schristos 	if(!k->rk.dname) {
6423b6c3722Schristos 		free(k);
6433b6c3722Schristos 		return NULL;
6443b6c3722Schristos 	}
6453b6c3722Schristos 	return k;
6463b6c3722Schristos }
6473b6c3722Schristos 
6483b6c3722Schristos /**
6493b6c3722Schristos  * Create packed_rrset data on the heap.
6503b6c3722Schristos  * @param iter: iterator over the elements in the list.  It filters elements.
6513b6c3722Schristos  * @param list: the list.
6523b6c3722Schristos  * @return data allocated or NULL on failure.
6533b6c3722Schristos  */
6543b6c3722Schristos static struct packed_rrset_data*
packed_rrset_heap_data(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6553b6c3722Schristos packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*,
6563b6c3722Schristos 	size_t*), struct autr_ta* list)
6573b6c3722Schristos {
6583b6c3722Schristos 	uint8_t* rr = NULL;
6593b6c3722Schristos 	size_t rr_len = 0, dname_len = 0;
6603b6c3722Schristos 	struct packed_rrset_data* data;
6613b6c3722Schristos 	size_t count=0, rrsig_count=0, len=0, i, total;
6623b6c3722Schristos 	uint8_t* nextrdata;
6633b6c3722Schristos 	struct autr_ta* list_i;
6643b6c3722Schristos 	time_t ttl = 0;
6653b6c3722Schristos 
6663b6c3722Schristos 	list_i = list;
6673b6c3722Schristos 	while(iter(&list_i, &rr, &rr_len, &dname_len)) {
6683b6c3722Schristos 		if(sldns_wirerr_get_type(rr, rr_len, dname_len) ==
6693b6c3722Schristos 			LDNS_RR_TYPE_RRSIG)
6703b6c3722Schristos 			rrsig_count++;
6713b6c3722Schristos 		else	count++;
6723b6c3722Schristos 		/* sizeof the rdlength + rdatalen */
6733b6c3722Schristos 		len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
6743b6c3722Schristos 		ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len);
6753b6c3722Schristos 	}
6763b6c3722Schristos 	if(count == 0 && rrsig_count == 0)
6773b6c3722Schristos 		return NULL;
6783b6c3722Schristos 
6793b6c3722Schristos 	/* allocate */
6803b6c3722Schristos 	total = count + rrsig_count;
6813b6c3722Schristos 	len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) +
6823b6c3722Schristos 		sizeof(uint8_t*));
6833b6c3722Schristos 	data = (struct packed_rrset_data*)calloc(1, len);
6843b6c3722Schristos 	if(!data)
6853b6c3722Schristos 		return NULL;
6863b6c3722Schristos 
6873b6c3722Schristos 	/* fill it */
6883b6c3722Schristos 	data->ttl = ttl;
6893b6c3722Schristos 	data->count = count;
6903b6c3722Schristos 	data->rrsig_count = rrsig_count;
6913b6c3722Schristos 	data->rr_len = (size_t*)((uint8_t*)data +
6923b6c3722Schristos 		sizeof(struct packed_rrset_data));
6933b6c3722Schristos 	data->rr_data = (uint8_t**)&(data->rr_len[total]);
6943b6c3722Schristos 	data->rr_ttl = (time_t*)&(data->rr_data[total]);
6953b6c3722Schristos 	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
6963b6c3722Schristos 
6973b6c3722Schristos 	/* fill out len, ttl, fields */
6983b6c3722Schristos 	list_i = list;
6993b6c3722Schristos 	i = 0;
7003b6c3722Schristos 	while(iter(&list_i, &rr, &rr_len, &dname_len)) {
7013b6c3722Schristos 		data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len,
7023b6c3722Schristos 			dname_len);
7033b6c3722Schristos 		if(data->rr_ttl[i] < data->ttl)
7043b6c3722Schristos 			data->ttl = data->rr_ttl[i];
7053b6c3722Schristos 		data->rr_len[i] = 2 /* the rdlength */ +
7063b6c3722Schristos 			sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
7073b6c3722Schristos 		i++;
7083b6c3722Schristos 	}
7093b6c3722Schristos 
7103b6c3722Schristos 	/* fixup rest of ptrs */
7113b6c3722Schristos 	for(i=0; i<total; i++) {
7123b6c3722Schristos 		data->rr_data[i] = nextrdata;
7133b6c3722Schristos 		nextrdata += data->rr_len[i];
7143b6c3722Schristos 	}
7153b6c3722Schristos 
7163b6c3722Schristos 	/* copy data in there */
7173b6c3722Schristos 	list_i = list;
7183b6c3722Schristos 	i = 0;
7193b6c3722Schristos 	while(iter(&list_i, &rr, &rr_len, &dname_len)) {
720f42d8de7Schristos 		log_assert(data->rr_data[i]);
7213b6c3722Schristos 		memmove(data->rr_data[i],
7223b6c3722Schristos 			sldns_wirerr_get_rdatawl(rr, rr_len, dname_len),
7233b6c3722Schristos 			data->rr_len[i]);
7243b6c3722Schristos 		i++;
7253b6c3722Schristos 	}
7263b6c3722Schristos 
7273b6c3722Schristos 	if(data->rrsig_count && data->count == 0) {
7283b6c3722Schristos 		data->count = data->rrsig_count; /* rrset type is RRSIG */
7293b6c3722Schristos 		data->rrsig_count = 0;
7303b6c3722Schristos 	}
7313b6c3722Schristos 	return data;
7323b6c3722Schristos }
7333b6c3722Schristos 
7343b6c3722Schristos /**
7353b6c3722Schristos  * Assemble the trust anchors into DS and DNSKEY packed rrsets.
7363b6c3722Schristos  * Uses only VALID and MISSING DNSKEYs.
7373b6c3722Schristos  * Read the sldns_rrs and builds packed rrsets
7383b6c3722Schristos  * @param tp: the trust point. Must be locked.
7393b6c3722Schristos  * @return false on malloc failure.
7403b6c3722Schristos  */
7413b6c3722Schristos static int
autr_assemble(struct trust_anchor * tp)7423b6c3722Schristos autr_assemble(struct trust_anchor* tp)
7433b6c3722Schristos {
7443b6c3722Schristos 	struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL;
7453b6c3722Schristos 
7463b6c3722Schristos 	/* make packed rrset keys - malloced with no ID number, they
7473b6c3722Schristos 	 * are not in the cache */
7483b6c3722Schristos 	/* make packed rrset data (if there is a key) */
7493b6c3722Schristos 	if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) {
7503b6c3722Schristos 		ubds = ub_packed_rrset_heap_key(
7513b6c3722Schristos 			assemble_iterate_ds, tp->autr->keys);
7523b6c3722Schristos 		if(!ubds)
7533b6c3722Schristos 			goto error_cleanup;
7543b6c3722Schristos 		ubds->entry.data = packed_rrset_heap_data(
7553b6c3722Schristos 			assemble_iterate_ds, tp->autr->keys);
7563b6c3722Schristos 		if(!ubds->entry.data)
7573b6c3722Schristos 			goto error_cleanup;
7583b6c3722Schristos 	}
7593b6c3722Schristos 
7603b6c3722Schristos 	/* make packed DNSKEY data */
7613b6c3722Schristos 	if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) {
7623b6c3722Schristos 		ubdnskey = ub_packed_rrset_heap_key(
7633b6c3722Schristos 			assemble_iterate_dnskey, tp->autr->keys);
7643b6c3722Schristos 		if(!ubdnskey)
7653b6c3722Schristos 			goto error_cleanup;
7663b6c3722Schristos 		ubdnskey->entry.data = packed_rrset_heap_data(
7673b6c3722Schristos 			assemble_iterate_dnskey, tp->autr->keys);
7683b6c3722Schristos 		if(!ubdnskey->entry.data) {
7693b6c3722Schristos 		error_cleanup:
7703b6c3722Schristos 			autr_rrset_delete(ubds);
7713b6c3722Schristos 			autr_rrset_delete(ubdnskey);
7723b6c3722Schristos 			return 0;
7733b6c3722Schristos 		}
7743b6c3722Schristos 	}
7753b6c3722Schristos 
7763b6c3722Schristos 	/* we have prepared the new keys so nothing can go wrong any more.
7773b6c3722Schristos 	 * And we are sure we cannot be left without trustanchor after
7783b6c3722Schristos 	 * any errors. Put in the new keys and remove old ones. */
7793b6c3722Schristos 
7803b6c3722Schristos 	/* free the old data */
7813b6c3722Schristos 	autr_rrset_delete(tp->ds_rrset);
7823b6c3722Schristos 	autr_rrset_delete(tp->dnskey_rrset);
7833b6c3722Schristos 
7843b6c3722Schristos 	/* assign the data to replace the old */
7853b6c3722Schristos 	tp->ds_rrset = ubds;
7863b6c3722Schristos 	tp->dnskey_rrset = ubdnskey;
7873b6c3722Schristos 	tp->numDS = assemble_iterate_count(assemble_iterate_ds,
7883b6c3722Schristos 		tp->autr->keys);
7893b6c3722Schristos 	tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey,
7903b6c3722Schristos 		tp->autr->keys);
7913b6c3722Schristos 	return 1;
7923b6c3722Schristos }
7933b6c3722Schristos 
7943b6c3722Schristos /** parse integer */
7953b6c3722Schristos static unsigned int
parse_int(char * line,int * ret)7963b6c3722Schristos parse_int(char* line, int* ret)
7973b6c3722Schristos {
7983b6c3722Schristos 	char *e;
7993b6c3722Schristos 	unsigned int x = (unsigned int)strtol(line, &e, 10);
8003b6c3722Schristos 	if(line == e) {
8013b6c3722Schristos 		*ret = -1; /* parse error */
8023b6c3722Schristos 		return 0;
8033b6c3722Schristos 	}
8043b6c3722Schristos 	*ret = 1; /* matched */
8053b6c3722Schristos 	return x;
8063b6c3722Schristos }
8073b6c3722Schristos 
8083b6c3722Schristos /** parse id sequence for anchor */
8093b6c3722Schristos static struct trust_anchor*
parse_id(struct val_anchors * anchors,char * line)8103b6c3722Schristos parse_id(struct val_anchors* anchors, char* line)
8113b6c3722Schristos {
8123b6c3722Schristos 	struct trust_anchor *tp;
8133b6c3722Schristos 	int r;
8143b6c3722Schristos 	uint16_t dclass;
8153b6c3722Schristos 	uint8_t* dname;
8163b6c3722Schristos 	size_t dname_len;
8173b6c3722Schristos 	/* read the owner name */
8183b6c3722Schristos 	char* next = strchr(line, ' ');
8193b6c3722Schristos 	if(!next)
8203b6c3722Schristos 		return NULL;
8213b6c3722Schristos 	next[0] = 0;
8223b6c3722Schristos 	dname = sldns_str2wire_dname(line, &dname_len);
8233b6c3722Schristos 	if(!dname)
8243b6c3722Schristos 		return NULL;
8253b6c3722Schristos 
8263b6c3722Schristos 	/* read the class */
8273b6c3722Schristos 	dclass = parse_int(next+1, &r);
8283b6c3722Schristos 	if(r == -1) {
8293b6c3722Schristos 		free(dname);
8303b6c3722Schristos 		return NULL;
8313b6c3722Schristos 	}
8323b6c3722Schristos 
8333b6c3722Schristos 	/* find the trust point */
8343b6c3722Schristos 	tp = autr_tp_create(anchors, dname, dname_len, dclass);
8353b6c3722Schristos 	free(dname);
8363b6c3722Schristos 	return tp;
8373b6c3722Schristos }
8383b6c3722Schristos 
8393b6c3722Schristos /**
8403b6c3722Schristos  * Parse variable from trustanchor header
8413b6c3722Schristos  * @param line: to parse
8423b6c3722Schristos  * @param anchors: the anchor is added to this, if "id:" is seen.
8433b6c3722Schristos  * @param anchor: the anchor as result value or previously returned anchor
8443b6c3722Schristos  * 	value to read the variable lines into.
8453b6c3722Schristos  * @return: 0 no match, -1 failed syntax error, +1 success line read.
8463b6c3722Schristos  * 	+2 revoked trust anchor file.
8473b6c3722Schristos  */
8483b6c3722Schristos static int
parse_var_line(char * line,struct val_anchors * anchors,struct trust_anchor ** anchor)8493b6c3722Schristos parse_var_line(char* line, struct val_anchors* anchors,
8503b6c3722Schristos 	struct trust_anchor** anchor)
8513b6c3722Schristos {
8523b6c3722Schristos 	struct trust_anchor* tp = *anchor;
8533b6c3722Schristos 	int r = 0;
8543b6c3722Schristos 	if(strncmp(line, ";;id: ", 6) == 0) {
8553b6c3722Schristos 		*anchor = parse_id(anchors, line+6);
8563b6c3722Schristos 		if(!*anchor) return -1;
8573b6c3722Schristos 		else return 1;
8583b6c3722Schristos 	} else if(strncmp(line, ";;REVOKED", 9) == 0) {
8593b6c3722Schristos 		if(tp) {
8603b6c3722Schristos 			log_err("REVOKED statement must be at start of file");
8613b6c3722Schristos 			return -1;
8623b6c3722Schristos 		}
8633b6c3722Schristos 		return 2;
8643b6c3722Schristos 	} else if(strncmp(line, ";;last_queried: ", 16) == 0) {
8653b6c3722Schristos 		if(!tp) return -1;
8663b6c3722Schristos 		lock_basic_lock(&tp->lock);
8673b6c3722Schristos 		tp->autr->last_queried = (time_t)parse_int(line+16, &r);
8683b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8693b6c3722Schristos 	} else if(strncmp(line, ";;last_success: ", 16) == 0) {
8703b6c3722Schristos 		if(!tp) return -1;
8713b6c3722Schristos 		lock_basic_lock(&tp->lock);
8723b6c3722Schristos 		tp->autr->last_success = (time_t)parse_int(line+16, &r);
8733b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8743b6c3722Schristos 	} else if(strncmp(line, ";;next_probe_time: ", 19) == 0) {
8753b6c3722Schristos 		if(!tp) return -1;
8763b6c3722Schristos 		lock_basic_lock(&anchors->lock);
8773b6c3722Schristos 		lock_basic_lock(&tp->lock);
8783b6c3722Schristos 		(void)rbtree_delete(&anchors->autr->probe, tp);
8793b6c3722Schristos 		tp->autr->next_probe_time = (time_t)parse_int(line+19, &r);
8803b6c3722Schristos 		(void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode);
8813b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8823b6c3722Schristos 		lock_basic_unlock(&anchors->lock);
8833b6c3722Schristos 	} else if(strncmp(line, ";;query_failed: ", 16) == 0) {
8843b6c3722Schristos 		if(!tp) return -1;
8853b6c3722Schristos 		lock_basic_lock(&tp->lock);
8863b6c3722Schristos 		tp->autr->query_failed = (uint8_t)parse_int(line+16, &r);
8873b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8883b6c3722Schristos 	} else if(strncmp(line, ";;query_interval: ", 18) == 0) {
8893b6c3722Schristos 		if(!tp) return -1;
8903b6c3722Schristos 		lock_basic_lock(&tp->lock);
8913b6c3722Schristos 		tp->autr->query_interval = (time_t)parse_int(line+18, &r);
8923b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8933b6c3722Schristos 	} else if(strncmp(line, ";;retry_time: ", 14) == 0) {
8943b6c3722Schristos 		if(!tp) return -1;
8953b6c3722Schristos 		lock_basic_lock(&tp->lock);
8963b6c3722Schristos 		tp->autr->retry_time = (time_t)parse_int(line+14, &r);
8973b6c3722Schristos 		lock_basic_unlock(&tp->lock);
8983b6c3722Schristos 	}
8993b6c3722Schristos 	return r;
9003b6c3722Schristos }
9013b6c3722Schristos 
9023b6c3722Schristos /** handle origin lines */
9033b6c3722Schristos static int
handle_origin(char * line,uint8_t ** origin,size_t * origin_len)9043b6c3722Schristos handle_origin(char* line, uint8_t** origin, size_t* origin_len)
9053b6c3722Schristos {
9063b6c3722Schristos 	size_t len = 0;
9073b6c3722Schristos 	while(isspace((unsigned char)*line))
9083b6c3722Schristos 		line++;
9093b6c3722Schristos 	if(strncmp(line, "$ORIGIN", 7) != 0)
9103b6c3722Schristos 		return 0;
9113b6c3722Schristos 	free(*origin);
9123b6c3722Schristos 	line += 7;
9133b6c3722Schristos 	while(isspace((unsigned char)*line))
9143b6c3722Schristos 		line++;
9153b6c3722Schristos 	*origin = sldns_str2wire_dname(line, &len);
9163b6c3722Schristos 	*origin_len = len;
9173b6c3722Schristos 	if(!*origin)
9183b6c3722Schristos 		log_warn("malloc failure or parse error in $ORIGIN");
9193b6c3722Schristos 	return 1;
9203b6c3722Schristos }
9213b6c3722Schristos 
9223b6c3722Schristos /** Read one line and put multiline RRs onto one line string */
9233b6c3722Schristos static int
read_multiline(char * buf,size_t len,FILE * in,int * linenr)9243b6c3722Schristos read_multiline(char* buf, size_t len, FILE* in, int* linenr)
9253b6c3722Schristos {
9263b6c3722Schristos 	char* pos = buf;
9273b6c3722Schristos 	size_t left = len;
9283b6c3722Schristos 	int depth = 0;
9293b6c3722Schristos 	buf[len-1] = 0;
9303b6c3722Schristos 	while(left > 0 && fgets(pos, (int)left, in) != NULL) {
9313b6c3722Schristos 		size_t i, poslen = strlen(pos);
9323b6c3722Schristos 		(*linenr)++;
9333b6c3722Schristos 
9343b6c3722Schristos 		/* check what the new depth is after the line */
9353b6c3722Schristos 		/* this routine cannot handle braces inside quotes,
9363b6c3722Schristos 		   say for TXT records, but this routine only has to read keys */
9373b6c3722Schristos 		for(i=0; i<poslen; i++) {
9383b6c3722Schristos 			if(pos[i] == '(') {
9393b6c3722Schristos 				depth++;
9403b6c3722Schristos 			} else if(pos[i] == ')') {
9413b6c3722Schristos 				if(depth == 0) {
9423b6c3722Schristos 					log_err("mismatch: too many ')'");
9433b6c3722Schristos 					return -1;
9443b6c3722Schristos 				}
9453b6c3722Schristos 				depth--;
9463b6c3722Schristos 			} else if(pos[i] == ';') {
9473b6c3722Schristos 				break;
9483b6c3722Schristos 			}
9493b6c3722Schristos 		}
9503b6c3722Schristos 
9513b6c3722Schristos 		/* normal oneline or last line: keeps newline and comments */
9523b6c3722Schristos 		if(depth == 0) {
9533b6c3722Schristos 			return 1;
9543b6c3722Schristos 		}
9553b6c3722Schristos 
9563b6c3722Schristos 		/* more lines expected, snip off comments and newline */
9573b6c3722Schristos 		if(poslen>0)
9583b6c3722Schristos 			pos[poslen-1] = 0; /* strip newline */
9593b6c3722Schristos 		if(strchr(pos, ';'))
9603b6c3722Schristos 			strchr(pos, ';')[0] = 0; /* strip comments */
9613b6c3722Schristos 
9623b6c3722Schristos 		/* move to paste other lines behind this one */
9633b6c3722Schristos 		poslen = strlen(pos);
9643b6c3722Schristos 		pos += poslen;
9653b6c3722Schristos 		left -= poslen;
9663b6c3722Schristos 		/* the newline is changed into a space */
9673b6c3722Schristos 		if(left <= 2 /* space and eos */) {
9683b6c3722Schristos 			log_err("line too long");
9693b6c3722Schristos 			return -1;
9703b6c3722Schristos 		}
9713b6c3722Schristos 		pos[0] = ' ';
9723b6c3722Schristos 		pos[1] = 0;
9733b6c3722Schristos 		pos += 1;
9743b6c3722Schristos 		left -= 1;
9753b6c3722Schristos 	}
9763b6c3722Schristos 	if(depth != 0) {
9773b6c3722Schristos 		log_err("mismatch: too many '('");
9783b6c3722Schristos 		return -1;
9793b6c3722Schristos 	}
9803b6c3722Schristos 	if(pos != buf)
9813b6c3722Schristos 		return 1;
9823b6c3722Schristos 	return 0;
9833b6c3722Schristos }
9843b6c3722Schristos 
autr_read_file(struct val_anchors * anchors,const char * nm)9853b6c3722Schristos int autr_read_file(struct val_anchors* anchors, const char* nm)
9863b6c3722Schristos {
9873b6c3722Schristos         /* the file descriptor */
9883b6c3722Schristos         FILE* fd;
9893b6c3722Schristos         /* keep track of line numbers */
9903b6c3722Schristos         int line_nr = 0;
9913b6c3722Schristos         /* single line */
9923b6c3722Schristos         char line[10240];
9933b6c3722Schristos 	/* trust point being read */
9943b6c3722Schristos 	struct trust_anchor *tp = NULL, *tp2;
9953b6c3722Schristos 	int r;
9963b6c3722Schristos 	/* for $ORIGIN parsing */
9973b6c3722Schristos 	uint8_t *origin=NULL, *prev=NULL;
9983b6c3722Schristos 	size_t origin_len=0, prev_len=0;
9993b6c3722Schristos 
10003b6c3722Schristos         if (!(fd = fopen(nm, "r"))) {
10013b6c3722Schristos                 log_err("unable to open %s for reading: %s",
10023b6c3722Schristos 			nm, strerror(errno));
10033b6c3722Schristos                 return 0;
10043b6c3722Schristos         }
10053b6c3722Schristos         verbose(VERB_ALGO, "reading autotrust anchor file %s", nm);
10063b6c3722Schristos         while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) {
10073b6c3722Schristos 		if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) {
10083b6c3722Schristos 			log_err("could not parse auto-trust-anchor-file "
10093b6c3722Schristos 				"%s line %d", nm, line_nr);
10103b6c3722Schristos 			fclose(fd);
10113b6c3722Schristos 			free(origin);
10123b6c3722Schristos 			free(prev);
10133b6c3722Schristos 			return 0;
10143b6c3722Schristos 		} else if(r == 1) {
10153b6c3722Schristos 			continue;
10163b6c3722Schristos 		} else if(r == 2) {
10173b6c3722Schristos 			log_warn("trust anchor %s has been revoked", nm);
10183b6c3722Schristos 			fclose(fd);
10193b6c3722Schristos 			free(origin);
10203b6c3722Schristos 			free(prev);
10213b6c3722Schristos 			return 1;
10223b6c3722Schristos 		}
10233b6c3722Schristos         	if (!str_contains_data(line, ';'))
10243b6c3722Schristos                 	continue; /* empty lines allowed */
10253b6c3722Schristos  		if(handle_origin(line, &origin, &origin_len))
10263b6c3722Schristos 			continue;
10273b6c3722Schristos 		r = 0;
10283b6c3722Schristos                 if(!(tp2=load_trustanchor(anchors, line, nm, origin,
10293b6c3722Schristos 			origin_len, &prev, &prev_len, &r))) {
10303b6c3722Schristos 			if(!r) log_err("failed to load trust anchor from %s "
10313b6c3722Schristos 				"at line %i, skipping", nm, line_nr);
10323b6c3722Schristos                         /* try to do the rest */
10333b6c3722Schristos 			continue;
10343b6c3722Schristos                 }
10353b6c3722Schristos 		if(tp && tp != tp2) {
10363b6c3722Schristos 			log_err("file %s has mismatching data inside: "
10373b6c3722Schristos 				"the file may only contain keys for one name, "
10383b6c3722Schristos 				"remove keys for other domain names", nm);
10393b6c3722Schristos         		fclose(fd);
10403b6c3722Schristos 			free(origin);
10413b6c3722Schristos 			free(prev);
10423b6c3722Schristos 			return 0;
10433b6c3722Schristos 		}
10443b6c3722Schristos 		tp = tp2;
10453b6c3722Schristos         }
10463b6c3722Schristos         fclose(fd);
10473b6c3722Schristos 	free(origin);
10483b6c3722Schristos 	free(prev);
10493b6c3722Schristos 	if(!tp) {
10503b6c3722Schristos 		log_err("failed to read %s", nm);
10513b6c3722Schristos 		return 0;
10523b6c3722Schristos 	}
10533b6c3722Schristos 
10543b6c3722Schristos 	/* now assemble the data into DNSKEY and DS packed rrsets */
10553b6c3722Schristos 	lock_basic_lock(&tp->lock);
10563b6c3722Schristos 	if(!autr_assemble(tp)) {
10573b6c3722Schristos 		lock_basic_unlock(&tp->lock);
10583b6c3722Schristos 		log_err("malloc failure assembling %s", nm);
10593b6c3722Schristos 		return 0;
10603b6c3722Schristos 	}
10613b6c3722Schristos 	lock_basic_unlock(&tp->lock);
10623b6c3722Schristos 	return 1;
10633b6c3722Schristos }
10643b6c3722Schristos 
10653b6c3722Schristos /** string for a trustanchor state */
10663b6c3722Schristos static const char*
trustanchor_state2str(autr_state_type s)10670cd9f4ecSchristos trustanchor_state2str(autr_state_type s)
10683b6c3722Schristos {
10693b6c3722Schristos         switch (s) {
10703b6c3722Schristos                 case AUTR_STATE_START:       return "  START  ";
10713b6c3722Schristos                 case AUTR_STATE_ADDPEND:     return " ADDPEND ";
10723b6c3722Schristos                 case AUTR_STATE_VALID:       return "  VALID  ";
10733b6c3722Schristos                 case AUTR_STATE_MISSING:     return " MISSING ";
10743b6c3722Schristos                 case AUTR_STATE_REVOKED:     return " REVOKED ";
10753b6c3722Schristos                 case AUTR_STATE_REMOVED:     return " REMOVED ";
10763b6c3722Schristos         }
10773b6c3722Schristos         return " UNKNOWN ";
10783b6c3722Schristos }
10793b6c3722Schristos 
10807a540f2bSchristos /** ctime r for autotrust */
autr_ctime_r(time_t * t,char * s)10817a540f2bSchristos static char* autr_ctime_r(time_t* t, char* s)
10827a540f2bSchristos {
10837a540f2bSchristos 	ctime_r(t, s);
10847a540f2bSchristos #ifdef USE_WINSOCK
10857a540f2bSchristos 	if(strlen(s) > 10 && s[7]==' ' && s[8]=='0')
10867a540f2bSchristos 		s[8]=' '; /* fix error in windows ctime */
10877a540f2bSchristos #endif
10887a540f2bSchristos 	return s;
10897a540f2bSchristos }
10907a540f2bSchristos 
10913b6c3722Schristos /** print ID to file */
10923b6c3722Schristos static int
print_id(FILE * out,char * fname,uint8_t * nm,size_t nmlen,uint16_t dclass)10933b6c3722Schristos print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass)
10943b6c3722Schristos {
10953b6c3722Schristos 	char* s = sldns_wire2str_dname(nm, nmlen);
10963b6c3722Schristos 	if(!s) {
10973b6c3722Schristos 		log_err("malloc failure in write to %s", fname);
10983b6c3722Schristos 		return 0;
10993b6c3722Schristos 	}
11003b6c3722Schristos 	if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) {
11013b6c3722Schristos 		log_err("could not write to %s: %s", fname, strerror(errno));
11023b6c3722Schristos 		free(s);
11033b6c3722Schristos 		return 0;
11043b6c3722Schristos 	}
11053b6c3722Schristos 	free(s);
11063b6c3722Schristos 	return 1;
11073b6c3722Schristos }
11083b6c3722Schristos 
11093b6c3722Schristos static int
autr_write_contents(FILE * out,char * fn,struct trust_anchor * tp)11103b6c3722Schristos autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp)
11113b6c3722Schristos {
11123b6c3722Schristos 	char tmi[32];
11133b6c3722Schristos 	struct autr_ta* ta;
11143b6c3722Schristos 	char* str;
11153b6c3722Schristos 
11163b6c3722Schristos 	/* write pretty header */
11173b6c3722Schristos 	if(fprintf(out, "; autotrust trust anchor file\n") < 0) {
11183b6c3722Schristos 		log_err("could not write to %s: %s", fn, strerror(errno));
11193b6c3722Schristos 		return 0;
11203b6c3722Schristos 	}
11213b6c3722Schristos 	if(tp->autr->revoked) {
11223b6c3722Schristos 		if(fprintf(out, ";;REVOKED\n") < 0 ||
11233b6c3722Schristos 		   fprintf(out, "; The zone has all keys revoked, and is\n"
11243b6c3722Schristos 			"; considered as if it has no trust anchors.\n"
11253b6c3722Schristos 			"; the remainder of the file is the last probe.\n"
11263b6c3722Schristos 			"; to restart the trust anchor, overwrite this file.\n"
11273b6c3722Schristos 			"; with one containing valid DNSKEYs or DSes.\n") < 0) {
11283b6c3722Schristos 		   log_err("could not write to %s: %s", fn, strerror(errno));
11293b6c3722Schristos 		   return 0;
11303b6c3722Schristos 		}
11313b6c3722Schristos 	}
11323b6c3722Schristos 	if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) {
11333b6c3722Schristos 		return 0;
11343b6c3722Schristos 	}
11353b6c3722Schristos 	if(fprintf(out, ";;last_queried: %u ;;%s",
11363b6c3722Schristos 		(unsigned int)tp->autr->last_queried,
11377a540f2bSchristos 		autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
11383b6c3722Schristos 	   fprintf(out, ";;last_success: %u ;;%s",
11393b6c3722Schristos 		(unsigned int)tp->autr->last_success,
11407a540f2bSchristos 		autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
11413b6c3722Schristos 	   fprintf(out, ";;next_probe_time: %u ;;%s",
11423b6c3722Schristos 		(unsigned int)tp->autr->next_probe_time,
11437a540f2bSchristos 		autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
11443b6c3722Schristos 	   fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0
11453b6c3722Schristos 	   || fprintf(out, ";;query_interval: %d\n",
11463b6c3722Schristos 	   (int)tp->autr->query_interval) < 0 ||
11473b6c3722Schristos 	   fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) {
11483b6c3722Schristos 		log_err("could not write to %s: %s", fn, strerror(errno));
11493b6c3722Schristos 		return 0;
11503b6c3722Schristos 	}
11513b6c3722Schristos 
11523b6c3722Schristos 	/* write anchors */
11533b6c3722Schristos 	for(ta=tp->autr->keys; ta; ta=ta->next) {
11543b6c3722Schristos 		/* by default do not store START and REMOVED keys */
11553b6c3722Schristos 		if(ta->s == AUTR_STATE_START)
11563b6c3722Schristos 			continue;
11573b6c3722Schristos 		if(ta->s == AUTR_STATE_REMOVED)
11583b6c3722Schristos 			continue;
11593b6c3722Schristos 		/* only store keys */
11603b6c3722Schristos 		if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len)
11613b6c3722Schristos 			!= LDNS_RR_TYPE_DNSKEY)
11623b6c3722Schristos 			continue;
11633b6c3722Schristos 		str = sldns_wire2str_rr(ta->rr, ta->rr_len);
11643b6c3722Schristos 		if(!str || !str[0]) {
11653b6c3722Schristos 			free(str);
11663b6c3722Schristos 			log_err("malloc failure writing %s", fn);
11673b6c3722Schristos 			return 0;
11683b6c3722Schristos 		}
11693b6c3722Schristos 		str[strlen(str)-1] = 0; /* remove newline */
11703b6c3722Schristos 		if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d "
11713b6c3722Schristos 			";;lastchange=%u ;;%s", str, (int)ta->s,
11723b6c3722Schristos 			trustanchor_state2str(ta->s), (int)ta->pending_count,
11733b6c3722Schristos 			(unsigned int)ta->last_change,
11747a540f2bSchristos 			autr_ctime_r(&(ta->last_change), tmi)) < 0) {
11753b6c3722Schristos 		   log_err("could not write to %s: %s", fn, strerror(errno));
11763b6c3722Schristos 		   free(str);
11773b6c3722Schristos 		   return 0;
11783b6c3722Schristos 		}
11793b6c3722Schristos 		free(str);
11803b6c3722Schristos 	}
11813b6c3722Schristos 	return 1;
11823b6c3722Schristos }
11833b6c3722Schristos 
autr_write_file(struct module_env * env,struct trust_anchor * tp)11843b6c3722Schristos void autr_write_file(struct module_env* env, struct trust_anchor* tp)
11853b6c3722Schristos {
11863b6c3722Schristos 	FILE* out;
11873b6c3722Schristos 	char* fname = tp->autr->file;
118801049ae6Schristos #ifndef S_SPLINT_S
118901049ae6Schristos 	long long llvalue;
119001049ae6Schristos #endif
11913b6c3722Schristos 	char tempf[2048];
11923b6c3722Schristos 	log_assert(tp->autr);
11933b6c3722Schristos 	if(!env) {
11943b6c3722Schristos 		log_err("autr_write_file: Module environment is NULL.");
11953b6c3722Schristos 		return;
11963b6c3722Schristos 	}
119701049ae6Schristos 	/* unique name with pid number, thread number, and struct pointer
119801049ae6Schristos 	 * (the pointer uniquifies for multiple libunbound contexts) */
119901049ae6Schristos #ifndef S_SPLINT_S
120001049ae6Schristos #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX)
120101049ae6Schristos 	/* avoid warning about upcast on 32bit systems */
120201049ae6Schristos 	llvalue = (unsigned long)tp;
120301049ae6Schristos #else
120401049ae6Schristos 	llvalue = (unsigned long long)tp;
120501049ae6Schristos #endif
12067a540f2bSchristos 	snprintf(tempf, sizeof(tempf), "%s.%d-%d-" ARG_LL "x", fname, (int)getpid(),
120701049ae6Schristos 		env->worker?*(int*)env->worker:0, llvalue);
120801049ae6Schristos #endif /* S_SPLINT_S */
12093b6c3722Schristos 	verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf);
12103b6c3722Schristos 	out = fopen(tempf, "w");
12113b6c3722Schristos 	if(!out) {
12123b6c3722Schristos 		fatal_exit("could not open autotrust file for writing, %s: %s",
12133b6c3722Schristos 			tempf, strerror(errno));
12143b6c3722Schristos 		return;
12153b6c3722Schristos 	}
12163b6c3722Schristos 	if(!autr_write_contents(out, tempf, tp)) {
12173b6c3722Schristos 		/* failed to write contents (completely) */
12183b6c3722Schristos 		fclose(out);
12193b6c3722Schristos 		unlink(tempf);
12203b6c3722Schristos 		fatal_exit("could not completely write: %s", fname);
12213b6c3722Schristos 		return;
12223b6c3722Schristos 	}
12233b6c3722Schristos 	if(fflush(out) != 0)
12243b6c3722Schristos 		log_err("could not fflush(%s): %s", fname, strerror(errno));
12253b6c3722Schristos #ifdef HAVE_FSYNC
12263b6c3722Schristos 	if(fsync(fileno(out)) != 0)
12273b6c3722Schristos 		log_err("could not fsync(%s): %s", fname, strerror(errno));
12283b6c3722Schristos #else
12290cd9f4ecSchristos 	FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
12303b6c3722Schristos #endif
12313b6c3722Schristos 	if(fclose(out) != 0) {
12323b6c3722Schristos 		fatal_exit("could not complete write: %s: %s",
12333b6c3722Schristos 			fname, strerror(errno));
12343b6c3722Schristos 		unlink(tempf);
12353b6c3722Schristos 		return;
12363b6c3722Schristos 	}
12373b6c3722Schristos 	/* success; overwrite actual file */
12383b6c3722Schristos 	verbose(VERB_ALGO, "autotrust: replaced %s", fname);
12393b6c3722Schristos #ifdef UB_ON_WINDOWS
12403b6c3722Schristos 	(void)unlink(fname); /* windows does not replace file with rename() */
12413b6c3722Schristos #endif
12423b6c3722Schristos 	if(rename(tempf, fname) < 0) {
12433b6c3722Schristos 		fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno));
12443b6c3722Schristos 	}
12453b6c3722Schristos }
12463b6c3722Schristos 
12473b6c3722Schristos /**
12483b6c3722Schristos  * Verify if dnskey works for trust point
12493b6c3722Schristos  * @param env: environment (with time) for verification
12503b6c3722Schristos  * @param ve: validator environment (with options) for verification.
12513b6c3722Schristos  * @param tp: trust point to verify with
12523b6c3722Schristos  * @param rrset: DNSKEY rrset to verify.
12530cd9f4ecSchristos  * @param qstate: qstate with region.
12543b6c3722Schristos  * @return false on failure, true if verification successful.
12553b6c3722Schristos  */
12563b6c3722Schristos static int
verify_dnskey(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * rrset,struct module_qstate * qstate)12573b6c3722Schristos verify_dnskey(struct module_env* env, struct val_env* ve,
12580cd9f4ecSchristos         struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
12590cd9f4ecSchristos 	struct module_qstate* qstate)
12603b6c3722Schristos {
12613b6c3722Schristos 	char* reason = NULL;
12623b6c3722Schristos 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
12633b6c3722Schristos 	int downprot = env->cfg->harden_algo_downgrade;
12643b6c3722Schristos 	enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
12650cd9f4ecSchristos 		tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
12667a540f2bSchristos 		NULL, qstate);
12673b6c3722Schristos 	/* sigalg is ignored, it returns algorithms signalled to exist, but
12683b6c3722Schristos 	 * in 5011 there are no other rrsets to check.  if downprot is
12693b6c3722Schristos 	 * enabled, then it checks that the DNSKEY is signed with all
12703b6c3722Schristos 	 * algorithms available in the trust store. */
12713b6c3722Schristos 	verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
12723b6c3722Schristos 		sec_status_to_string(sec));
12733b6c3722Schristos 	return sec == sec_status_secure;
12743b6c3722Schristos }
12753b6c3722Schristos 
12763b6c3722Schristos static int32_t
rrsig_get_expiry(uint8_t * d,size_t len)12773b6c3722Schristos rrsig_get_expiry(uint8_t* d, size_t len)
12783b6c3722Schristos {
12793b6c3722Schristos 	/* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */
12803b6c3722Schristos 	if(len < 2+8+4)
12813b6c3722Schristos 		return 0;
12823b6c3722Schristos 	return sldns_read_uint32(d+2+8);
12833b6c3722Schristos }
12843b6c3722Schristos 
12853b6c3722Schristos /** Find minimum expiration interval from signatures */
12863b6c3722Schristos static time_t
min_expiry(struct module_env * env,struct packed_rrset_data * dd)12873b6c3722Schristos min_expiry(struct module_env* env, struct packed_rrset_data* dd)
12883b6c3722Schristos {
12893b6c3722Schristos 	size_t i;
12903b6c3722Schristos 	int32_t t, r = 15 * 24 * 3600; /* 15 days max */
12913b6c3722Schristos 	for(i=dd->count; i<dd->count+dd->rrsig_count; i++) {
12923b6c3722Schristos 		t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]);
12933b6c3722Schristos 		if((int32_t)t - (int32_t)*env->now > 0) {
12943b6c3722Schristos 			t -= (int32_t)*env->now;
12953b6c3722Schristos 			if(t < r)
12963b6c3722Schristos 				r = t;
12973b6c3722Schristos 		}
12983b6c3722Schristos 	}
12993b6c3722Schristos 	return (time_t)r;
13003b6c3722Schristos }
13013b6c3722Schristos 
13023b6c3722Schristos /** Is rr self-signed revoked key */
13033b6c3722Schristos static int
rr_is_selfsigned_revoked(struct module_env * env,struct val_env * ve,struct ub_packed_rrset_key * dnskey_rrset,size_t i,struct module_qstate * qstate)13043b6c3722Schristos rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
13050cd9f4ecSchristos 	struct ub_packed_rrset_key* dnskey_rrset, size_t i,
13060cd9f4ecSchristos 	struct module_qstate* qstate)
13073b6c3722Schristos {
13083b6c3722Schristos 	enum sec_status sec;
13093b6c3722Schristos 	char* reason = NULL;
13103b6c3722Schristos 	verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
13113b6c3722Schristos 		(int)i);
13123b6c3722Schristos 	/* no algorithm downgrade protection necessary, if it is selfsigned
13133b6c3722Schristos 	 * revoked it can be removed. */
13143b6c3722Schristos 	sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
13157a540f2bSchristos 		&reason, NULL, LDNS_SECTION_ANSWER, qstate);
13163b6c3722Schristos 	return (sec == sec_status_secure);
13173b6c3722Schristos }
13183b6c3722Schristos 
13193b6c3722Schristos /** Set fetched value */
13203b6c3722Schristos static void
seen_trustanchor(struct autr_ta * ta,uint8_t seen)13213b6c3722Schristos seen_trustanchor(struct autr_ta* ta, uint8_t seen)
13223b6c3722Schristos {
13233b6c3722Schristos 	ta->fetched = seen;
13243b6c3722Schristos 	if(ta->pending_count < 250) /* no numerical overflow, please */
13253b6c3722Schristos 		ta->pending_count++;
13263b6c3722Schristos }
13273b6c3722Schristos 
13283b6c3722Schristos /** set revoked value */
13293b6c3722Schristos static void
seen_revoked_trustanchor(struct autr_ta * ta,uint8_t revoked)13303b6c3722Schristos seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked)
13313b6c3722Schristos {
13323b6c3722Schristos 	ta->revoked = revoked;
13333b6c3722Schristos }
13343b6c3722Schristos 
13353b6c3722Schristos /** revoke a trust anchor */
13363b6c3722Schristos static void
revoke_dnskey(struct autr_ta * ta,int off)13373b6c3722Schristos revoke_dnskey(struct autr_ta* ta, int off)
13383b6c3722Schristos {
13393b6c3722Schristos 	uint16_t flags;
13403b6c3722Schristos 	uint8_t* data;
13413b6c3722Schristos 	if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) !=
13423b6c3722Schristos 		LDNS_RR_TYPE_DNSKEY)
13433b6c3722Schristos 		return;
13443b6c3722Schristos 	if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2)
13453b6c3722Schristos 		return;
13463b6c3722Schristos 	data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len);
13473b6c3722Schristos 	flags = sldns_read_uint16(data);
13483b6c3722Schristos 	if (off && (flags&LDNS_KEY_REVOKE_KEY))
13493b6c3722Schristos 		flags ^= LDNS_KEY_REVOKE_KEY; /* flip */
13503b6c3722Schristos 	else
13513b6c3722Schristos 		flags |= LDNS_KEY_REVOKE_KEY;
13523b6c3722Schristos 	sldns_write_uint16(data, flags);
13533b6c3722Schristos }
13543b6c3722Schristos 
13553b6c3722Schristos /** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */
13563b6c3722Schristos static int
dnskey_compare_skip_revbit(uint8_t * a,size_t a_len,uint8_t * b,size_t b_len)13573b6c3722Schristos dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len)
13583b6c3722Schristos {
13593b6c3722Schristos 	size_t i;
13603b6c3722Schristos 	if(a_len != b_len)
13613b6c3722Schristos 		return -1;
13623b6c3722Schristos 	/* compare RRs RDATA byte for byte. */
13633b6c3722Schristos 	for(i = 0; i < a_len; i++)
13643b6c3722Schristos 	{
13653b6c3722Schristos 		uint8_t rdf1, rdf2;
13663b6c3722Schristos 		rdf1 = a[i];
13673b6c3722Schristos 		rdf2 = b[i];
13683b6c3722Schristos 		if(i==1) {
13693b6c3722Schristos 			/* this is the second part of the flags field */
13703b6c3722Schristos 			rdf1 |= LDNS_KEY_REVOKE_KEY;
13713b6c3722Schristos 			rdf2 |= LDNS_KEY_REVOKE_KEY;
13723b6c3722Schristos 		}
13733b6c3722Schristos 		if (rdf1 < rdf2)	return -1;
13743b6c3722Schristos 		else if (rdf1 > rdf2)	return 1;
13753b6c3722Schristos         }
13763b6c3722Schristos 	return 0;
13773b6c3722Schristos }
13783b6c3722Schristos 
13793b6c3722Schristos 
13803b6c3722Schristos /** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */
13813b6c3722Schristos static int
ta_compare(struct autr_ta * a,uint16_t t,uint8_t * b,size_t b_len)13823b6c3722Schristos ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len)
13833b6c3722Schristos {
13843b6c3722Schristos 	if(!a) return -1;
13853b6c3722Schristos 	else if(!b) return -1;
13863b6c3722Schristos 	else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t)
13873b6c3722Schristos 		return (int)sldns_wirerr_get_type(a->rr, a->rr_len,
13883b6c3722Schristos 			a->dname_len) - (int)t;
13893b6c3722Schristos 	else if(t == LDNS_RR_TYPE_DNSKEY) {
13903b6c3722Schristos 		return dnskey_compare_skip_revbit(
13913b6c3722Schristos 			sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len),
13923b6c3722Schristos 			sldns_wirerr_get_rdatalen(a->rr, a->rr_len,
13933b6c3722Schristos 			a->dname_len), b, b_len);
13943b6c3722Schristos 	}
13953b6c3722Schristos 	else if(t == LDNS_RR_TYPE_DS) {
13963b6c3722Schristos 		if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) !=
13973b6c3722Schristos 			b_len)
13983b6c3722Schristos 			return -1;
13993b6c3722Schristos 		return memcmp(sldns_wirerr_get_rdata(a->rr,
14003b6c3722Schristos 			a->rr_len, a->dname_len), b, b_len);
14013b6c3722Schristos 	}
14023b6c3722Schristos 	return -1;
14033b6c3722Schristos }
14043b6c3722Schristos 
14053b6c3722Schristos /**
14063b6c3722Schristos  * Find key
14073b6c3722Schristos  * @param tp: to search in
14083b6c3722Schristos  * @param t: rr type of the rdata.
14093b6c3722Schristos  * @param rdata: to look for  (no rdatalen in it)
14103b6c3722Schristos  * @param rdata_len: length of rdata
14113b6c3722Schristos  * @param result: returns NULL or the ta key looked for.
14123b6c3722Schristos  * @return false on malloc failure during search. if true examine result.
14133b6c3722Schristos  */
14143b6c3722Schristos static int
find_key(struct trust_anchor * tp,uint16_t t,uint8_t * rdata,size_t rdata_len,struct autr_ta ** result)14153b6c3722Schristos find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len,
14163b6c3722Schristos 	struct autr_ta** result)
14173b6c3722Schristos {
14183b6c3722Schristos 	struct autr_ta* ta;
14193b6c3722Schristos 	if(!tp || !rdata) {
14203b6c3722Schristos 		*result = NULL;
14213b6c3722Schristos 		return 0;
14223b6c3722Schristos 	}
14233b6c3722Schristos 	for(ta=tp->autr->keys; ta; ta=ta->next) {
14243b6c3722Schristos 		if(ta_compare(ta, t, rdata, rdata_len) == 0) {
14253b6c3722Schristos 			*result = ta;
14263b6c3722Schristos 			return 1;
14273b6c3722Schristos 		}
14283b6c3722Schristos 	}
14293b6c3722Schristos 	*result = NULL;
14303b6c3722Schristos 	return 1;
14313b6c3722Schristos }
14323b6c3722Schristos 
14333b6c3722Schristos /** add key and clone RR and tp already locked. rdata without rdlen. */
14343b6c3722Schristos static struct autr_ta*
add_key(struct trust_anchor * tp,uint32_t ttl,uint8_t * rdata,size_t rdata_len)14353b6c3722Schristos add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
14363b6c3722Schristos {
14373b6c3722Schristos 	struct autr_ta* ta;
14383b6c3722Schristos 	uint8_t* rr;
14393b6c3722Schristos 	size_t rr_len, dname_len;
14403b6c3722Schristos 	uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY);
14413b6c3722Schristos 	uint16_t rrclass = htons(LDNS_RR_CLASS_IN);
14423b6c3722Schristos 	uint16_t rdlen = htons(rdata_len);
14433b6c3722Schristos 	dname_len = tp->namelen;
14443b6c3722Schristos 	ttl = htonl(ttl);
14453b6c3722Schristos 	rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len;
14463b6c3722Schristos 	rr = (uint8_t*)malloc(rr_len);
14473b6c3722Schristos 	if(!rr) return NULL;
14483b6c3722Schristos 	memmove(rr, tp->name, tp->namelen);
14493b6c3722Schristos 	memmove(rr+dname_len, &rrtype, 2);
14503b6c3722Schristos 	memmove(rr+dname_len+2, &rrclass, 2);
14513b6c3722Schristos 	memmove(rr+dname_len+4, &ttl, 4);
14523b6c3722Schristos 	memmove(rr+dname_len+8, &rdlen, 2);
14533b6c3722Schristos 	memmove(rr+dname_len+10, rdata, rdata_len);
14543b6c3722Schristos 	ta = autr_ta_create(rr, rr_len, dname_len);
14553b6c3722Schristos 	if(!ta) {
14563b6c3722Schristos 		/* rr freed in autr_ta_create */
14573b6c3722Schristos 		return NULL;
14583b6c3722Schristos 	}
14593b6c3722Schristos 	/* link in, tp already locked */
14603b6c3722Schristos 	ta->next = tp->autr->keys;
14613b6c3722Schristos 	tp->autr->keys = ta;
14623b6c3722Schristos 	return ta;
14633b6c3722Schristos }
14643b6c3722Schristos 
14653b6c3722Schristos /** get TTL from DNSKEY rrset */
14663b6c3722Schristos static time_t
key_ttl(struct ub_packed_rrset_key * k)14673b6c3722Schristos key_ttl(struct ub_packed_rrset_key* k)
14683b6c3722Schristos {
14693b6c3722Schristos 	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
14703b6c3722Schristos 	return d->ttl;
14713b6c3722Schristos }
14723b6c3722Schristos 
14733b6c3722Schristos /** update the time values for the trustpoint */
14743b6c3722Schristos static void
set_tp_times(struct trust_anchor * tp,time_t rrsig_exp_interval,time_t origttl,int * changed)14753b6c3722Schristos set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval,
14763b6c3722Schristos 	time_t origttl, int* changed)
14773b6c3722Schristos {
14783b6c3722Schristos 	time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time;
14793b6c3722Schristos 
14803b6c3722Schristos 	/* x = MIN(15days, ttl/2, expire/2) */
14813b6c3722Schristos 	x = 15 * 24 * 3600;
14823b6c3722Schristos 	if(origttl/2 < x)
14833b6c3722Schristos 		x = origttl/2;
14843b6c3722Schristos 	if(rrsig_exp_interval/2 < x)
14853b6c3722Schristos 		x = rrsig_exp_interval/2;
14863b6c3722Schristos 	/* MAX(1hr, x) */
14873b6c3722Schristos 	if(!autr_permit_small_holddown) {
14883b6c3722Schristos 		if(x < 3600)
14893b6c3722Schristos 			tp->autr->query_interval = 3600;
14903b6c3722Schristos 		else	tp->autr->query_interval = x;
14913b6c3722Schristos 	}	else    tp->autr->query_interval = x;
14923b6c3722Schristos 
14933b6c3722Schristos 	/* x= MIN(1day, ttl/10, expire/10) */
14943b6c3722Schristos 	x = 24 * 3600;
14953b6c3722Schristos 	if(origttl/10 < x)
14963b6c3722Schristos 		x = origttl/10;
14973b6c3722Schristos 	if(rrsig_exp_interval/10 < x)
14983b6c3722Schristos 		x = rrsig_exp_interval/10;
14993b6c3722Schristos 	/* MAX(1hr, x) */
15003b6c3722Schristos 	if(!autr_permit_small_holddown) {
15013b6c3722Schristos 		if(x < 3600)
15023b6c3722Schristos 			tp->autr->retry_time = 3600;
15033b6c3722Schristos 		else	tp->autr->retry_time = x;
15043b6c3722Schristos 	}	else    tp->autr->retry_time = x;
15053b6c3722Schristos 
15063b6c3722Schristos 	if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) {
15073b6c3722Schristos 		*changed = 1;
15083b6c3722Schristos 		verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl);
15093b6c3722Schristos 		verbose(VERB_ALGO, "rrsig_exp_interval is %d",
15103b6c3722Schristos 			(int)rrsig_exp_interval);
15113b6c3722Schristos 		verbose(VERB_ALGO, "query_interval: %d, retry_time: %d",
15123b6c3722Schristos 			(int)tp->autr->query_interval,
15133b6c3722Schristos 			(int)tp->autr->retry_time);
15143b6c3722Schristos 	}
15153b6c3722Schristos }
15163b6c3722Schristos 
15173b6c3722Schristos /** init events to zero */
15183b6c3722Schristos static void
init_events(struct trust_anchor * tp)15193b6c3722Schristos init_events(struct trust_anchor* tp)
15203b6c3722Schristos {
15213b6c3722Schristos 	struct autr_ta* ta;
15223b6c3722Schristos 	for(ta=tp->autr->keys; ta; ta=ta->next) {
15233b6c3722Schristos 		ta->fetched = 0;
15243b6c3722Schristos 	}
15253b6c3722Schristos }
15263b6c3722Schristos 
15273b6c3722Schristos /** check for revoked keys without trusting any other information */
15283b6c3722Schristos static void
check_contains_revoked(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,int * changed,struct module_qstate * qstate)15293b6c3722Schristos check_contains_revoked(struct module_env* env, struct val_env* ve,
15303b6c3722Schristos 	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
15310cd9f4ecSchristos 	int* changed, struct module_qstate* qstate)
15323b6c3722Schristos {
15333b6c3722Schristos 	struct packed_rrset_data* dd = (struct packed_rrset_data*)
15343b6c3722Schristos 		dnskey_rrset->entry.data;
15353b6c3722Schristos 	size_t i;
15363b6c3722Schristos 	log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
15373b6c3722Schristos 	for(i=0; i<dd->count; i++) {
15383b6c3722Schristos 		struct autr_ta* ta = NULL;
15393b6c3722Schristos 		if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
15403b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2) ||
15413b6c3722Schristos 			!rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
15423b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2))
15433b6c3722Schristos 			continue; /* not a revoked KSK */
15443b6c3722Schristos 		if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
15453b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
15463b6c3722Schristos 			log_err("malloc failure");
15473b6c3722Schristos 			continue; /* malloc fail in compare*/
15483b6c3722Schristos 		}
15493b6c3722Schristos 		if(!ta)
15503b6c3722Schristos 			continue; /* key not found */
15510cd9f4ecSchristos 		if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) {
15523b6c3722Schristos 			/* checked if there is an rrsig signed by this key. */
15533b6c3722Schristos 			/* same keytag, but stored can be revoked already, so
15543b6c3722Schristos 			 * compare keytags, with +0 or +128(REVOKE flag) */
15553b6c3722Schristos 			log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 ==
15563b6c3722Schristos 				sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
15573b6c3722Schristos 				ta->rr, ta->rr_len, ta->dname_len),
15583b6c3722Schristos 				sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
15593b6c3722Schristos 				ta->dname_len)) ||
15603b6c3722Schristos 				dnskey_calc_keytag(dnskey_rrset, i) ==
15613b6c3722Schristos 				sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
15623b6c3722Schristos 				ta->rr, ta->rr_len, ta->dname_len),
15633b6c3722Schristos 				sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
15643b6c3722Schristos 				ta->dname_len))); /* checks conversion*/
15653b6c3722Schristos 			verbose_key(ta, VERB_ALGO, "is self-signed revoked");
15663b6c3722Schristos 			if(!ta->revoked)
15673b6c3722Schristos 				*changed = 1;
15683b6c3722Schristos 			seen_revoked_trustanchor(ta, 1);
15693b6c3722Schristos 			do_revoked(env, ta, changed);
15703b6c3722Schristos 		}
15713b6c3722Schristos 	}
15723b6c3722Schristos }
15733b6c3722Schristos 
15743b6c3722Schristos /** See if a DNSKEY is verified by one of the DSes */
15753b6c3722Schristos static int
key_matches_a_ds(struct module_env * env,struct val_env * ve,struct ub_packed_rrset_key * dnskey_rrset,size_t key_idx,struct ub_packed_rrset_key * ds_rrset)15763b6c3722Schristos key_matches_a_ds(struct module_env* env, struct val_env* ve,
15773b6c3722Schristos 	struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx,
15783b6c3722Schristos 	struct ub_packed_rrset_key* ds_rrset)
15793b6c3722Schristos {
15803b6c3722Schristos 	struct packed_rrset_data* dd = (struct packed_rrset_data*)
15813b6c3722Schristos 	                ds_rrset->entry.data;
15823b6c3722Schristos 	size_t ds_idx, num = dd->count;
15833b6c3722Schristos 	int d = val_favorite_ds_algo(ds_rrset);
15843b6c3722Schristos 	char* reason = "";
15853b6c3722Schristos 	for(ds_idx=0; ds_idx<num; ds_idx++) {
15863b6c3722Schristos 		if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) ||
15873b6c3722Schristos 			!ds_key_algo_is_supported(ds_rrset, ds_idx) ||
15887a540f2bSchristos 			!dnskey_size_is_supported(dnskey_rrset, key_idx) ||
15893b6c3722Schristos 			ds_get_digest_algo(ds_rrset, ds_idx) != d)
15903b6c3722Schristos 			continue;
15913b6c3722Schristos 		if(ds_get_key_algo(ds_rrset, ds_idx)
15923b6c3722Schristos 		   != dnskey_get_algo(dnskey_rrset, key_idx)
15933b6c3722Schristos 		   || dnskey_calc_keytag(dnskey_rrset, key_idx)
15943b6c3722Schristos 		   != ds_get_keytag(ds_rrset, ds_idx)) {
15953b6c3722Schristos 			continue;
15963b6c3722Schristos 		}
15973b6c3722Schristos 		if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx,
15983b6c3722Schristos 			ds_rrset, ds_idx)) {
15993b6c3722Schristos 			verbose(VERB_ALGO, "DS match attempt failed");
16003b6c3722Schristos 			continue;
16013b6c3722Schristos 		}
16020cd9f4ecSchristos 		/* match of hash is sufficient for bootstrap of trust point */
16030cd9f4ecSchristos 		(void)reason;
16040cd9f4ecSchristos 		(void)ve;
16050cd9f4ecSchristos 		return 1;
16060cd9f4ecSchristos 		/* no need to check RRSIG, DS hash already matched with source
16073b6c3722Schristos 		if(dnskey_verify_rrset(env, ve, dnskey_rrset,
16083b6c3722Schristos 			dnskey_rrset, key_idx, &reason) == sec_status_secure) {
16093b6c3722Schristos 			return 1;
16103b6c3722Schristos 		} else {
16113b6c3722Schristos 			verbose(VERB_ALGO, "DS match failed because the key "
16123b6c3722Schristos 				"does not verify the keyset: %s", reason);
16133b6c3722Schristos 		}
16140cd9f4ecSchristos 		*/
16153b6c3722Schristos 	}
16163b6c3722Schristos 	return 0;
16173b6c3722Schristos }
16183b6c3722Schristos 
16193b6c3722Schristos /** Set update events */
16203b6c3722Schristos static int
update_events(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,int * changed)16213b6c3722Schristos update_events(struct module_env* env, struct val_env* ve,
16223b6c3722Schristos 	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
16233b6c3722Schristos 	int* changed)
16243b6c3722Schristos {
16253b6c3722Schristos 	struct packed_rrset_data* dd = (struct packed_rrset_data*)
16263b6c3722Schristos 		dnskey_rrset->entry.data;
16273b6c3722Schristos 	size_t i;
16283b6c3722Schristos 	log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
16293b6c3722Schristos 	init_events(tp);
16303b6c3722Schristos 	for(i=0; i<dd->count; i++) {
16313b6c3722Schristos 		struct autr_ta* ta = NULL;
16323b6c3722Schristos 		if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
16333b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2))
16343b6c3722Schristos 			continue;
16353b6c3722Schristos 		if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
16363b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2)) {
16373b6c3722Schristos 			/* self-signed revoked keys already detected before,
16383b6c3722Schristos 			 * other revoked keys are not 'added' again */
16393b6c3722Schristos 			continue;
16403b6c3722Schristos 		}
16413b6c3722Schristos 		/* is a key of this type supported?. Note rr_list and
16423b6c3722Schristos 		 * packed_rrset are in the same order. */
16437a540f2bSchristos 		if(!dnskey_algo_is_supported(dnskey_rrset, i) ||
16447a540f2bSchristos 			!dnskey_size_is_supported(dnskey_rrset, i)) {
16453b6c3722Schristos 			/* skip unknown algorithm key, it is useless to us */
16463b6c3722Schristos 			log_nametypeclass(VERB_DETAIL, "trust point has "
16473b6c3722Schristos 				"unsupported algorithm at",
16483b6c3722Schristos 				tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
16493b6c3722Schristos 			continue;
16503b6c3722Schristos 		}
16513b6c3722Schristos 
16523b6c3722Schristos 		/* is it new? if revocation bit set, find the unrevoked key */
16533b6c3722Schristos 		if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
16543b6c3722Schristos 			dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
16553b6c3722Schristos 			return 0;
16563b6c3722Schristos 		}
16573b6c3722Schristos 		if(!ta) {
16583b6c3722Schristos 			ta = add_key(tp, (uint32_t)dd->rr_ttl[i],
16593b6c3722Schristos 				dd->rr_data[i]+2, dd->rr_len[i]-2);
16603b6c3722Schristos 			*changed = 1;
16613b6c3722Schristos 			/* first time seen, do we have DSes? if match: VALID */
16623b6c3722Schristos 			if(ta && tp->ds_rrset && key_matches_a_ds(env, ve,
16633b6c3722Schristos 				dnskey_rrset, i, tp->ds_rrset)) {
16643b6c3722Schristos 				verbose_key(ta, VERB_ALGO, "verified by DS");
16653b6c3722Schristos 				ta->s = AUTR_STATE_VALID;
16663b6c3722Schristos 			}
16673b6c3722Schristos 		}
16683b6c3722Schristos 		if(!ta) {
16693b6c3722Schristos 			return 0;
16703b6c3722Schristos 		}
16713b6c3722Schristos 		seen_trustanchor(ta, 1);
16723b6c3722Schristos 		verbose_key(ta, VERB_ALGO, "in DNS response");
16733b6c3722Schristos 	}
16743b6c3722Schristos 	set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed);
16753b6c3722Schristos 	return 1;
16763b6c3722Schristos }
16773b6c3722Schristos 
16783b6c3722Schristos /**
16793b6c3722Schristos  * Check if the holddown time has already exceeded
16803b6c3722Schristos  * setting: add-holddown: add holddown timer
16813b6c3722Schristos  * setting: del-holddown: del holddown timer
16823b6c3722Schristos  * @param env: environment with current time
16833b6c3722Schristos  * @param ta: trust anchor to check for.
16843b6c3722Schristos  * @param holddown: the timer value
16853b6c3722Schristos  * @return number of seconds the holddown has passed.
16863b6c3722Schristos  */
16873b6c3722Schristos static time_t
check_holddown(struct module_env * env,struct autr_ta * ta,unsigned int holddown)16883b6c3722Schristos check_holddown(struct module_env* env, struct autr_ta* ta,
16893b6c3722Schristos 	unsigned int holddown)
16903b6c3722Schristos {
16913b6c3722Schristos         time_t elapsed;
16923b6c3722Schristos 	if(*env->now < ta->last_change) {
16933b6c3722Schristos 		log_warn("time goes backwards. delaying key holddown");
16943b6c3722Schristos 		return 0;
16953b6c3722Schristos 	}
16963b6c3722Schristos 	elapsed = *env->now - ta->last_change;
16973b6c3722Schristos         if (elapsed > (time_t)holddown) {
16983b6c3722Schristos                 return elapsed-(time_t)holddown;
16993b6c3722Schristos         }
17003b6c3722Schristos 	verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go",
17013b6c3722Schristos 		(long long) ((time_t)holddown-elapsed));
17023b6c3722Schristos         return 0;
17033b6c3722Schristos }
17043b6c3722Schristos 
17053b6c3722Schristos 
17063b6c3722Schristos /** Set last_change to now */
17073b6c3722Schristos static void
reset_holddown(struct module_env * env,struct autr_ta * ta,int * changed)17083b6c3722Schristos reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed)
17093b6c3722Schristos {
17103b6c3722Schristos 	ta->last_change = *env->now;
17113b6c3722Schristos 	*changed = 1;
17123b6c3722Schristos }
17133b6c3722Schristos 
17143b6c3722Schristos /** Set the state for this trust anchor */
17153b6c3722Schristos static void
set_trustanchor_state(struct module_env * env,struct autr_ta * ta,int * changed,autr_state_type s)17163b6c3722Schristos set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed,
17170cd9f4ecSchristos 	autr_state_type s)
17183b6c3722Schristos {
17193b6c3722Schristos 	verbose_key(ta, VERB_ALGO, "update: %s to %s",
17203b6c3722Schristos 		trustanchor_state2str(ta->s), trustanchor_state2str(s));
17213b6c3722Schristos 	ta->s = s;
17223b6c3722Schristos 	reset_holddown(env, ta, changed);
17233b6c3722Schristos }
17243b6c3722Schristos 
17253b6c3722Schristos 
17263b6c3722Schristos /** Event: NewKey */
17273b6c3722Schristos static void
do_newkey(struct module_env * env,struct autr_ta * anchor,int * c)17283b6c3722Schristos do_newkey(struct module_env* env, struct autr_ta* anchor, int* c)
17293b6c3722Schristos {
17303b6c3722Schristos 	if (anchor->s == AUTR_STATE_START)
17313b6c3722Schristos 		set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND);
17323b6c3722Schristos }
17333b6c3722Schristos 
17343b6c3722Schristos /** Event: AddTime */
17353b6c3722Schristos static void
do_addtime(struct module_env * env,struct autr_ta * anchor,int * c)17363b6c3722Schristos do_addtime(struct module_env* env, struct autr_ta* anchor, int* c)
17373b6c3722Schristos {
17383b6c3722Schristos 	/* This not according to RFC, this is 30 days, but the RFC demands
17393b6c3722Schristos 	 * MAX(30days, TTL expire time of first DNSKEY set with this key),
17403b6c3722Schristos 	 * The value may be too small if a very large TTL was used. */
17413b6c3722Schristos 	time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown);
17423b6c3722Schristos 	if (exceeded && anchor->s == AUTR_STATE_ADDPEND) {
17433b6c3722Schristos 		verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded "
17443b6c3722Schristos 			ARG_LL "d seconds ago, and pending-count %d",
17453b6c3722Schristos 			(long long)exceeded, anchor->pending_count);
17463b6c3722Schristos 		if(anchor->pending_count >= MIN_PENDINGCOUNT) {
17473b6c3722Schristos 			set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
17483b6c3722Schristos 			anchor->pending_count = 0;
17493b6c3722Schristos 			return;
17503b6c3722Schristos 		}
17513b6c3722Schristos 		verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check "
17523b6c3722Schristos 			"failed (pending count: %d)", anchor->pending_count);
17533b6c3722Schristos 	}
17543b6c3722Schristos }
17553b6c3722Schristos 
17563b6c3722Schristos /** Event: RemTime */
17573b6c3722Schristos static void
do_remtime(struct module_env * env,struct autr_ta * anchor,int * c)17583b6c3722Schristos do_remtime(struct module_env* env, struct autr_ta* anchor, int* c)
17593b6c3722Schristos {
17603b6c3722Schristos 	time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown);
17613b6c3722Schristos 	if(exceeded && anchor->s == AUTR_STATE_REVOKED) {
17623b6c3722Schristos 		verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded "
17633b6c3722Schristos 			ARG_LL "d seconds ago", (long long)exceeded);
17643b6c3722Schristos 		set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED);
17653b6c3722Schristos 	}
17663b6c3722Schristos }
17673b6c3722Schristos 
17683b6c3722Schristos /** Event: KeyRem */
17693b6c3722Schristos static void
do_keyrem(struct module_env * env,struct autr_ta * anchor,int * c)17703b6c3722Schristos do_keyrem(struct module_env* env, struct autr_ta* anchor, int* c)
17713b6c3722Schristos {
17723b6c3722Schristos 	if(anchor->s == AUTR_STATE_ADDPEND) {
17733b6c3722Schristos 		set_trustanchor_state(env, anchor, c, AUTR_STATE_START);
17743b6c3722Schristos 		anchor->pending_count = 0;
17753b6c3722Schristos 	} else if(anchor->s == AUTR_STATE_VALID)
17763b6c3722Schristos 		set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING);
17773b6c3722Schristos }
17783b6c3722Schristos 
17793b6c3722Schristos /** Event: KeyPres */
17803b6c3722Schristos static void
do_keypres(struct module_env * env,struct autr_ta * anchor,int * c)17813b6c3722Schristos do_keypres(struct module_env* env, struct autr_ta* anchor, int* c)
17823b6c3722Schristos {
17833b6c3722Schristos 	if(anchor->s == AUTR_STATE_MISSING)
17843b6c3722Schristos 		set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
17853b6c3722Schristos }
17863b6c3722Schristos 
17873b6c3722Schristos /* Event: Revoked */
17883b6c3722Schristos static void
do_revoked(struct module_env * env,struct autr_ta * anchor,int * c)17893b6c3722Schristos do_revoked(struct module_env* env, struct autr_ta* anchor, int* c)
17903b6c3722Schristos {
17913b6c3722Schristos 	if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) {
17923b6c3722Schristos                 set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED);
17933b6c3722Schristos 		verbose_key(anchor, VERB_ALGO, "old id, prior to revocation");
17943b6c3722Schristos                 revoke_dnskey(anchor, 0);
17953b6c3722Schristos 		verbose_key(anchor, VERB_ALGO, "new id, after revocation");
17963b6c3722Schristos 	}
17973b6c3722Schristos }
17983b6c3722Schristos 
17993b6c3722Schristos /** Do statestable transition matrix for anchor */
18003b6c3722Schristos static void
anchor_state_update(struct module_env * env,struct autr_ta * anchor,int * c)18013b6c3722Schristos anchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c)
18023b6c3722Schristos {
18033b6c3722Schristos 	log_assert(anchor);
18043b6c3722Schristos 	switch(anchor->s) {
18053b6c3722Schristos 	/* START */
18063b6c3722Schristos 	case AUTR_STATE_START:
18073b6c3722Schristos 		/* NewKey: ADDPEND */
18083b6c3722Schristos 		if (anchor->fetched)
18093b6c3722Schristos 			do_newkey(env, anchor, c);
18103b6c3722Schristos 		break;
18113b6c3722Schristos 	/* ADDPEND */
18123b6c3722Schristos 	case AUTR_STATE_ADDPEND:
18133b6c3722Schristos 		/* KeyRem: START */
18143b6c3722Schristos 		if (!anchor->fetched)
18153b6c3722Schristos 			do_keyrem(env, anchor, c);
18163b6c3722Schristos 		/* AddTime: VALID */
18173b6c3722Schristos 		else	do_addtime(env, anchor, c);
18183b6c3722Schristos 		break;
18193b6c3722Schristos 	/* VALID */
18203b6c3722Schristos 	case AUTR_STATE_VALID:
18213b6c3722Schristos 		/* RevBit: REVOKED */
18223b6c3722Schristos 		if (anchor->revoked)
18233b6c3722Schristos 			do_revoked(env, anchor, c);
18243b6c3722Schristos 		/* KeyRem: MISSING */
18253b6c3722Schristos 		else if (!anchor->fetched)
18263b6c3722Schristos 			do_keyrem(env, anchor, c);
18273b6c3722Schristos 		else if(!anchor->last_change) {
18283b6c3722Schristos 			verbose_key(anchor, VERB_ALGO, "first seen");
18293b6c3722Schristos 			reset_holddown(env, anchor, c);
18303b6c3722Schristos 		}
18313b6c3722Schristos 		break;
18323b6c3722Schristos 	/* MISSING */
18333b6c3722Schristos 	case AUTR_STATE_MISSING:
18343b6c3722Schristos 		/* RevBit: REVOKED */
18353b6c3722Schristos 		if (anchor->revoked)
18363b6c3722Schristos 			do_revoked(env, anchor, c);
18373b6c3722Schristos 		/* KeyPres */
18383b6c3722Schristos 		else if (anchor->fetched)
18393b6c3722Schristos 			do_keypres(env, anchor, c);
18403b6c3722Schristos 		break;
18413b6c3722Schristos 	/* REVOKED */
18423b6c3722Schristos 	case AUTR_STATE_REVOKED:
18433b6c3722Schristos 		if (anchor->fetched)
18443b6c3722Schristos 			reset_holddown(env, anchor, c);
18453b6c3722Schristos 		/* RemTime: REMOVED */
18463b6c3722Schristos 		else	do_remtime(env, anchor, c);
18473b6c3722Schristos 		break;
18483b6c3722Schristos 	/* REMOVED */
18493b6c3722Schristos 	case AUTR_STATE_REMOVED:
18503b6c3722Schristos 	default:
18513b6c3722Schristos 		break;
18523b6c3722Schristos 	}
18533b6c3722Schristos }
18543b6c3722Schristos 
18553b6c3722Schristos /** if ZSK init then trust KSKs */
18563b6c3722Schristos static int
init_zsk_to_ksk(struct module_env * env,struct trust_anchor * tp,int * changed)18573b6c3722Schristos init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed)
18583b6c3722Schristos {
18593b6c3722Schristos 	/* search for VALID ZSKs */
18603b6c3722Schristos 	struct autr_ta* anchor;
18613b6c3722Schristos 	int validzsk = 0;
18623b6c3722Schristos 	int validksk = 0;
18633b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18643b6c3722Schristos 		/* last_change test makes sure it was manually configured */
18653b6c3722Schristos 		if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len,
18663b6c3722Schristos 			anchor->dname_len) == LDNS_RR_TYPE_DNSKEY &&
18673b6c3722Schristos 			anchor->last_change == 0 &&
18683b6c3722Schristos 			!ta_is_dnskey_sep(anchor) &&
18693b6c3722Schristos 			anchor->s == AUTR_STATE_VALID)
18703b6c3722Schristos                         validzsk++;
18713b6c3722Schristos 	}
18723b6c3722Schristos 	if(validzsk == 0)
18733b6c3722Schristos 		return 0;
18743b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18753b6c3722Schristos                 if (ta_is_dnskey_sep(anchor) &&
18763b6c3722Schristos 			anchor->s == AUTR_STATE_ADDPEND) {
18773b6c3722Schristos 			verbose_key(anchor, VERB_ALGO, "trust KSK from "
18783b6c3722Schristos 				"ZSK(config)");
18793b6c3722Schristos 			set_trustanchor_state(env, anchor, changed,
18803b6c3722Schristos 				AUTR_STATE_VALID);
18813b6c3722Schristos 			validksk++;
18823b6c3722Schristos 		}
18833b6c3722Schristos 	}
18843b6c3722Schristos 	return validksk;
18853b6c3722Schristos }
18863b6c3722Schristos 
18873b6c3722Schristos /** Remove missing trustanchors so the list does not grow forever */
18883b6c3722Schristos static void
remove_missing_trustanchors(struct module_env * env,struct trust_anchor * tp,int * changed)18893b6c3722Schristos remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp,
18903b6c3722Schristos 	int* changed)
18913b6c3722Schristos {
18923b6c3722Schristos 	struct autr_ta* anchor;
18933b6c3722Schristos 	time_t exceeded;
18943b6c3722Schristos 	int valid = 0;
18953b6c3722Schristos 	/* see if we have anchors that are valid */
18963b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18973b6c3722Schristos 		/* Only do KSKs */
18983b6c3722Schristos                 if (!ta_is_dnskey_sep(anchor))
18993b6c3722Schristos                         continue;
19003b6c3722Schristos                 if (anchor->s == AUTR_STATE_VALID)
19013b6c3722Schristos                         valid++;
19023b6c3722Schristos 	}
19033b6c3722Schristos 	/* if there are no SEP Valid anchors, see if we started out with
19043b6c3722Schristos 	 * a ZSK (last-change=0) anchor, which is VALID and there are KSKs
19053b6c3722Schristos 	 * now that can be made valid.  Do this immediately because there
19063b6c3722Schristos 	 * is no guarantee that the ZSKs get announced long enough.  Usually
19073b6c3722Schristos 	 * this is immediately after init with a ZSK trusted, unless the domain
19083b6c3722Schristos 	 * was not advertising any KSKs at all.  In which case we perfectly
19093b6c3722Schristos 	 * track the zero number of KSKs. */
19103b6c3722Schristos 	if(valid == 0) {
19113b6c3722Schristos 		valid = init_zsk_to_ksk(env, tp, changed);
19123b6c3722Schristos 		if(valid == 0)
19133b6c3722Schristos 			return;
19143b6c3722Schristos 	}
19153b6c3722Schristos 
19163b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19173b6c3722Schristos 		/* ignore ZSKs if newly added */
19183b6c3722Schristos 		if(anchor->s == AUTR_STATE_START)
19193b6c3722Schristos 			continue;
19203b6c3722Schristos 		/* remove ZSKs if a KSK is present */
19213b6c3722Schristos                 if (!ta_is_dnskey_sep(anchor)) {
19223b6c3722Schristos 			if(valid > 0) {
19233b6c3722Schristos 				verbose_key(anchor, VERB_ALGO, "remove ZSK "
19243b6c3722Schristos 					"[%d key(s) VALID]", valid);
19253b6c3722Schristos 				set_trustanchor_state(env, anchor, changed,
19263b6c3722Schristos 					AUTR_STATE_REMOVED);
19273b6c3722Schristos 			}
19283b6c3722Schristos                         continue;
19293b6c3722Schristos 		}
19303b6c3722Schristos                 /* Only do MISSING keys */
19313b6c3722Schristos                 if (anchor->s != AUTR_STATE_MISSING)
19323b6c3722Schristos                         continue;
19333b6c3722Schristos 		if(env->cfg->keep_missing == 0)
19343b6c3722Schristos 			continue; /* keep forever */
19353b6c3722Schristos 
19363b6c3722Schristos 		exceeded = check_holddown(env, anchor, env->cfg->keep_missing);
19373b6c3722Schristos 		/* If keep_missing has exceeded and we still have more than
19383b6c3722Schristos 		 * one valid KSK: remove missing trust anchor */
19393b6c3722Schristos                 if (exceeded && valid > 0) {
19403b6c3722Schristos 			verbose_key(anchor, VERB_ALGO, "keep-missing time "
19413b6c3722Schristos 				"exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]",
19423b6c3722Schristos 				(long long)exceeded, valid);
19433b6c3722Schristos 			set_trustanchor_state(env, anchor, changed,
19443b6c3722Schristos 				AUTR_STATE_REMOVED);
19453b6c3722Schristos 		}
19463b6c3722Schristos 	}
19473b6c3722Schristos }
19483b6c3722Schristos 
19493b6c3722Schristos /** Do the statetable from RFC5011 transition matrix */
19503b6c3722Schristos static int
do_statetable(struct module_env * env,struct trust_anchor * tp,int * changed)19513b6c3722Schristos do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed)
19523b6c3722Schristos {
19533b6c3722Schristos 	struct autr_ta* anchor;
19543b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19553b6c3722Schristos 		/* Only do KSKs */
19563b6c3722Schristos 		if(!ta_is_dnskey_sep(anchor))
19573b6c3722Schristos 			continue;
19583b6c3722Schristos 		anchor_state_update(env, anchor, changed);
19593b6c3722Schristos 	}
19603b6c3722Schristos 	remove_missing_trustanchors(env, tp, changed);
19613b6c3722Schristos 	return 1;
19623b6c3722Schristos }
19633b6c3722Schristos 
19643b6c3722Schristos /** See if time alone makes ADDPEND to VALID transition */
19653b6c3722Schristos static void
autr_holddown_exceed(struct module_env * env,struct trust_anchor * tp,int * c)19663b6c3722Schristos autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c)
19673b6c3722Schristos {
19683b6c3722Schristos 	struct autr_ta* anchor;
19693b6c3722Schristos 	for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19703b6c3722Schristos 		if(ta_is_dnskey_sep(anchor) &&
19713b6c3722Schristos 			anchor->s == AUTR_STATE_ADDPEND)
19723b6c3722Schristos 			do_addtime(env, anchor, c);
19733b6c3722Schristos 	}
19743b6c3722Schristos }
19753b6c3722Schristos 
19763b6c3722Schristos /** cleanup key list */
19773b6c3722Schristos static void
autr_cleanup_keys(struct trust_anchor * tp)19783b6c3722Schristos autr_cleanup_keys(struct trust_anchor* tp)
19793b6c3722Schristos {
19803b6c3722Schristos 	struct autr_ta* p, **prevp;
19813b6c3722Schristos 	prevp = &tp->autr->keys;
19823b6c3722Schristos 	p = tp->autr->keys;
19833b6c3722Schristos 	while(p) {
19843b6c3722Schristos 		/* do we want to remove this key? */
19853b6c3722Schristos 		if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED ||
19863b6c3722Schristos 			sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len)
19873b6c3722Schristos 			!= LDNS_RR_TYPE_DNSKEY) {
19883b6c3722Schristos 			struct autr_ta* np = p->next;
19893b6c3722Schristos 			/* remove */
19903b6c3722Schristos 			free(p->rr);
19913b6c3722Schristos 			free(p);
19923b6c3722Schristos 			/* snip and go to next item */
19933b6c3722Schristos 			*prevp = np;
19943b6c3722Schristos 			p = np;
19953b6c3722Schristos 			continue;
19963b6c3722Schristos 		}
19973b6c3722Schristos 		/* remove pending counts if no longer pending */
19983b6c3722Schristos 		if(p->s != AUTR_STATE_ADDPEND)
19993b6c3722Schristos 			p->pending_count = 0;
20003b6c3722Schristos 		prevp = &p->next;
20013b6c3722Schristos 		p = p->next;
20023b6c3722Schristos 	}
20033b6c3722Schristos }
20043b6c3722Schristos 
20053b6c3722Schristos /** calculate next probe time */
20063b6c3722Schristos static time_t
calc_next_probe(struct module_env * env,time_t wait)20073b6c3722Schristos calc_next_probe(struct module_env* env, time_t wait)
20083b6c3722Schristos {
20093b6c3722Schristos 	/* make it random, 90-100% */
20103b6c3722Schristos 	time_t rnd, rest;
20113b6c3722Schristos 	if(!autr_permit_small_holddown) {
20123b6c3722Schristos 		if(wait < 3600)
20133b6c3722Schristos 			wait = 3600;
20143b6c3722Schristos 	} else {
20153b6c3722Schristos 		if(wait == 0) wait = 1;
20163b6c3722Schristos 	}
20173b6c3722Schristos 	rnd = wait/10;
20183b6c3722Schristos 	rest = wait-rnd;
20193b6c3722Schristos 	rnd = (time_t)ub_random_max(env->rnd, (long int)rnd);
20203b6c3722Schristos 	return (time_t)(*env->now + rest + rnd);
20213b6c3722Schristos }
20223b6c3722Schristos 
20233b6c3722Schristos /** what is first probe time (anchors must be locked) */
20243b6c3722Schristos static time_t
wait_probe_time(struct val_anchors * anchors)20253b6c3722Schristos wait_probe_time(struct val_anchors* anchors)
20263b6c3722Schristos {
20270cd9f4ecSchristos 	rbnode_type* t = rbtree_first(&anchors->autr->probe);
20283b6c3722Schristos 	if(t != RBTREE_NULL)
20293b6c3722Schristos 		return ((struct trust_anchor*)t->key)->autr->next_probe_time;
20303b6c3722Schristos 	return 0;
20313b6c3722Schristos }
20323b6c3722Schristos 
20333b6c3722Schristos /** reset worker timer */
20343b6c3722Schristos static void
reset_worker_timer(struct module_env * env)20353b6c3722Schristos reset_worker_timer(struct module_env* env)
20363b6c3722Schristos {
20373b6c3722Schristos 	struct timeval tv;
20383b6c3722Schristos #ifndef S_SPLINT_S
20393b6c3722Schristos 	time_t next = (time_t)wait_probe_time(env->anchors);
20403b6c3722Schristos 	/* in case this is libunbound, no timer */
20413b6c3722Schristos 	if(!env->probe_timer)
20423b6c3722Schristos 		return;
20433b6c3722Schristos 	if(next > *env->now)
20443b6c3722Schristos 		tv.tv_sec = (time_t)(next - *env->now);
20453b6c3722Schristos 	else	tv.tv_sec = 0;
20463b6c3722Schristos #endif
20473b6c3722Schristos 	tv.tv_usec = 0;
20483b6c3722Schristos 	comm_timer_set(env->probe_timer, &tv);
20493b6c3722Schristos 	verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec);
20503b6c3722Schristos }
20513b6c3722Schristos 
20523b6c3722Schristos /** set next probe for trust anchor */
20533b6c3722Schristos static int
set_next_probe(struct module_env * env,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset)20543b6c3722Schristos set_next_probe(struct module_env* env, struct trust_anchor* tp,
20553b6c3722Schristos 	struct ub_packed_rrset_key* dnskey_rrset)
20563b6c3722Schristos {
20573b6c3722Schristos 	struct trust_anchor key, *tp2;
20583b6c3722Schristos 	time_t mold, mnew;
20593b6c3722Schristos 	/* use memory allocated in rrset for temporary name storage */
20603b6c3722Schristos 	key.node.key = &key;
20613b6c3722Schristos 	key.name = dnskey_rrset->rk.dname;
20623b6c3722Schristos 	key.namelen = dnskey_rrset->rk.dname_len;
20633b6c3722Schristos 	key.namelabs = dname_count_labels(key.name);
20643b6c3722Schristos 	key.dclass = tp->dclass;
20653b6c3722Schristos 	lock_basic_unlock(&tp->lock);
20663b6c3722Schristos 
20673b6c3722Schristos 	/* fetch tp again and lock anchors, so that we can modify the trees */
20683b6c3722Schristos 	lock_basic_lock(&env->anchors->lock);
20693b6c3722Schristos 	tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key);
20703b6c3722Schristos 	if(!tp2) {
20713b6c3722Schristos 		verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe");
20723b6c3722Schristos 		lock_basic_unlock(&env->anchors->lock);
20733b6c3722Schristos 		return 0;
20743b6c3722Schristos 	}
20753b6c3722Schristos 	log_assert(tp == tp2);
20763b6c3722Schristos 	lock_basic_lock(&tp->lock);
20773b6c3722Schristos 
20783b6c3722Schristos 	/* schedule */
20793b6c3722Schristos 	mold = wait_probe_time(env->anchors);
20803b6c3722Schristos 	(void)rbtree_delete(&env->anchors->autr->probe, tp);
20813b6c3722Schristos 	tp->autr->next_probe_time = calc_next_probe(env,
20823b6c3722Schristos 		tp->autr->query_interval);
20833b6c3722Schristos 	(void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
20843b6c3722Schristos 	mnew = wait_probe_time(env->anchors);
20853b6c3722Schristos 
20863b6c3722Schristos 	lock_basic_unlock(&env->anchors->lock);
20873b6c3722Schristos 	verbose(VERB_ALGO, "next probe set in %d seconds",
20883b6c3722Schristos 		(int)tp->autr->next_probe_time - (int)*env->now);
20893b6c3722Schristos 	if(mold != mnew) {
20903b6c3722Schristos 		reset_worker_timer(env);
20913b6c3722Schristos 	}
20923b6c3722Schristos 	return 1;
20933b6c3722Schristos }
20943b6c3722Schristos 
20953b6c3722Schristos /** Revoke and Delete a trust point */
20963b6c3722Schristos static void
autr_tp_remove(struct module_env * env,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset)20973b6c3722Schristos autr_tp_remove(struct module_env* env, struct trust_anchor* tp,
20983b6c3722Schristos 	struct ub_packed_rrset_key* dnskey_rrset)
20993b6c3722Schristos {
21003b6c3722Schristos 	struct trust_anchor* del_tp;
21013b6c3722Schristos 	struct trust_anchor key;
21023b6c3722Schristos 	struct autr_point_data pd;
21033b6c3722Schristos 	time_t mold, mnew;
21043b6c3722Schristos 
21053b6c3722Schristos 	log_nametypeclass(VERB_OPS, "trust point was revoked",
21063b6c3722Schristos 		tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
21073b6c3722Schristos 	tp->autr->revoked = 1;
21083b6c3722Schristos 
21093b6c3722Schristos 	/* use space allocated for dnskey_rrset to save name of anchor */
21103b6c3722Schristos 	memset(&key, 0, sizeof(key));
21113b6c3722Schristos 	memset(&pd, 0, sizeof(pd));
21123b6c3722Schristos 	key.autr = &pd;
21133b6c3722Schristos 	key.node.key = &key;
21143b6c3722Schristos 	pd.pnode.key = &key;
21153b6c3722Schristos 	pd.next_probe_time = tp->autr->next_probe_time;
21163b6c3722Schristos 	key.name = dnskey_rrset->rk.dname;
21173b6c3722Schristos 	key.namelen = tp->namelen;
21183b6c3722Schristos 	key.namelabs = tp->namelabs;
21193b6c3722Schristos 	key.dclass = tp->dclass;
21203b6c3722Schristos 
21213b6c3722Schristos 	/* unlock */
21223b6c3722Schristos 	lock_basic_unlock(&tp->lock);
21233b6c3722Schristos 
21243b6c3722Schristos 	/* take from tree. It could be deleted by someone else,hence (void). */
21253b6c3722Schristos 	lock_basic_lock(&env->anchors->lock);
21263b6c3722Schristos 	del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key);
21273b6c3722Schristos 	mold = wait_probe_time(env->anchors);
21283b6c3722Schristos 	(void)rbtree_delete(&env->anchors->autr->probe, &key);
21293b6c3722Schristos 	mnew = wait_probe_time(env->anchors);
21303b6c3722Schristos 	anchors_init_parents_locked(env->anchors);
21313b6c3722Schristos 	lock_basic_unlock(&env->anchors->lock);
21323b6c3722Schristos 
21333b6c3722Schristos 	/* if !del_tp then the trust point is no longer present in the tree,
21343b6c3722Schristos 	 * it was deleted by someone else, who will write the zonefile and
21353b6c3722Schristos 	 * clean up the structure */
21363b6c3722Schristos 	if(del_tp) {
21373b6c3722Schristos 		/* save on disk */
21383b6c3722Schristos 		del_tp->autr->next_probe_time = 0; /* no more probing for it */
21393b6c3722Schristos 		autr_write_file(env, del_tp);
21403b6c3722Schristos 
21413b6c3722Schristos 		/* delete */
21423b6c3722Schristos 		autr_point_delete(del_tp);
21433b6c3722Schristos 	}
21443b6c3722Schristos 	if(mold != mnew) {
21453b6c3722Schristos 		reset_worker_timer(env);
21463b6c3722Schristos 	}
21473b6c3722Schristos }
21483b6c3722Schristos 
autr_process_prime(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,struct module_qstate * qstate)21493b6c3722Schristos int autr_process_prime(struct module_env* env, struct val_env* ve,
21500cd9f4ecSchristos 	struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
21510cd9f4ecSchristos 	struct module_qstate* qstate)
21523b6c3722Schristos {
21533b6c3722Schristos 	int changed = 0;
21543b6c3722Schristos 	log_assert(tp && tp->autr);
21553b6c3722Schristos 	/* autotrust update trust anchors */
21563b6c3722Schristos 	/* the tp is locked, and stays locked unless it is deleted */
21573b6c3722Schristos 
21583b6c3722Schristos 	/* we could just catch the anchor here while another thread
21593b6c3722Schristos 	 * is busy deleting it. Just unlock and let the other do its job */
21603b6c3722Schristos 	if(tp->autr->revoked) {
21613b6c3722Schristos 		log_nametypeclass(VERB_ALGO, "autotrust not processed, "
21623b6c3722Schristos 			"trust point revoked", tp->name,
21633b6c3722Schristos 			LDNS_RR_TYPE_DNSKEY, tp->dclass);
21643b6c3722Schristos 		lock_basic_unlock(&tp->lock);
21653b6c3722Schristos 		return 0; /* it is revoked */
21663b6c3722Schristos 	}
21673b6c3722Schristos 
21683b6c3722Schristos 	/* query_dnskeys(): */
21693b6c3722Schristos 	tp->autr->last_queried = *env->now;
21703b6c3722Schristos 
21713b6c3722Schristos 	log_nametypeclass(VERB_ALGO, "autotrust process for",
21723b6c3722Schristos 		tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
21733b6c3722Schristos 	/* see if time alone makes some keys valid */
21743b6c3722Schristos 	autr_holddown_exceed(env, tp, &changed);
21753b6c3722Schristos 	if(changed) {
21763b6c3722Schristos 		verbose(VERB_ALGO, "autotrust: morekeys, reassemble");
21773b6c3722Schristos 		if(!autr_assemble(tp)) {
21783b6c3722Schristos 			log_err("malloc failure assembling autotrust keys");
21793b6c3722Schristos 			return 1; /* unchanged */
21803b6c3722Schristos 		}
21813b6c3722Schristos 	}
21823b6c3722Schristos 	/* did we get any data? */
21833b6c3722Schristos 	if(!dnskey_rrset) {
21843b6c3722Schristos 		verbose(VERB_ALGO, "autotrust: no dnskey rrset");
21853b6c3722Schristos 		/* no update of query_failed, because then we would have
21863b6c3722Schristos 		 * to write to disk. But we cannot because we maybe are
21870cd9f4ecSchristos 		 * still 'initializing' with DS records, that we cannot write
21883b6c3722Schristos 		 * in the full format (which only contains KSKs). */
21893b6c3722Schristos 		return 1; /* trust point exists */
21903b6c3722Schristos 	}
21913b6c3722Schristos 	/* check for revoked keys to remove immediately */
21920cd9f4ecSchristos 	check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate);
21933b6c3722Schristos 	if(changed) {
21943b6c3722Schristos 		verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
21953b6c3722Schristos 		if(!autr_assemble(tp)) {
21963b6c3722Schristos 			log_err("malloc failure assembling autotrust keys");
21973b6c3722Schristos 			return 1; /* unchanged */
21983b6c3722Schristos 		}
21993b6c3722Schristos 		if(!tp->ds_rrset && !tp->dnskey_rrset) {
22003b6c3722Schristos 			/* no more keys, all are revoked */
22013b6c3722Schristos 			/* this is a success for this probe attempt */
22023b6c3722Schristos 			tp->autr->last_success = *env->now;
22033b6c3722Schristos 			autr_tp_remove(env, tp, dnskey_rrset);
22043b6c3722Schristos 			return 0; /* trust point removed */
22053b6c3722Schristos 		}
22063b6c3722Schristos 	}
22073b6c3722Schristos 	/* verify the dnskey rrset and see if it is valid. */
22080cd9f4ecSchristos 	if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) {
22093b6c3722Schristos 		verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
22103b6c3722Schristos 		/* only increase failure count if this is not the first prime,
22113b6c3722Schristos 		 * this means there was a previous successful probe */
22123b6c3722Schristos 		if(tp->autr->last_success) {
22133b6c3722Schristos 			tp->autr->query_failed += 1;
22143b6c3722Schristos 			autr_write_file(env, tp);
22153b6c3722Schristos 		}
22163b6c3722Schristos 		return 1; /* trust point exists */
22173b6c3722Schristos 	}
22183b6c3722Schristos 
22193b6c3722Schristos 	tp->autr->last_success = *env->now;
22203b6c3722Schristos 	tp->autr->query_failed = 0;
22213b6c3722Schristos 
22223b6c3722Schristos 	/* Add new trust anchors to the data structure
22233b6c3722Schristos 	 * - note which trust anchors are seen this probe.
22243b6c3722Schristos 	 * Set trustpoint query_interval and retry_time.
22253b6c3722Schristos 	 * - find minimum rrsig expiration interval
22263b6c3722Schristos 	 */
22273b6c3722Schristos 	if(!update_events(env, ve, tp, dnskey_rrset, &changed)) {
22283b6c3722Schristos 		log_err("malloc failure in autotrust update_events. "
22293b6c3722Schristos 			"trust point unchanged.");
22303b6c3722Schristos 		return 1; /* trust point unchanged, so exists */
22313b6c3722Schristos 	}
22323b6c3722Schristos 
22333b6c3722Schristos 	/* - for every SEP key do the 5011 statetable.
22343b6c3722Schristos 	 * - remove missing trustanchors (if veryold and we have new anchors).
22353b6c3722Schristos 	 */
22363b6c3722Schristos 	if(!do_statetable(env, tp, &changed)) {
22373b6c3722Schristos 		log_err("malloc failure in autotrust do_statetable. "
22383b6c3722Schristos 			"trust point unchanged.");
22393b6c3722Schristos 		return 1; /* trust point unchanged, so exists */
22403b6c3722Schristos 	}
22413b6c3722Schristos 
22423b6c3722Schristos 	autr_cleanup_keys(tp);
22433b6c3722Schristos 	if(!set_next_probe(env, tp, dnskey_rrset))
22443b6c3722Schristos 		return 0; /* trust point does not exist */
22453b6c3722Schristos 	autr_write_file(env, tp);
22463b6c3722Schristos 	if(changed) {
22473b6c3722Schristos 		verbose(VERB_ALGO, "autotrust: changed, reassemble");
22483b6c3722Schristos 		if(!autr_assemble(tp)) {
22493b6c3722Schristos 			log_err("malloc failure assembling autotrust keys");
22503b6c3722Schristos 			return 1; /* unchanged */
22513b6c3722Schristos 		}
22523b6c3722Schristos 		if(!tp->ds_rrset && !tp->dnskey_rrset) {
22533b6c3722Schristos 			/* no more keys, all are revoked */
22543b6c3722Schristos 			autr_tp_remove(env, tp, dnskey_rrset);
22553b6c3722Schristos 			return 0; /* trust point removed */
22563b6c3722Schristos 		}
22573b6c3722Schristos 	} else verbose(VERB_ALGO, "autotrust: no changes");
22583b6c3722Schristos 
22593b6c3722Schristos 	return 1; /* trust point exists */
22603b6c3722Schristos }
22613b6c3722Schristos 
22623b6c3722Schristos /** debug print a trust anchor key */
22633b6c3722Schristos static void
autr_debug_print_ta(struct autr_ta * ta)22643b6c3722Schristos autr_debug_print_ta(struct autr_ta* ta)
22653b6c3722Schristos {
22663b6c3722Schristos 	char buf[32];
22673b6c3722Schristos 	char* str = sldns_wire2str_rr(ta->rr, ta->rr_len);
22683b6c3722Schristos 	if(!str) {
22693b6c3722Schristos 		log_info("out of memory in debug_print_ta");
22703b6c3722Schristos 		return;
22713b6c3722Schristos 	}
227201049ae6Schristos 	if(str[0]) str[strlen(str)-1]=0; /* remove newline */
22737a540f2bSchristos 	(void)autr_ctime_r(&ta->last_change, buf);
22743b6c3722Schristos 	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
22753b6c3722Schristos 	log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s",
22763b6c3722Schristos 		trustanchor_state2str(ta->s), str, ta->s, ta->pending_count,
22773b6c3722Schristos 		ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf);
22783b6c3722Schristos 	free(str);
22793b6c3722Schristos }
22803b6c3722Schristos 
22813b6c3722Schristos /** debug print a trust point */
22823b6c3722Schristos static void
autr_debug_print_tp(struct trust_anchor * tp)22833b6c3722Schristos autr_debug_print_tp(struct trust_anchor* tp)
22843b6c3722Schristos {
22853b6c3722Schristos 	struct autr_ta* ta;
22863b6c3722Schristos 	char buf[257];
22873b6c3722Schristos 	if(!tp->autr)
22883b6c3722Schristos 		return;
22893b6c3722Schristos 	dname_str(tp->name, buf);
22903b6c3722Schristos 	log_info("trust point %s : %d", buf, (int)tp->dclass);
22913b6c3722Schristos 	log_info("assembled %d DS and %d DNSKEYs",
22923b6c3722Schristos 		(int)tp->numDS, (int)tp->numDNSKEY);
22933b6c3722Schristos 	if(tp->ds_rrset) {
229401049ae6Schristos 		log_packed_rrset(NO_VERBOSE, "DS:", tp->ds_rrset);
22953b6c3722Schristos 	}
22963b6c3722Schristos 	if(tp->dnskey_rrset) {
229701049ae6Schristos 		log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset);
22983b6c3722Schristos 	}
22993b6c3722Schristos 	log_info("file %s", tp->autr->file);
23007a540f2bSchristos 	(void)autr_ctime_r(&tp->autr->last_queried, buf);
23013b6c3722Schristos 	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23023b6c3722Schristos 	log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf);
23037a540f2bSchristos 	(void)autr_ctime_r(&tp->autr->last_success, buf);
23043b6c3722Schristos 	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23053b6c3722Schristos 	log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf);
23067a540f2bSchristos 	(void)autr_ctime_r(&tp->autr->next_probe_time, buf);
23073b6c3722Schristos 	if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23083b6c3722Schristos 	log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time,
23093b6c3722Schristos 		buf);
23103b6c3722Schristos 	log_info("query_interval: %u", (unsigned)tp->autr->query_interval);
23113b6c3722Schristos 	log_info("retry_time: %u", (unsigned)tp->autr->retry_time);
23123b6c3722Schristos 	log_info("query_failed: %u", (unsigned)tp->autr->query_failed);
23133b6c3722Schristos 
23143b6c3722Schristos 	for(ta=tp->autr->keys; ta; ta=ta->next) {
23153b6c3722Schristos 		autr_debug_print_ta(ta);
23163b6c3722Schristos 	}
23173b6c3722Schristos }
23183b6c3722Schristos 
23193b6c3722Schristos void
autr_debug_print(struct val_anchors * anchors)23203b6c3722Schristos autr_debug_print(struct val_anchors* anchors)
23213b6c3722Schristos {
23223b6c3722Schristos 	struct trust_anchor* tp;
23233b6c3722Schristos 	lock_basic_lock(&anchors->lock);
23243b6c3722Schristos 	RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) {
23253b6c3722Schristos 		lock_basic_lock(&tp->lock);
23263b6c3722Schristos 		autr_debug_print_tp(tp);
23273b6c3722Schristos 		lock_basic_unlock(&tp->lock);
23283b6c3722Schristos 	}
23293b6c3722Schristos 	lock_basic_unlock(&anchors->lock);
23303b6c3722Schristos }
23313b6c3722Schristos 
probe_answer_cb(void * arg,int ATTR_UNUSED (rcode),sldns_buffer * ATTR_UNUSED (buf),enum sec_status ATTR_UNUSED (sec),char * ATTR_UNUSED (why_bogus),int ATTR_UNUSED (was_ratelimited))23323b6c3722Schristos void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode),
23333b6c3722Schristos 	sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec),
2334f42d8de7Schristos 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
23353b6c3722Schristos {
23363b6c3722Schristos 	/* retry was set before the query was done,
23373b6c3722Schristos 	 * re-querytime is set when query succeeded, but that may not
23383b6c3722Schristos 	 * have reset this timer because the query could have been
23393b6c3722Schristos 	 * handled by another thread. In that case, this callback would
23403b6c3722Schristos 	 * get called after the original timeout is done.
23413b6c3722Schristos 	 * By not resetting the timer, it may probe more often, but not
23423b6c3722Schristos 	 * less often.
23433b6c3722Schristos 	 * Unless the new lookup resulted in smaller TTLs and thus smaller
23443b6c3722Schristos 	 * timeout values. In that case one old TTL could be mistakenly done.
23453b6c3722Schristos 	 */
23463b6c3722Schristos 	struct module_env* env = (struct module_env*)arg;
23473b6c3722Schristos 	verbose(VERB_ALGO, "autotrust probe answer cb");
23483b6c3722Schristos 	reset_worker_timer(env);
23493b6c3722Schristos }
23503b6c3722Schristos 
23513b6c3722Schristos /** probe a trust anchor DNSKEY and unlocks tp */
23523b6c3722Schristos static void
probe_anchor(struct module_env * env,struct trust_anchor * tp)23533b6c3722Schristos probe_anchor(struct module_env* env, struct trust_anchor* tp)
23543b6c3722Schristos {
23553b6c3722Schristos 	struct query_info qinfo;
23563b6c3722Schristos 	uint16_t qflags = BIT_RD;
23573b6c3722Schristos 	struct edns_data edns;
23583b6c3722Schristos 	sldns_buffer* buf = env->scratch_buffer;
23593b6c3722Schristos 	qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen);
23603b6c3722Schristos 	if(!qinfo.qname) {
23613b6c3722Schristos 		log_err("out of memory making 5011 probe");
23623b6c3722Schristos 		return;
23633b6c3722Schristos 	}
23643b6c3722Schristos 	qinfo.qname_len = tp->namelen;
23653b6c3722Schristos 	qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
23663b6c3722Schristos 	qinfo.qclass = tp->dclass;
23670cd9f4ecSchristos 	qinfo.local_alias = NULL;
23683b6c3722Schristos 	log_query_info(VERB_ALGO, "autotrust probe", &qinfo);
23693b6c3722Schristos 	verbose(VERB_ALGO, "retry probe set in %d seconds",
23703b6c3722Schristos 		(int)tp->autr->next_probe_time - (int)*env->now);
23713b6c3722Schristos 	edns.edns_present = 1;
23723b6c3722Schristos 	edns.ext_rcode = 0;
23733b6c3722Schristos 	edns.edns_version = 0;
23743b6c3722Schristos 	edns.bits = EDNS_DO;
23757a540f2bSchristos 	edns.opt_list_in = NULL;
23767a540f2bSchristos 	edns.opt_list_out = NULL;
23777a540f2bSchristos 	edns.opt_list_inplace_cb_out = NULL;
2378d0eba39bSchristos 	edns.padding_block_size = 0;
2379*91f7d55fSchristos 	edns.cookie_present = 0;
2380*91f7d55fSchristos 	edns.cookie_valid = 0;
23813b6c3722Schristos 	if(sldns_buffer_capacity(buf) < 65535)
23823b6c3722Schristos 		edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
23833b6c3722Schristos 	else	edns.udp_size = 65535;
23843b6c3722Schristos 
23853b6c3722Schristos 	/* can't hold the lock while mesh_run is processing */
23863b6c3722Schristos 	lock_basic_unlock(&tp->lock);
23873b6c3722Schristos 
23883b6c3722Schristos 	/* delete the DNSKEY from rrset and key cache so an active probe
23893b6c3722Schristos 	 * is done. First the rrset so another thread does not use it
23903b6c3722Schristos 	 * to recreate the key entry in a race condition. */
23913b6c3722Schristos 	rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len,
23923b6c3722Schristos 		qinfo.qtype, qinfo.qclass, 0);
23933b6c3722Schristos 	key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len,
23943b6c3722Schristos 		qinfo.qclass);
23953b6c3722Schristos 
23963b6c3722Schristos 	if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
23977a540f2bSchristos 		&probe_answer_cb, env, 0)) {
23983b6c3722Schristos 		log_err("out of memory making 5011 probe");
23993b6c3722Schristos 	}
24003b6c3722Schristos }
24013b6c3722Schristos 
24023b6c3722Schristos /** fetch first to-probe trust-anchor and lock it and set retrytime */
24033b6c3722Schristos static struct trust_anchor*
todo_probe(struct module_env * env,time_t * next)24043b6c3722Schristos todo_probe(struct module_env* env, time_t* next)
24053b6c3722Schristos {
24063b6c3722Schristos 	struct trust_anchor* tp;
24070cd9f4ecSchristos 	rbnode_type* el;
24083b6c3722Schristos 	/* get first one */
24093b6c3722Schristos 	lock_basic_lock(&env->anchors->lock);
24103b6c3722Schristos 	if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) {
24113b6c3722Schristos 		/* in case of revoked anchors */
24123b6c3722Schristos 		lock_basic_unlock(&env->anchors->lock);
24133b6c3722Schristos 		/* signal that there are no anchors to probe */
24143b6c3722Schristos 		*next = 0;
24153b6c3722Schristos 		return NULL;
24163b6c3722Schristos 	}
24173b6c3722Schristos 	tp = (struct trust_anchor*)el->key;
24183b6c3722Schristos 	lock_basic_lock(&tp->lock);
24193b6c3722Schristos 
24203b6c3722Schristos 	/* is it eligible? */
24213b6c3722Schristos 	if((time_t)tp->autr->next_probe_time > *env->now) {
24223b6c3722Schristos 		/* no more to probe */
24233b6c3722Schristos 		*next = (time_t)tp->autr->next_probe_time - *env->now;
24243b6c3722Schristos 		lock_basic_unlock(&tp->lock);
24253b6c3722Schristos 		lock_basic_unlock(&env->anchors->lock);
24263b6c3722Schristos 		return NULL;
24273b6c3722Schristos 	}
24283b6c3722Schristos 
24293b6c3722Schristos 	/* reset its next probe time */
24303b6c3722Schristos 	(void)rbtree_delete(&env->anchors->autr->probe, tp);
24313b6c3722Schristos 	tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time);
24323b6c3722Schristos 	(void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
24333b6c3722Schristos 	lock_basic_unlock(&env->anchors->lock);
24343b6c3722Schristos 
24353b6c3722Schristos 	return tp;
24363b6c3722Schristos }
24373b6c3722Schristos 
24383b6c3722Schristos time_t
autr_probe_timer(struct module_env * env)24393b6c3722Schristos autr_probe_timer(struct module_env* env)
24403b6c3722Schristos {
24413b6c3722Schristos 	struct trust_anchor* tp;
24423b6c3722Schristos 	time_t next_probe = 3600;
24433b6c3722Schristos 	int num = 0;
24443b6c3722Schristos 	if(autr_permit_small_holddown) next_probe = 1;
24453b6c3722Schristos 	verbose(VERB_ALGO, "autotrust probe timer callback");
24463b6c3722Schristos 	/* while there are still anchors to probe */
24473b6c3722Schristos 	while( (tp = todo_probe(env, &next_probe)) ) {
24483b6c3722Schristos 		/* make a probe for this anchor */
24493b6c3722Schristos 		probe_anchor(env, tp);
24503b6c3722Schristos 		num++;
24513b6c3722Schristos 	}
24523b6c3722Schristos 	regional_free_all(env->scratch);
24533b6c3722Schristos 	if(next_probe == 0)
24543b6c3722Schristos 		return 0; /* no trust points to probe */
24553b6c3722Schristos 	verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num);
24563b6c3722Schristos 	return next_probe;
24573b6c3722Schristos }
2458