1238104Sdes#include <ldns/config.h>
2238104Sdes
3238104Sdes#include <ldns/ldns.h>
4238104Sdes
5238104Sdes#include <strings.h>
6238104Sdes#include <time.h>
7238104Sdes
8238104Sdes#ifdef HAVE_SSL
9238104Sdes/* this entire file is rather useless when you don't have
10238104Sdes * crypto...
11238104Sdes */
12238104Sdes#include <openssl/ssl.h>
13238104Sdes#include <openssl/evp.h>
14238104Sdes#include <openssl/rand.h>
15238104Sdes#include <openssl/err.h>
16238104Sdes#include <openssl/md5.h>
17238104Sdes
18238104Sdesldns_dnssec_data_chain *
19246827Sdesldns_dnssec_data_chain_new(void)
20238104Sdes{
21238104Sdes	ldns_dnssec_data_chain *nc = LDNS_CALLOC(ldns_dnssec_data_chain, 1);
22238104Sdes        if(!nc) return NULL;
23238104Sdes	/*
24238104Sdes	 * not needed anymore because CALLOC initalizes everything to zero.
25238104Sdes
26238104Sdes	nc->rrset = NULL;
27238104Sdes	nc->parent_type = 0;
28238104Sdes	nc->parent = NULL;
29238104Sdes	nc->signatures = NULL;
30238104Sdes	nc->packet_rcode = 0;
31238104Sdes	nc->packet_qtype = 0;
32238104Sdes	nc->packet_nodata = false;
33238104Sdes
34238104Sdes	 */
35238104Sdes	return nc;
36238104Sdes}
37238104Sdes
38238104Sdesvoid
39238104Sdesldns_dnssec_data_chain_free(ldns_dnssec_data_chain *chain)
40238104Sdes{
41238104Sdes	LDNS_FREE(chain);
42238104Sdes}
43238104Sdes
44238104Sdesvoid
45238104Sdesldns_dnssec_data_chain_deep_free(ldns_dnssec_data_chain *chain)
46238104Sdes{
47238104Sdes	ldns_rr_list_deep_free(chain->rrset);
48238104Sdes	ldns_rr_list_deep_free(chain->signatures);
49238104Sdes	if (chain->parent) {
50238104Sdes		ldns_dnssec_data_chain_deep_free(chain->parent);
51238104Sdes	}
52238104Sdes	LDNS_FREE(chain);
53238104Sdes}
54238104Sdes
55238104Sdesvoid
56238104Sdesldns_dnssec_data_chain_print_fmt(FILE *out, const ldns_output_format *fmt,
57238104Sdes		const ldns_dnssec_data_chain *chain)
58238104Sdes{
59238104Sdes	ldns_lookup_table *rcode;
60238104Sdes	const ldns_rr_descriptor *rr_descriptor;
61238104Sdes	if (chain) {
62238104Sdes		ldns_dnssec_data_chain_print_fmt(out, fmt, chain->parent);
63238104Sdes		if (ldns_rr_list_rr_count(chain->rrset) > 0) {
64238104Sdes			rcode = ldns_lookup_by_id(ldns_rcodes,
65238104Sdes								 (int) chain->packet_rcode);
66238104Sdes			if (rcode) {
67238104Sdes				fprintf(out, ";; rcode: %s\n", rcode->name);
68238104Sdes			}
69238104Sdes
70238104Sdes			rr_descriptor = ldns_rr_descript(chain->packet_qtype);
71238104Sdes			if (rr_descriptor && rr_descriptor->_name) {
72238104Sdes				fprintf(out, ";; qtype: %s\n", rr_descriptor->_name);
73238104Sdes			} else if (chain->packet_qtype != 0) {
74238104Sdes				fprintf(out, "TYPE%u",
75238104Sdes					   chain->packet_qtype);
76238104Sdes			}
77238104Sdes			if (chain->packet_nodata) {
78238104Sdes				fprintf(out, ";; NODATA response\n");
79238104Sdes			}
80238104Sdes			fprintf(out, "rrset:\n");
81238104Sdes			ldns_rr_list_print_fmt(out, fmt, chain->rrset);
82238104Sdes			fprintf(out, "sigs:\n");
83238104Sdes			ldns_rr_list_print_fmt(out, fmt, chain->signatures);
84238104Sdes			fprintf(out, "---\n");
85238104Sdes		} else {
86238104Sdes			fprintf(out, "<no data>\n");
87238104Sdes		}
88238104Sdes	}
89238104Sdes}
90238104Sdesvoid
91238104Sdesldns_dnssec_data_chain_print(FILE *out, const ldns_dnssec_data_chain *chain)
92238104Sdes{
93238104Sdes	ldns_dnssec_data_chain_print_fmt(
94238104Sdes			out, ldns_output_format_default, chain);
95238104Sdes}
96238104Sdes
97238104Sdes
98238104Sdesstatic void
99238104Sdesldns_dnssec_build_data_chain_dnskey(ldns_resolver *res,
100238104Sdes					    uint16_t qflags,
101238104Sdes					    const ldns_pkt *pkt,
102238104Sdes					    ldns_rr_list *signatures,
103238104Sdes						ldns_dnssec_data_chain *new_chain,
104238104Sdes						ldns_rdf *key_name,
105238104Sdes						ldns_rr_class c) {
106238104Sdes	ldns_rr_list *keys;
107238104Sdes	ldns_pkt *my_pkt;
108238104Sdes	if (signatures && ldns_rr_list_rr_count(signatures) > 0) {
109238104Sdes		new_chain->signatures = ldns_rr_list_clone(signatures);
110238104Sdes		new_chain->parent_type = 0;
111238104Sdes
112238104Sdes		keys = ldns_pkt_rr_list_by_name_and_type(
113238104Sdes				  pkt,
114238104Sdes				 key_name,
115238104Sdes				 LDNS_RR_TYPE_DNSKEY,
116238104Sdes				 LDNS_SECTION_ANY_NOQUESTION
117238104Sdes			  );
118238104Sdes		if (!keys) {
119238104Sdes			my_pkt = ldns_resolver_query(res,
120238104Sdes									key_name,
121238104Sdes									LDNS_RR_TYPE_DNSKEY,
122238104Sdes									c,
123238104Sdes									qflags);
124238104Sdes			if (my_pkt) {
125238104Sdes			keys = ldns_pkt_rr_list_by_name_and_type(
126238104Sdes					  my_pkt,
127238104Sdes					 key_name,
128238104Sdes					 LDNS_RR_TYPE_DNSKEY,
129238104Sdes					 LDNS_SECTION_ANY_NOQUESTION
130238104Sdes				  );
131238104Sdes			new_chain->parent = ldns_dnssec_build_data_chain(res,
132238104Sdes													qflags,
133238104Sdes													keys,
134238104Sdes													my_pkt,
135238104Sdes													NULL);
136238104Sdes			new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY;
137238104Sdes			ldns_pkt_free(my_pkt);
138238104Sdes			}
139238104Sdes		} else {
140238104Sdes			new_chain->parent = ldns_dnssec_build_data_chain(res,
141238104Sdes													qflags,
142238104Sdes													keys,
143238104Sdes													pkt,
144238104Sdes													NULL);
145238104Sdes			new_chain->parent->packet_qtype = LDNS_RR_TYPE_DNSKEY;
146238104Sdes		}
147238104Sdes		ldns_rr_list_deep_free(keys);
148238104Sdes	}
149238104Sdes}
150238104Sdes
151238104Sdesstatic void
152238104Sdesldns_dnssec_build_data_chain_other(ldns_resolver *res,
153238104Sdes					    uint16_t qflags,
154238104Sdes						ldns_dnssec_data_chain *new_chain,
155238104Sdes						ldns_rdf *key_name,
156238104Sdes						ldns_rr_class c,
157238104Sdes						ldns_rr_list *dss)
158238104Sdes{
159238104Sdes	/* 'self-signed', parent is a DS */
160238104Sdes
161238104Sdes	/* okay, either we have other keys signing the current one,
162238104Sdes	 * or the current
163238104Sdes	 * one should have a DS record in the parent zone.
164238104Sdes	 * How do we find this out? Try both?
165238104Sdes	 *
166238104Sdes	 * request DNSKEYS for current zone,
167238104Sdes	 * add all signatures to current level
168238104Sdes	 */
169238104Sdes	ldns_pkt *my_pkt;
170238104Sdes	ldns_rr_list *signatures2;
171238104Sdes
172238104Sdes	new_chain->parent_type = 1;
173238104Sdes
174238104Sdes	my_pkt = ldns_resolver_query(res,
175238104Sdes							key_name,
176238104Sdes							LDNS_RR_TYPE_DS,
177238104Sdes							c,
178238104Sdes							qflags);
179238104Sdes	if (my_pkt) {
180238104Sdes	dss = ldns_pkt_rr_list_by_name_and_type(my_pkt,
181238104Sdes									key_name,
182238104Sdes									LDNS_RR_TYPE_DS,
183238104Sdes									LDNS_SECTION_ANY_NOQUESTION
184238104Sdes									);
185238104Sdes	if (dss) {
186238104Sdes		new_chain->parent = ldns_dnssec_build_data_chain(res,
187238104Sdes												qflags,
188238104Sdes												dss,
189238104Sdes												my_pkt,
190238104Sdes												NULL);
191238104Sdes		new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS;
192238104Sdes		ldns_rr_list_deep_free(dss);
193238104Sdes	}
194238104Sdes	ldns_pkt_free(my_pkt);
195238104Sdes	}
196238104Sdes
197238104Sdes	my_pkt = ldns_resolver_query(res,
198238104Sdes							key_name,
199238104Sdes							LDNS_RR_TYPE_DNSKEY,
200238104Sdes							c,
201238104Sdes							qflags);
202238104Sdes	if (my_pkt) {
203238104Sdes	signatures2 = ldns_pkt_rr_list_by_name_and_type(my_pkt,
204238104Sdes										   key_name,
205238104Sdes										   LDNS_RR_TYPE_RRSIG,
206238104Sdes										   LDNS_SECTION_ANSWER);
207238104Sdes	if (signatures2) {
208238104Sdes		if (new_chain->signatures) {
209238104Sdes			printf("There were already sigs!\n");
210238104Sdes			ldns_rr_list_deep_free(new_chain->signatures);
211238104Sdes			printf("replacing the old sigs\n");
212238104Sdes		}
213238104Sdes		new_chain->signatures = signatures2;
214238104Sdes	}
215238104Sdes	ldns_pkt_free(my_pkt);
216238104Sdes	}
217238104Sdes}
218238104Sdes
219246827Sdesstatic ldns_dnssec_data_chain *
220238104Sdesldns_dnssec_build_data_chain_nokeyname(ldns_resolver *res,
221238104Sdes                                       uint16_t qflags,
222238104Sdes                                       ldns_rr *orig_rr,
223238104Sdes                                       const ldns_rr_list *rrset,
224238104Sdes                                       ldns_dnssec_data_chain *new_chain)
225238104Sdes{
226238104Sdes	ldns_rdf *possible_parent_name;
227238104Sdes	ldns_pkt *my_pkt;
228238104Sdes	/* apparently we were not able to find a signing key, so
229238104Sdes	   we assume the chain ends here
230238104Sdes	*/
231238104Sdes	/* try parents for auth denial of DS */
232238104Sdes	if (orig_rr) {
233238104Sdes		possible_parent_name = ldns_rr_owner(orig_rr);
234238104Sdes	} else if (rrset && ldns_rr_list_rr_count(rrset) > 0) {
235238104Sdes		possible_parent_name = ldns_rr_owner(ldns_rr_list_rr(rrset, 0));
236238104Sdes	} else {
237238104Sdes		/* no information to go on, give up */
238238104Sdes		return new_chain;
239238104Sdes	}
240238104Sdes
241238104Sdes	my_pkt = ldns_resolver_query(res,
242238104Sdes	              possible_parent_name,
243238104Sdes	              LDNS_RR_TYPE_DS,
244238104Sdes	              LDNS_RR_CLASS_IN,
245238104Sdes	              qflags);
246238104Sdes	if (!my_pkt) {
247238104Sdes		return new_chain;
248238104Sdes	}
249238104Sdes
250238104Sdes	if (ldns_pkt_ancount(my_pkt) > 0) {
251238104Sdes		/* add error, no sigs but DS in parent */
252238104Sdes		/*ldns_pkt_print(stdout, my_pkt);*/
253238104Sdes		ldns_pkt_free(my_pkt);
254238104Sdes	} else {
255238104Sdes		/* are there signatures? */
256238104Sdes		new_chain->parent =  ldns_dnssec_build_data_chain(res,
257238104Sdes		                          qflags,
258238104Sdes		                          NULL,
259238104Sdes		                          my_pkt,
260238104Sdes		                          NULL);
261238104Sdes
262238104Sdes		new_chain->parent->packet_qtype = LDNS_RR_TYPE_DS;
263238104Sdes
264238104Sdes	}
265238104Sdes	return new_chain;
266238104Sdes}
267238104Sdes
268238104Sdes
269238104Sdesldns_dnssec_data_chain *
270238104Sdesldns_dnssec_build_data_chain(ldns_resolver *res,
271238104Sdes					    uint16_t qflags,
272238104Sdes					    const ldns_rr_list *rrset,
273238104Sdes					    const ldns_pkt *pkt,
274238104Sdes					    ldns_rr *orig_rr)
275238104Sdes{
276238104Sdes	ldns_rr_list *signatures = NULL;
277238104Sdes	ldns_rr_list *dss = NULL;
278238104Sdes
279238104Sdes	ldns_rr_list *my_rrset;
280238104Sdes
281238104Sdes	ldns_pkt *my_pkt;
282238104Sdes
283238104Sdes	ldns_rdf *name = NULL, *key_name = NULL;
284238104Sdes	ldns_rr_type type = 0;
285238104Sdes	ldns_rr_class c = 0;
286238104Sdes
287238104Sdes	bool other_rrset = false;
288246854Sdes
289238104Sdes	ldns_dnssec_data_chain *new_chain = ldns_dnssec_data_chain_new();
290238104Sdes
291246854Sdes	assert(pkt != NULL);
292246854Sdes
293238104Sdes	if (!ldns_dnssec_pkt_has_rrsigs(pkt)) {
294238104Sdes		/* hmm. no dnssec data in the packet. go up to try and deny
295238104Sdes		 * DS? */
296238104Sdes		return new_chain;
297238104Sdes	}
298238104Sdes
299238104Sdes	if (orig_rr) {
300238104Sdes		new_chain->rrset = ldns_rr_list_new();
301238104Sdes		ldns_rr_list_push_rr(new_chain->rrset, orig_rr);
302238104Sdes		new_chain->parent = ldns_dnssec_build_data_chain(res,
303238104Sdes											    qflags,
304238104Sdes											    rrset,
305238104Sdes											    pkt,
306238104Sdes											    NULL);
307238104Sdes		new_chain->packet_rcode = ldns_pkt_get_rcode(pkt);
308238104Sdes		new_chain->packet_qtype = ldns_rr_get_type(orig_rr);
309238104Sdes		if (ldns_pkt_ancount(pkt) == 0) {
310238104Sdes			new_chain->packet_nodata = true;
311238104Sdes		}
312238104Sdes		return new_chain;
313238104Sdes	}
314238104Sdes
315238104Sdes	if (!rrset || ldns_rr_list_rr_count(rrset) < 1) {
316238104Sdes		/* hmm, no data, do we have denial? only works if pkt was given,
317238104Sdes		   otherwise caller has to do the check himself */
318238104Sdes		new_chain->packet_nodata = true;
319238104Sdes		if (pkt) {
320238104Sdes			my_rrset = ldns_pkt_rr_list_by_type(pkt,
321238104Sdes										 LDNS_RR_TYPE_NSEC,
322238104Sdes										 LDNS_SECTION_ANY_NOQUESTION
323238104Sdes										 );
324238104Sdes			if (my_rrset) {
325238104Sdes				if (ldns_rr_list_rr_count(my_rrset) > 0) {
326238104Sdes					type = LDNS_RR_TYPE_NSEC;
327238104Sdes					other_rrset = true;
328238104Sdes				} else {
329238104Sdes					ldns_rr_list_deep_free(my_rrset);
330238104Sdes					my_rrset = NULL;
331238104Sdes				}
332238104Sdes			} else {
333238104Sdes				/* nothing, try nsec3 */
334238104Sdes				my_rrset = ldns_pkt_rr_list_by_type(pkt,
335238104Sdes						     LDNS_RR_TYPE_NSEC3,
336238104Sdes							LDNS_SECTION_ANY_NOQUESTION);
337238104Sdes				if (my_rrset) {
338238104Sdes					if (ldns_rr_list_rr_count(my_rrset) > 0) {
339238104Sdes						type = LDNS_RR_TYPE_NSEC3;
340238104Sdes						other_rrset = true;
341238104Sdes					} else {
342238104Sdes						ldns_rr_list_deep_free(my_rrset);
343238104Sdes						my_rrset = NULL;
344238104Sdes					}
345238104Sdes				} else {
346238104Sdes					/* nothing, stop */
347238104Sdes					/* try parent zone? for denied insecure? */
348238104Sdes					return new_chain;
349238104Sdes				}
350238104Sdes			}
351238104Sdes		} else {
352238104Sdes			return new_chain;
353238104Sdes		}
354238104Sdes	} else {
355238104Sdes		my_rrset = (ldns_rr_list *) rrset;
356238104Sdes	}
357238104Sdes
358238104Sdes	if (my_rrset && ldns_rr_list_rr_count(my_rrset) > 0) {
359238104Sdes		new_chain->rrset = ldns_rr_list_clone(my_rrset);
360238104Sdes		name = ldns_rr_owner(ldns_rr_list_rr(my_rrset, 0));
361238104Sdes		type = ldns_rr_get_type(ldns_rr_list_rr(my_rrset, 0));
362238104Sdes		c = ldns_rr_get_class(ldns_rr_list_rr(my_rrset, 0));
363238104Sdes	}
364238104Sdes
365238104Sdes	if (other_rrset) {
366238104Sdes		ldns_rr_list_deep_free(my_rrset);
367238104Sdes	}
368238104Sdes
369238104Sdes	/* normally there will only be 1 signature 'set'
370238104Sdes	   but there can be more than 1 denial (wildcards)
371238104Sdes	   so check for NSEC
372238104Sdes	*/
373238104Sdes	if (type == LDNS_RR_TYPE_NSEC || type == LDNS_RR_TYPE_NSEC3) {
374238104Sdes		/* just throw in all signatures, the tree builder must sort
375238104Sdes		   this out */
376238104Sdes		if (pkt) {
377238104Sdes			signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type);
378238104Sdes		} else {
379238104Sdes			my_pkt = ldns_resolver_query(res, name, type, c, qflags);
380238104Sdes			if (my_pkt) {
381238104Sdes			signatures = ldns_dnssec_pkt_get_rrsigs_for_type(pkt, type);
382238104Sdes			ldns_pkt_free(my_pkt);
383238104Sdes			}
384238104Sdes		}
385238104Sdes	} else {
386238104Sdes		if (pkt) {
387238104Sdes			signatures =
388238104Sdes				ldns_dnssec_pkt_get_rrsigs_for_name_and_type(pkt,
389238104Sdes													name,
390238104Sdes													type);
391238104Sdes		}
392238104Sdes		if (!signatures) {
393238104Sdes			my_pkt = ldns_resolver_query(res, name, type, c, qflags);
394238104Sdes			if (my_pkt) {
395238104Sdes			signatures =
396238104Sdes				ldns_dnssec_pkt_get_rrsigs_for_name_and_type(my_pkt,
397238104Sdes													name,
398238104Sdes													type);
399238104Sdes			ldns_pkt_free(my_pkt);
400238104Sdes			}
401238104Sdes		}
402238104Sdes	}
403238104Sdes
404238104Sdes	if (signatures && ldns_rr_list_rr_count(signatures) > 0) {
405238104Sdes		key_name = ldns_rr_rdf(ldns_rr_list_rr(signatures, 0), 7);
406238104Sdes	}
407238104Sdes	if (!key_name) {
408246854Sdes		if (signatures) {
409246854Sdes			ldns_rr_list_deep_free(signatures);
410246854Sdes		}
411238104Sdes		return ldns_dnssec_build_data_chain_nokeyname(res,
412238104Sdes		                                              qflags,
413238104Sdes		                                              orig_rr,
414238104Sdes		                                              rrset,
415238104Sdes		                                              new_chain);
416238104Sdes	}
417238104Sdes	if (type != LDNS_RR_TYPE_DNSKEY) {
418238104Sdes		ldns_dnssec_build_data_chain_dnskey(res,
419238104Sdes		                                    qflags,
420238104Sdes		                                    pkt,
421238104Sdes		                                    signatures,
422238104Sdes		                                    new_chain,
423238104Sdes		                                    key_name,
424238104Sdes		                                    c
425246854Sdes		                                   );
426238104Sdes	} else {
427238104Sdes		ldns_dnssec_build_data_chain_other(res,
428238104Sdes		                                   qflags,
429238104Sdes		                                   new_chain,
430238104Sdes		                                   key_name,
431238104Sdes		                                   c,
432238104Sdes		                                   dss
433246854Sdes		                                  );
434238104Sdes	}
435238104Sdes	if (signatures) {
436238104Sdes		ldns_rr_list_deep_free(signatures);
437238104Sdes	}
438238104Sdes	return new_chain;
439238104Sdes}
440238104Sdes
441238104Sdesldns_dnssec_trust_tree *
442246827Sdesldns_dnssec_trust_tree_new(void)
443238104Sdes{
444238104Sdes	ldns_dnssec_trust_tree *new_tree = LDNS_XMALLOC(ldns_dnssec_trust_tree,
445238104Sdes										   1);
446238104Sdes        if(!new_tree) return NULL;
447238104Sdes	new_tree->rr = NULL;
448238104Sdes	new_tree->rrset = NULL;
449238104Sdes	new_tree->parent_count = 0;
450238104Sdes
451238104Sdes	return new_tree;
452238104Sdes}
453238104Sdes
454238104Sdesvoid
455238104Sdesldns_dnssec_trust_tree_free(ldns_dnssec_trust_tree *tree)
456238104Sdes{
457238104Sdes	size_t i;
458238104Sdes	if (tree) {
459238104Sdes		for (i = 0; i < tree->parent_count; i++) {
460238104Sdes			ldns_dnssec_trust_tree_free(tree->parents[i]);
461238104Sdes		}
462238104Sdes	}
463238104Sdes	LDNS_FREE(tree);
464238104Sdes}
465238104Sdes
466238104Sdessize_t
467238104Sdesldns_dnssec_trust_tree_depth(ldns_dnssec_trust_tree *tree)
468238104Sdes{
469238104Sdes	size_t result = 0;
470238104Sdes	size_t parent = 0;
471238104Sdes	size_t i;
472238104Sdes
473238104Sdes	for (i = 0; i < tree->parent_count; i++) {
474238104Sdes		parent = ldns_dnssec_trust_tree_depth(tree->parents[i]);
475238104Sdes		if (parent > result) {
476238104Sdes			result = parent;
477238104Sdes		}
478238104Sdes	}
479238104Sdes	return 1 + result;
480238104Sdes}
481238104Sdes
482238104Sdes/* TODO ldns_ */
483238104Sdesstatic void
484238104Sdesprint_tabs(FILE *out, size_t nr, uint8_t *map, size_t treedepth)
485238104Sdes{
486238104Sdes	size_t i;
487238104Sdes	for (i = 0; i < nr; i++) {
488238104Sdes		if (i == nr - 1) {
489238104Sdes			fprintf(out, "|---");
490238104Sdes		} else if (map && i < treedepth && map[i] == 1) {
491238104Sdes			fprintf(out, "|   ");
492238104Sdes		} else {
493238104Sdes			fprintf(out, "    ");
494238104Sdes		}
495238104Sdes	}
496238104Sdes}
497238104Sdes
498246827Sdesstatic void
499238104Sdesldns_dnssec_trust_tree_print_sm_fmt(FILE *out,
500238104Sdes		const ldns_output_format *fmt,
501238104Sdes		ldns_dnssec_trust_tree *tree,
502238104Sdes		size_t tabs,
503238104Sdes		bool extended,
504238104Sdes		uint8_t *sibmap,
505238104Sdes		size_t treedepth)
506238104Sdes{
507238104Sdes	size_t i;
508238104Sdes	const ldns_rr_descriptor *descriptor;
509238104Sdes	bool mapset = false;
510238104Sdes
511238104Sdes	if (!sibmap) {
512238104Sdes		treedepth = ldns_dnssec_trust_tree_depth(tree);
513238104Sdes		sibmap = LDNS_XMALLOC(uint8_t, treedepth);
514238104Sdes                if(!sibmap)
515238104Sdes                        return; /* mem err */
516238104Sdes		memset(sibmap, 0, treedepth);
517238104Sdes		mapset = true;
518238104Sdes	}
519238104Sdes
520238104Sdes	if (tree) {
521238104Sdes		if (tree->rr) {
522238104Sdes			print_tabs(out, tabs, sibmap, treedepth);
523238104Sdes			ldns_rdf_print(out, ldns_rr_owner(tree->rr));
524238104Sdes			descriptor = ldns_rr_descript(ldns_rr_get_type(tree->rr));
525238104Sdes
526238104Sdes			if (descriptor->_name) {
527238104Sdes				fprintf(out, " (%s", descriptor->_name);
528238104Sdes			} else {
529238104Sdes				fprintf(out, " (TYPE%d",
530238104Sdes					   ldns_rr_get_type(tree->rr));
531238104Sdes			}
532238104Sdes			if (tabs > 0) {
533238104Sdes				if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DNSKEY) {
534238104Sdes					fprintf(out, " keytag: %u",
535238104Sdes					        (unsigned int) ldns_calc_keytag(tree->rr));
536238104Sdes					fprintf(out, " alg: ");
537238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2));
538238104Sdes					fprintf(out, " flags: ");
539238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
540238104Sdes				} else if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_DS) {
541238104Sdes					fprintf(out, " keytag: ");
542238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
543238104Sdes					fprintf(out, " digest type: ");
544238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 2));
545238104Sdes				}
546238104Sdes				if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NSEC) {
547238104Sdes					fprintf(out, " ");
548238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 0));
549238104Sdes					fprintf(out, " ");
550238104Sdes					ldns_rdf_print(out, ldns_rr_rdf(tree->rr, 1));
551238104Sdes				}
552238104Sdes			}
553238104Sdes
554238104Sdes			fprintf(out, ")\n");
555238104Sdes			for (i = 0; i < tree->parent_count; i++) {
556238104Sdes				if (tree->parent_count > 1 && i < tree->parent_count - 1) {
557238104Sdes					sibmap[tabs] = 1;
558238104Sdes				} else {
559238104Sdes					sibmap[tabs] = 0;
560238104Sdes				}
561238104Sdes				/* only print errors */
562238104Sdes				if (ldns_rr_get_type(tree->parents[i]->rr) ==
563238104Sdes				    LDNS_RR_TYPE_NSEC ||
564238104Sdes				    ldns_rr_get_type(tree->parents[i]->rr) ==
565238104Sdes				    LDNS_RR_TYPE_NSEC3) {
566238104Sdes					if (tree->parent_status[i] == LDNS_STATUS_OK) {
567238104Sdes						print_tabs(out, tabs + 1, sibmap, treedepth);
568238104Sdes						if (tabs == 0 &&
569238104Sdes						    ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS &&
570238104Sdes							ldns_rr_rd_count(tree->rr) > 0) {
571238104Sdes							fprintf(out, "Existence of DS is denied by:\n");
572238104Sdes						} else {
573238104Sdes							fprintf(out, "Existence is denied by:\n");
574238104Sdes						}
575238104Sdes					} else {
576238104Sdes						/* NS records aren't signed */
577238104Sdes						if (ldns_rr_get_type(tree->rr) == LDNS_RR_TYPE_NS) {
578238104Sdes							fprintf(out, "Existence of DS is denied by:\n");
579238104Sdes						} else {
580238104Sdes							print_tabs(out, tabs + 1, sibmap, treedepth);
581238104Sdes							fprintf(out,
582238104Sdes								   "Error in denial of existence: %s\n",
583238104Sdes								   ldns_get_errorstr_by_id(
584238104Sdes									   tree->parent_status[i]));
585238104Sdes						}
586238104Sdes					}
587238104Sdes				} else
588238104Sdes					if (tree->parent_status[i] != LDNS_STATUS_OK) {
589238104Sdes						print_tabs(out, tabs + 1, sibmap, treedepth);
590238104Sdes						fprintf(out,
591238104Sdes							   "%s:\n",
592238104Sdes							   ldns_get_errorstr_by_id(
593238104Sdes							       tree->parent_status[i]));
594238104Sdes						if (tree->parent_status[i]
595238104Sdes						    == LDNS_STATUS_SSL_ERR) {
596238104Sdes							printf("; SSL Error: ");
597238104Sdes							ERR_load_crypto_strings();
598238104Sdes							ERR_print_errors_fp(stdout);
599238104Sdes							printf("\n");
600238104Sdes						}
601238104Sdes						ldns_rr_print_fmt(out, fmt,
602238104Sdes							tree->
603238104Sdes							parent_signature[i]);
604238104Sdes						printf("For RRset:\n");
605238104Sdes						ldns_rr_list_print_fmt(out, fmt,
606238104Sdes								tree->rrset);
607238104Sdes						printf("With key:\n");
608238104Sdes						ldns_rr_print_fmt(out, fmt,
609238104Sdes							tree->parents[i]->rr);
610238104Sdes					}
611238104Sdes				ldns_dnssec_trust_tree_print_sm_fmt(out, fmt,
612238104Sdes						tree->parents[i],
613238104Sdes						tabs+1,
614238104Sdes						extended,
615238104Sdes						sibmap,
616238104Sdes						treedepth);
617238104Sdes			}
618238104Sdes		} else {
619238104Sdes			print_tabs(out, tabs, sibmap, treedepth);
620238104Sdes			fprintf(out, "<no data>\n");
621238104Sdes		}
622238104Sdes	} else {
623238104Sdes		fprintf(out, "<null pointer>\n");
624238104Sdes	}
625238104Sdes
626238104Sdes	if (mapset) {
627238104Sdes		LDNS_FREE(sibmap);
628238104Sdes	}
629238104Sdes}
630238104Sdes
631238104Sdesvoid
632238104Sdesldns_dnssec_trust_tree_print_fmt(FILE *out, const ldns_output_format *fmt,
633238104Sdes		ldns_dnssec_trust_tree *tree,
634238104Sdes		size_t tabs,
635238104Sdes		bool extended)
636238104Sdes{
637238104Sdes	ldns_dnssec_trust_tree_print_sm_fmt(out, fmt,
638238104Sdes			tree, tabs, extended, NULL, 0);
639238104Sdes}
640238104Sdes
641238104Sdesvoid
642238104Sdesldns_dnssec_trust_tree_print(FILE *out,
643238104Sdes		ldns_dnssec_trust_tree *tree,
644238104Sdes		size_t tabs,
645238104Sdes		bool extended)
646238104Sdes{
647238104Sdes	ldns_dnssec_trust_tree_print_fmt(out, ldns_output_format_default,
648238104Sdes			tree, tabs, extended);
649238104Sdes}
650238104Sdes
651238104Sdes
652238104Sdesldns_status
653238104Sdesldns_dnssec_trust_tree_add_parent(ldns_dnssec_trust_tree *tree,
654238104Sdes                                  const ldns_dnssec_trust_tree *parent,
655238104Sdes                                  const ldns_rr *signature,
656238104Sdes                                  const ldns_status parent_status)
657238104Sdes{
658238104Sdes	if (tree
659238104Sdes	    && parent
660238104Sdes	    && tree->parent_count < LDNS_DNSSEC_TRUST_TREE_MAX_PARENTS) {
661238104Sdes		/*
662238104Sdes		  printf("Add parent for: ");
663238104Sdes		  ldns_rr_print(stdout, tree->rr);
664238104Sdes		  printf("parent: ");
665238104Sdes		  ldns_rr_print(stdout, parent->rr);
666238104Sdes		*/
667238104Sdes		tree->parents[tree->parent_count] =
668238104Sdes			(ldns_dnssec_trust_tree *) parent;
669238104Sdes		tree->parent_status[tree->parent_count] = parent_status;
670238104Sdes		tree->parent_signature[tree->parent_count] = (ldns_rr *) signature;
671238104Sdes		tree->parent_count++;
672238104Sdes		return LDNS_STATUS_OK;
673238104Sdes	} else {
674238104Sdes		return LDNS_STATUS_ERR;
675238104Sdes	}
676238104Sdes}
677238104Sdes
678238104Sdes/* if rr is null, take the first from the rrset */
679238104Sdesldns_dnssec_trust_tree *
680238104Sdesldns_dnssec_derive_trust_tree_time(
681238104Sdes		ldns_dnssec_data_chain *data_chain,
682238104Sdes		ldns_rr *rr,
683238104Sdes		time_t check_time
684238104Sdes		)
685238104Sdes{
686238104Sdes	ldns_rr_list *cur_rrset;
687238104Sdes	ldns_rr_list *cur_sigs;
688238104Sdes	ldns_rr *cur_rr = NULL;
689238104Sdes	ldns_rr *cur_sig_rr;
690238104Sdes	size_t i, j;
691238104Sdes
692238104Sdes	ldns_dnssec_trust_tree *new_tree = ldns_dnssec_trust_tree_new();
693238104Sdes        if(!new_tree)
694238104Sdes                return NULL;
695238104Sdes
696238104Sdes	if (data_chain && data_chain->rrset) {
697238104Sdes		cur_rrset = data_chain->rrset;
698238104Sdes
699238104Sdes		cur_sigs = data_chain->signatures;
700238104Sdes
701238104Sdes		if (rr) {
702238104Sdes			cur_rr = rr;
703238104Sdes		}
704238104Sdes
705238104Sdes		if (!cur_rr && ldns_rr_list_rr_count(cur_rrset) > 0) {
706238104Sdes			cur_rr = ldns_rr_list_rr(cur_rrset, 0);
707238104Sdes		}
708238104Sdes
709238104Sdes		if (cur_rr) {
710238104Sdes			new_tree->rr = cur_rr;
711238104Sdes			new_tree->rrset = cur_rrset;
712238104Sdes			/* there are three possibilities:
713238104Sdes			   1 - 'normal' rrset, signed by a key
714238104Sdes			   2 - dnskey signed by other dnskey
715238104Sdes			   3 - dnskey proven by higher level DS
716238104Sdes			   (data denied by nsec is a special case that can
717238104Sdes			   occur in multiple places)
718238104Sdes
719238104Sdes			*/
720238104Sdes			if (cur_sigs) {
721238104Sdes				for (i = 0; i < ldns_rr_list_rr_count(cur_sigs); i++) {
722238104Sdes					/* find the appropriate key in the parent list */
723238104Sdes					cur_sig_rr = ldns_rr_list_rr(cur_sigs, i);
724238104Sdes
725238104Sdes					if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_NSEC) {
726238104Sdes						if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr),
727238104Sdes										   ldns_rr_owner(cur_rr)))
728238104Sdes							{
729238104Sdes								/* find first that does match */
730238104Sdes
731238104Sdes								for (j = 0;
732238104Sdes								     j < ldns_rr_list_rr_count(cur_rrset) &&
733238104Sdes										ldns_dname_compare(ldns_rr_owner(cur_sig_rr),ldns_rr_owner(cur_rr)) != 0;
734238104Sdes								     j++) {
735238104Sdes									cur_rr = ldns_rr_list_rr(cur_rrset, j);
736238104Sdes
737238104Sdes								}
738238104Sdes								if (ldns_dname_compare(ldns_rr_owner(cur_sig_rr),
739238104Sdes												   ldns_rr_owner(cur_rr)))
740238104Sdes									{
741238104Sdes										break;
742238104Sdes									}
743238104Sdes							}
744238104Sdes
745238104Sdes					}
746238104Sdes					/* option 1 */
747238104Sdes					if (data_chain->parent) {
748238104Sdes						ldns_dnssec_derive_trust_tree_normal_rrset_time(
749238104Sdes						    new_tree,
750238104Sdes						    data_chain,
751238104Sdes						    cur_sig_rr,
752238104Sdes						    check_time);
753238104Sdes					}
754238104Sdes
755238104Sdes					/* option 2 */
756238104Sdes					ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
757238104Sdes					    new_tree,
758238104Sdes					    data_chain,
759238104Sdes					    cur_rr,
760238104Sdes					    cur_sig_rr,
761238104Sdes					    check_time);
762238104Sdes				}
763238104Sdes
764238104Sdes				ldns_dnssec_derive_trust_tree_ds_rrset_time(
765238104Sdes						new_tree, data_chain,
766238104Sdes						cur_rr, check_time);
767238104Sdes			} else {
768238104Sdes				/* no signatures? maybe it's nsec data */
769238104Sdes
770238104Sdes				/* just add every rr from parent as new parent */
771238104Sdes				ldns_dnssec_derive_trust_tree_no_sig_time(
772238104Sdes					new_tree, data_chain, check_time);
773238104Sdes			}
774238104Sdes		}
775238104Sdes	}
776238104Sdes
777238104Sdes	return new_tree;
778238104Sdes}
779238104Sdes
780238104Sdesldns_dnssec_trust_tree *
781238104Sdesldns_dnssec_derive_trust_tree(ldns_dnssec_data_chain *data_chain, ldns_rr *rr)
782238104Sdes{
783238104Sdes	return ldns_dnssec_derive_trust_tree_time(data_chain, rr, ldns_time(NULL));
784238104Sdes}
785238104Sdes
786238104Sdesvoid
787238104Sdesldns_dnssec_derive_trust_tree_normal_rrset_time(
788238104Sdes		ldns_dnssec_trust_tree *new_tree,
789238104Sdes		ldns_dnssec_data_chain *data_chain,
790238104Sdes		ldns_rr *cur_sig_rr,
791238104Sdes		time_t check_time)
792238104Sdes{
793238104Sdes	size_t i, j;
794238104Sdes	ldns_rr_list *cur_rrset = ldns_rr_list_clone(data_chain->rrset);
795238104Sdes	ldns_dnssec_trust_tree *cur_parent_tree;
796238104Sdes	ldns_rr *cur_parent_rr;
797238104Sdes	uint16_t cur_keytag;
798238104Sdes	ldns_rr_list *tmp_rrset = NULL;
799238104Sdes	ldns_status cur_status;
800238104Sdes
801238104Sdes	cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr));
802238104Sdes
803238104Sdes	for (j = 0; j < ldns_rr_list_rr_count(data_chain->parent->rrset); j++) {
804238104Sdes		cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j);
805238104Sdes		if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) {
806238104Sdes			if (ldns_calc_keytag(cur_parent_rr) == cur_keytag) {
807238104Sdes
808238104Sdes				/* TODO: check wildcard nsec too */
809238104Sdes				if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) {
810238104Sdes					tmp_rrset = cur_rrset;
811238104Sdes					if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0))
812238104Sdes					    == LDNS_RR_TYPE_NSEC ||
813238104Sdes					    ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0))
814238104Sdes					    == LDNS_RR_TYPE_NSEC3) {
815238104Sdes						/* might contain different names!
816238104Sdes						   sort and split */
817238104Sdes						ldns_rr_list_sort(cur_rrset);
818246854Sdes						assert(tmp_rrset == cur_rrset);
819238104Sdes						tmp_rrset = ldns_rr_list_pop_rrset(cur_rrset);
820238104Sdes
821238104Sdes						/* with nsecs, this might be the wrong one */
822238104Sdes						while (tmp_rrset &&
823238104Sdes						       ldns_rr_list_rr_count(cur_rrset) > 0 &&
824238104Sdes						       ldns_dname_compare(
825238104Sdes								ldns_rr_owner(ldns_rr_list_rr(
826238104Sdes										        tmp_rrset, 0)),
827238104Sdes								ldns_rr_owner(cur_sig_rr)) != 0) {
828238104Sdes							ldns_rr_list_deep_free(tmp_rrset);
829238104Sdes							tmp_rrset =
830238104Sdes								ldns_rr_list_pop_rrset(cur_rrset);
831238104Sdes						}
832238104Sdes					}
833238104Sdes					cur_status = ldns_verify_rrsig_time(
834238104Sdes							tmp_rrset,
835238104Sdes							cur_sig_rr,
836238104Sdes							cur_parent_rr,
837238104Sdes							check_time);
838246854Sdes					if (tmp_rrset && tmp_rrset != cur_rrset
839246854Sdes							) {
840246854Sdes						ldns_rr_list_deep_free(
841246854Sdes								tmp_rrset);
842246854Sdes						tmp_rrset = NULL;
843246854Sdes					}
844238104Sdes					/* avoid dupes */
845238104Sdes					for (i = 0; i < new_tree->parent_count; i++) {
846238104Sdes						if (cur_parent_rr == new_tree->parents[i]->rr) {
847238104Sdes							goto done;
848238104Sdes						}
849238104Sdes					}
850238104Sdes
851238104Sdes					cur_parent_tree =
852238104Sdes						ldns_dnssec_derive_trust_tree_time(
853238104Sdes								data_chain->parent,
854238104Sdes						                cur_parent_rr,
855238104Sdes								check_time);
856238104Sdes					(void)ldns_dnssec_trust_tree_add_parent(new_tree,
857238104Sdes					           cur_parent_tree,
858238104Sdes					           cur_sig_rr,
859238104Sdes					           cur_status);
860238104Sdes				}
861238104Sdes			}
862238104Sdes		}
863238104Sdes	}
864238104Sdes done:
865238104Sdes	ldns_rr_list_deep_free(cur_rrset);
866238104Sdes}
867238104Sdes
868238104Sdesvoid
869238104Sdesldns_dnssec_derive_trust_tree_normal_rrset(ldns_dnssec_trust_tree *new_tree,
870238104Sdes                                           ldns_dnssec_data_chain *data_chain,
871238104Sdes                                           ldns_rr *cur_sig_rr)
872238104Sdes{
873238104Sdes	ldns_dnssec_derive_trust_tree_normal_rrset_time(
874238104Sdes			new_tree, data_chain, cur_sig_rr, ldns_time(NULL));
875238104Sdes}
876238104Sdes
877238104Sdesvoid
878238104Sdesldns_dnssec_derive_trust_tree_dnskey_rrset_time(
879238104Sdes		ldns_dnssec_trust_tree *new_tree,
880238104Sdes		ldns_dnssec_data_chain *data_chain,
881238104Sdes		ldns_rr *cur_rr,
882238104Sdes		ldns_rr *cur_sig_rr,
883238104Sdes		time_t check_time)
884238104Sdes{
885238104Sdes	size_t j;
886238104Sdes	ldns_rr_list *cur_rrset = data_chain->rrset;
887238104Sdes	ldns_dnssec_trust_tree *cur_parent_tree;
888238104Sdes	ldns_rr *cur_parent_rr;
889238104Sdes	uint16_t cur_keytag;
890238104Sdes	ldns_status cur_status;
891238104Sdes
892238104Sdes	cur_keytag = ldns_rdf2native_int16(ldns_rr_rrsig_keytag(cur_sig_rr));
893238104Sdes
894238104Sdes	for (j = 0; j < ldns_rr_list_rr_count(cur_rrset); j++) {
895238104Sdes		cur_parent_rr = ldns_rr_list_rr(cur_rrset, j);
896238104Sdes		if (cur_parent_rr != cur_rr &&
897238104Sdes		    ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DNSKEY) {
898238104Sdes			if (ldns_calc_keytag(cur_parent_rr) == cur_keytag
899238104Sdes			    ) {
900238104Sdes				cur_parent_tree = ldns_dnssec_trust_tree_new();
901238104Sdes				cur_parent_tree->rr = cur_parent_rr;
902238104Sdes				cur_parent_tree->rrset = cur_rrset;
903238104Sdes				cur_status = ldns_verify_rrsig_time(
904238104Sdes						cur_rrset, cur_sig_rr,
905238104Sdes						cur_parent_rr, check_time);
906238104Sdes				(void) ldns_dnssec_trust_tree_add_parent(new_tree,
907238104Sdes				            cur_parent_tree, cur_sig_rr, cur_status);
908238104Sdes			}
909238104Sdes		}
910238104Sdes	}
911238104Sdes}
912238104Sdes
913238104Sdesvoid
914238104Sdesldns_dnssec_derive_trust_tree_dnskey_rrset(ldns_dnssec_trust_tree *new_tree,
915238104Sdes                                           ldns_dnssec_data_chain *data_chain,
916238104Sdes                                           ldns_rr *cur_rr,
917238104Sdes                                           ldns_rr *cur_sig_rr)
918238104Sdes{
919238104Sdes	ldns_dnssec_derive_trust_tree_dnskey_rrset_time(
920238104Sdes			new_tree, data_chain, cur_rr, cur_sig_rr, ldns_time(NULL));
921238104Sdes}
922238104Sdes
923238104Sdesvoid
924238104Sdesldns_dnssec_derive_trust_tree_ds_rrset_time(
925238104Sdes		ldns_dnssec_trust_tree *new_tree,
926238104Sdes		ldns_dnssec_data_chain *data_chain,
927238104Sdes		ldns_rr *cur_rr,
928238104Sdes		time_t check_time)
929238104Sdes{
930238104Sdes	size_t j, h;
931238104Sdes	ldns_rr_list *cur_rrset = data_chain->rrset;
932238104Sdes	ldns_dnssec_trust_tree *cur_parent_tree;
933238104Sdes	ldns_rr *cur_parent_rr;
934238104Sdes
935238104Sdes	/* try the parent to see whether there are DSs there */
936238104Sdes	if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_DNSKEY &&
937238104Sdes	    data_chain->parent &&
938238104Sdes	    data_chain->parent->rrset
939238104Sdes	    ) {
940238104Sdes		for (j = 0;
941238104Sdes			j < ldns_rr_list_rr_count(data_chain->parent->rrset);
942238104Sdes			j++) {
943238104Sdes			cur_parent_rr = ldns_rr_list_rr(data_chain->parent->rrset, j);
944238104Sdes			if (ldns_rr_get_type(cur_parent_rr) == LDNS_RR_TYPE_DS) {
945238104Sdes				for (h = 0; h < ldns_rr_list_rr_count(cur_rrset); h++) {
946238104Sdes					cur_rr = ldns_rr_list_rr(cur_rrset, h);
947238104Sdes					if (ldns_rr_compare_ds(cur_rr, cur_parent_rr)) {
948238104Sdes						cur_parent_tree =
949238104Sdes							ldns_dnssec_derive_trust_tree_time(
950238104Sdes							    data_chain->parent,
951238104Sdes							    cur_parent_rr,
952238104Sdes							    check_time);
953238104Sdes						(void) ldns_dnssec_trust_tree_add_parent(
954238104Sdes						            new_tree,
955238104Sdes						            cur_parent_tree,
956238104Sdes						            NULL,
957238104Sdes						            LDNS_STATUS_OK);
958238104Sdes					} else {
959238104Sdes						/*ldns_rr_print(stdout, cur_parent_rr);*/
960238104Sdes					}
961238104Sdes				}
962238104Sdes			}
963238104Sdes		}
964238104Sdes	}
965238104Sdes}
966238104Sdes
967238104Sdesvoid
968238104Sdesldns_dnssec_derive_trust_tree_ds_rrset(ldns_dnssec_trust_tree *new_tree,
969238104Sdes                                       ldns_dnssec_data_chain *data_chain,
970238104Sdes                                       ldns_rr *cur_rr)
971238104Sdes{
972238104Sdes	ldns_dnssec_derive_trust_tree_ds_rrset_time(
973238104Sdes			new_tree, data_chain, cur_rr, ldns_time(NULL));
974238104Sdes}
975238104Sdes
976238104Sdesvoid
977238104Sdesldns_dnssec_derive_trust_tree_no_sig_time(
978238104Sdes		ldns_dnssec_trust_tree *new_tree,
979238104Sdes		ldns_dnssec_data_chain *data_chain,
980238104Sdes		time_t check_time)
981238104Sdes{
982238104Sdes	size_t i;
983238104Sdes	ldns_rr_list *cur_rrset;
984238104Sdes	ldns_rr *cur_parent_rr;
985238104Sdes	ldns_dnssec_trust_tree *cur_parent_tree;
986238104Sdes	ldns_status result;
987238104Sdes
988238104Sdes	if (data_chain->parent && data_chain->parent->rrset) {
989238104Sdes		cur_rrset = data_chain->parent->rrset;
990238104Sdes		/* nsec? */
991238104Sdes		if (cur_rrset && ldns_rr_list_rr_count(cur_rrset) > 0) {
992238104Sdes			if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) ==
993238104Sdes			    LDNS_RR_TYPE_NSEC3) {
994238104Sdes				result = ldns_dnssec_verify_denial_nsec3(
995238104Sdes					        new_tree->rr,
996238104Sdes						   cur_rrset,
997238104Sdes						   data_chain->parent->signatures,
998238104Sdes						   data_chain->packet_rcode,
999238104Sdes						   data_chain->packet_qtype,
1000238104Sdes						   data_chain->packet_nodata);
1001238104Sdes			} else if (ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0)) ==
1002238104Sdes					 LDNS_RR_TYPE_NSEC) {
1003238104Sdes				result = ldns_dnssec_verify_denial(
1004238104Sdes					        new_tree->rr,
1005238104Sdes						   cur_rrset,
1006238104Sdes						   data_chain->parent->signatures);
1007238104Sdes			} else {
1008238104Sdes				/* unsigned zone, unsigned parent */
1009238104Sdes				result = LDNS_STATUS_OK;
1010238104Sdes			}
1011238104Sdes		} else {
1012238104Sdes			result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1013238104Sdes		}
1014238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(cur_rrset); i++) {
1015238104Sdes			cur_parent_rr = ldns_rr_list_rr(cur_rrset, i);
1016238104Sdes			cur_parent_tree =
1017238104Sdes				ldns_dnssec_derive_trust_tree_time(
1018238104Sdes						data_chain->parent,
1019238104Sdes						cur_parent_rr,
1020238104Sdes						check_time);
1021238104Sdes			(void) ldns_dnssec_trust_tree_add_parent(new_tree,
1022238104Sdes			            cur_parent_tree, NULL, result);
1023238104Sdes		}
1024238104Sdes	}
1025238104Sdes}
1026238104Sdes
1027238104Sdesvoid
1028238104Sdesldns_dnssec_derive_trust_tree_no_sig(ldns_dnssec_trust_tree *new_tree,
1029238104Sdes                                     ldns_dnssec_data_chain *data_chain)
1030238104Sdes{
1031238104Sdes	ldns_dnssec_derive_trust_tree_no_sig_time(
1032238104Sdes			new_tree, data_chain, ldns_time(NULL));
1033238104Sdes}
1034238104Sdes
1035238104Sdes/*
1036238104Sdes * returns OK if there is a path from tree to key with only OK
1037238104Sdes * the (first) error in between otherwise
1038238104Sdes * or NOT_FOUND if the key wasn't present at all
1039238104Sdes */
1040238104Sdesldns_status
1041238104Sdesldns_dnssec_trust_tree_contains_keys(ldns_dnssec_trust_tree *tree,
1042238104Sdes							  ldns_rr_list *trusted_keys)
1043238104Sdes{
1044238104Sdes	size_t i;
1045238104Sdes	ldns_status result = LDNS_STATUS_CRYPTO_NO_DNSKEY;
1046238104Sdes	bool equal;
1047238104Sdes	ldns_status parent_result;
1048238104Sdes
1049238104Sdes	if (tree && trusted_keys && ldns_rr_list_rr_count(trusted_keys) > 0)
1050238104Sdes		{ if (tree->rr) {
1051238104Sdes				for (i = 0; i < ldns_rr_list_rr_count(trusted_keys); i++) {
1052238104Sdes					equal = ldns_rr_compare_ds(
1053238104Sdes							  tree->rr,
1054238104Sdes							  ldns_rr_list_rr(trusted_keys, i));
1055238104Sdes					if (equal) {
1056238104Sdes						result = LDNS_STATUS_OK;
1057238104Sdes						return result;
1058238104Sdes					}
1059238104Sdes				}
1060238104Sdes			}
1061238104Sdes			for (i = 0; i < tree->parent_count; i++) {
1062238104Sdes				parent_result =
1063238104Sdes					ldns_dnssec_trust_tree_contains_keys(tree->parents[i],
1064238104Sdes												  trusted_keys);
1065238104Sdes				if (parent_result != LDNS_STATUS_CRYPTO_NO_DNSKEY) {
1066238104Sdes					if (tree->parent_status[i] != LDNS_STATUS_OK) {
1067238104Sdes						result = tree->parent_status[i];
1068238104Sdes					} else {
1069246854Sdes						if (tree->rr &&
1070246854Sdes						    ldns_rr_get_type(tree->rr)
1071238104Sdes						    == LDNS_RR_TYPE_NSEC &&
1072238104Sdes						    parent_result == LDNS_STATUS_OK
1073238104Sdes						    ) {
1074238104Sdes							result =
1075238104Sdes								LDNS_STATUS_DNSSEC_EXISTENCE_DENIED;
1076238104Sdes						} else {
1077238104Sdes							result = parent_result;
1078238104Sdes						}
1079238104Sdes					}
1080238104Sdes				}
1081238104Sdes			}
1082238104Sdes		} else {
1083238104Sdes		result = LDNS_STATUS_ERR;
1084238104Sdes	}
1085238104Sdes
1086238104Sdes	return result;
1087238104Sdes}
1088238104Sdes
1089238104Sdesldns_status
1090238104Sdesldns_verify_time(
1091238104Sdes		ldns_rr_list *rrset,
1092238104Sdes		ldns_rr_list *rrsig,
1093238104Sdes		const ldns_rr_list *keys,
1094238104Sdes		time_t check_time,
1095238104Sdes		ldns_rr_list *good_keys
1096238104Sdes		)
1097238104Sdes{
1098238104Sdes	uint16_t i;
1099238104Sdes	ldns_status verify_result = LDNS_STATUS_ERR;
1100238104Sdes
1101238104Sdes	if (!rrset || !rrsig || !keys) {
1102238104Sdes		return LDNS_STATUS_ERR;
1103238104Sdes	}
1104238104Sdes
1105238104Sdes	if (ldns_rr_list_rr_count(rrset) < 1) {
1106238104Sdes		return LDNS_STATUS_ERR;
1107238104Sdes	}
1108238104Sdes
1109238104Sdes	if (ldns_rr_list_rr_count(rrsig) < 1) {
1110238104Sdes		return LDNS_STATUS_CRYPTO_NO_RRSIG;
1111238104Sdes	}
1112238104Sdes
1113238104Sdes	if (ldns_rr_list_rr_count(keys) < 1) {
1114238104Sdes		verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
1115238104Sdes	} else {
1116238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) {
1117238104Sdes			ldns_status s = ldns_verify_rrsig_keylist_time(
1118238104Sdes					rrset, ldns_rr_list_rr(rrsig, i),
1119238104Sdes					keys, check_time, good_keys);
1120238104Sdes			/* try a little to get more descriptive error */
1121238104Sdes			if(s == LDNS_STATUS_OK) {
1122238104Sdes				verify_result = LDNS_STATUS_OK;
1123238104Sdes			} else if(verify_result == LDNS_STATUS_ERR)
1124238104Sdes				verify_result = s;
1125238104Sdes			else if(s !=  LDNS_STATUS_ERR && verify_result ==
1126238104Sdes				LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY)
1127238104Sdes				verify_result = s;
1128238104Sdes		}
1129238104Sdes	}
1130238104Sdes	return verify_result;
1131238104Sdes}
1132238104Sdes
1133238104Sdesldns_status
1134238104Sdesldns_verify(ldns_rr_list *rrset, ldns_rr_list *rrsig, const ldns_rr_list *keys,
1135238104Sdes		  ldns_rr_list *good_keys)
1136238104Sdes{
1137238104Sdes	return ldns_verify_time(rrset, rrsig, keys, ldns_time(NULL), good_keys);
1138238104Sdes}
1139238104Sdes
1140238104Sdesldns_status
1141238104Sdesldns_verify_notime(ldns_rr_list *rrset, ldns_rr_list *rrsig,
1142238104Sdes	const ldns_rr_list *keys, ldns_rr_list *good_keys)
1143238104Sdes{
1144238104Sdes	uint16_t i;
1145238104Sdes	ldns_status verify_result = LDNS_STATUS_ERR;
1146238104Sdes
1147238104Sdes	if (!rrset || !rrsig || !keys) {
1148238104Sdes		return LDNS_STATUS_ERR;
1149238104Sdes	}
1150238104Sdes
1151238104Sdes	if (ldns_rr_list_rr_count(rrset) < 1) {
1152238104Sdes		return LDNS_STATUS_ERR;
1153238104Sdes	}
1154238104Sdes
1155238104Sdes	if (ldns_rr_list_rr_count(rrsig) < 1) {
1156238104Sdes		return LDNS_STATUS_CRYPTO_NO_RRSIG;
1157238104Sdes	}
1158238104Sdes
1159238104Sdes	if (ldns_rr_list_rr_count(keys) < 1) {
1160238104Sdes		verify_result = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
1161238104Sdes	} else {
1162238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rrsig); i++) {
1163238104Sdes			ldns_status s = ldns_verify_rrsig_keylist_notime(rrset,
1164238104Sdes				ldns_rr_list_rr(rrsig, i), keys, good_keys);
1165238104Sdes
1166238104Sdes			/* try a little to get more descriptive error */
1167238104Sdes			if (s == LDNS_STATUS_OK) {
1168238104Sdes				verify_result = LDNS_STATUS_OK;
1169238104Sdes			} else if (verify_result == LDNS_STATUS_ERR) {
1170238104Sdes				verify_result = s;
1171238104Sdes			} else if (s !=  LDNS_STATUS_ERR && verify_result ==
1172238104Sdes				LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) {
1173238104Sdes				verify_result = s;
1174238104Sdes			}
1175238104Sdes		}
1176238104Sdes	}
1177238104Sdes	return verify_result;
1178238104Sdes}
1179238104Sdes
1180238104Sdesldns_rr_list *
1181238104Sdesldns_fetch_valid_domain_keys_time(const ldns_resolver *res,
1182238104Sdes                             const ldns_rdf *domain,
1183238104Sdes                             const ldns_rr_list *keys,
1184238104Sdes			     time_t check_time,
1185238104Sdes                             ldns_status *status)
1186238104Sdes{
1187238104Sdes	ldns_rr_list * trusted_keys = NULL;
1188238104Sdes	ldns_rr_list * ds_keys = NULL;
1189238104Sdes	ldns_rdf * prev_parent_domain;
1190238104Sdes	ldns_rdf *      parent_domain;
1191238104Sdes	ldns_rr_list * parent_keys = NULL;
1192238104Sdes
1193238104Sdes	if (res && domain && keys) {
1194238104Sdes
1195238104Sdes		if ((trusted_keys = ldns_validate_domain_dnskey_time(res,
1196238104Sdes                                         domain, keys, check_time))) {
1197238104Sdes			*status = LDNS_STATUS_OK;
1198238104Sdes		} else {
1199238104Sdes			/* No trusted keys in this domain, we'll have to find some in the parent domain */
1200238104Sdes			*status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
1201238104Sdes
1202238104Sdes			parent_domain = ldns_dname_left_chop(domain);
1203246854Sdes			while (parent_domain && /* Fail if we are at the root*/
1204246854Sdes					ldns_rdf_size(parent_domain) > 0) {
1205238104Sdes
1206238104Sdes				if ((parent_keys =
1207238104Sdes					ldns_fetch_valid_domain_keys_time(res,
1208238104Sdes					     parent_domain,
1209238104Sdes					     keys,
1210238104Sdes					     check_time,
1211238104Sdes					     status))) {
1212238104Sdes					/* Check DS records */
1213238104Sdes					if ((ds_keys =
1214238104Sdes						ldns_validate_domain_ds_time(res,
1215238104Sdes						     domain,
1216238104Sdes						     parent_keys,
1217238104Sdes						     check_time))) {
1218238104Sdes						trusted_keys =
1219238104Sdes						ldns_fetch_valid_domain_keys_time(
1220238104Sdes								res,
1221238104Sdes								domain,
1222238104Sdes								ds_keys,
1223238104Sdes								check_time,
1224238104Sdes								status);
1225238104Sdes						ldns_rr_list_deep_free(ds_keys);
1226238104Sdes					} else {
1227238104Sdes						/* No valid DS at the parent -- fail */
1228238104Sdes						*status = LDNS_STATUS_CRYPTO_NO_TRUSTED_DS ;
1229238104Sdes					}
1230238104Sdes					ldns_rr_list_deep_free(parent_keys);
1231238104Sdes					break;
1232238104Sdes				} else {
1233238104Sdes					parent_domain = ldns_dname_left_chop((
1234238104Sdes						prev_parent_domain
1235238104Sdes							= parent_domain
1236238104Sdes						));
1237238104Sdes					ldns_rdf_deep_free(prev_parent_domain);
1238238104Sdes				}
1239238104Sdes			}
1240246854Sdes			if (parent_domain) {
1241246854Sdes				ldns_rdf_deep_free(parent_domain);
1242246854Sdes			}
1243238104Sdes		}
1244238104Sdes	}
1245238104Sdes	return trusted_keys;
1246238104Sdes}
1247238104Sdes
1248238104Sdesldns_rr_list *
1249238104Sdesldns_fetch_valid_domain_keys(const ldns_resolver *res,
1250238104Sdes                             const ldns_rdf *domain,
1251238104Sdes                             const ldns_rr_list *keys,
1252238104Sdes                             ldns_status *status)
1253238104Sdes{
1254238104Sdes	return ldns_fetch_valid_domain_keys_time(
1255238104Sdes			res, domain, keys, ldns_time(NULL), status);
1256238104Sdes}
1257238104Sdes
1258238104Sdesldns_rr_list *
1259238104Sdesldns_validate_domain_dnskey_time(
1260238104Sdes		const ldns_resolver * res,
1261238104Sdes		const ldns_rdf * domain,
1262238104Sdes		const ldns_rr_list * keys,
1263238104Sdes		time_t check_time
1264238104Sdes		)
1265238104Sdes{
1266238104Sdes	ldns_pkt * keypkt;
1267238104Sdes	ldns_rr * cur_key;
1268238104Sdes	uint16_t key_i; uint16_t key_j; uint16_t key_k;
1269238104Sdes	uint16_t sig_i; ldns_rr * cur_sig;
1270238104Sdes
1271238104Sdes	ldns_rr_list * domain_keys = NULL;
1272238104Sdes	ldns_rr_list * domain_sigs = NULL;
1273238104Sdes	ldns_rr_list * trusted_keys = NULL;
1274238104Sdes
1275238104Sdes	/* Fetch keys for the domain */
1276238104Sdes	keypkt = ldns_resolver_query(res, domain,
1277238104Sdes		LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, LDNS_RD);
1278238104Sdes	if (keypkt) {
1279238104Sdes		domain_keys = ldns_pkt_rr_list_by_type(keypkt,
1280238104Sdes									    LDNS_RR_TYPE_DNSKEY,
1281238104Sdes									    LDNS_SECTION_ANSWER);
1282238104Sdes		domain_sigs = ldns_pkt_rr_list_by_type(keypkt,
1283238104Sdes									    LDNS_RR_TYPE_RRSIG,
1284238104Sdes									    LDNS_SECTION_ANSWER);
1285238104Sdes
1286238104Sdes		/* Try to validate the record using our keys */
1287238104Sdes		for (key_i=0; key_i< ldns_rr_list_rr_count(domain_keys); key_i++) {
1288238104Sdes
1289238104Sdes			cur_key = ldns_rr_list_rr(domain_keys, key_i);
1290238104Sdes			for (key_j=0; key_j<ldns_rr_list_rr_count(keys); key_j++) {
1291238104Sdes				if (ldns_rr_compare_ds(ldns_rr_list_rr(keys, key_j),
1292238104Sdes								   cur_key)) {
1293238104Sdes
1294238104Sdes					/* Current key is trusted -- validate */
1295238104Sdes					trusted_keys = ldns_rr_list_new();
1296238104Sdes
1297238104Sdes					for (sig_i=0;
1298238104Sdes						sig_i<ldns_rr_list_rr_count(domain_sigs);
1299238104Sdes						sig_i++) {
1300238104Sdes						cur_sig = ldns_rr_list_rr(domain_sigs, sig_i);
1301238104Sdes						/* Avoid non-matching sigs */
1302238104Sdes						if (ldns_rdf2native_int16(
1303238104Sdes							   ldns_rr_rrsig_keytag(cur_sig))
1304238104Sdes						    == ldns_calc_keytag(cur_key)) {
1305238104Sdes							if (ldns_verify_rrsig_time(
1306238104Sdes									domain_keys,
1307238104Sdes									cur_sig,
1308238104Sdes									cur_key,
1309238104Sdes									check_time)
1310238104Sdes							    == LDNS_STATUS_OK) {
1311238104Sdes
1312238104Sdes								/* Push the whole rrset
1313238104Sdes								   -- we can't do much more */
1314238104Sdes								for (key_k=0;
1315238104Sdes									key_k<ldns_rr_list_rr_count(
1316238104Sdes											domain_keys);
1317238104Sdes									key_k++) {
1318238104Sdes									ldns_rr_list_push_rr(
1319238104Sdes									    trusted_keys,
1320238104Sdes									    ldns_rr_clone(
1321238104Sdes										   ldns_rr_list_rr(
1322238104Sdes											  domain_keys,
1323238104Sdes											  key_k)));
1324238104Sdes								}
1325238104Sdes
1326238104Sdes								ldns_rr_list_deep_free(domain_keys);
1327238104Sdes								ldns_rr_list_deep_free(domain_sigs);
1328238104Sdes								ldns_pkt_free(keypkt);
1329238104Sdes								return trusted_keys;
1330238104Sdes							}
1331238104Sdes						}
1332238104Sdes					}
1333238104Sdes
1334238104Sdes					/* Only push our trusted key */
1335238104Sdes					ldns_rr_list_push_rr(trusted_keys,
1336238104Sdes									 ldns_rr_clone(cur_key));
1337238104Sdes				}
1338238104Sdes			}
1339238104Sdes		}
1340238104Sdes
1341238104Sdes		ldns_rr_list_deep_free(domain_keys);
1342238104Sdes		ldns_rr_list_deep_free(domain_sigs);
1343238104Sdes		ldns_pkt_free(keypkt);
1344238104Sdes
1345238104Sdes	} else {
1346238104Sdes		/* LDNS_STATUS_CRYPTO_NO_DNSKEY */
1347238104Sdes	}
1348238104Sdes
1349238104Sdes	return trusted_keys;
1350238104Sdes}
1351238104Sdes
1352238104Sdesldns_rr_list *
1353238104Sdesldns_validate_domain_dnskey(const ldns_resolver * res,
1354238104Sdes					   const ldns_rdf * domain,
1355238104Sdes					   const ldns_rr_list * keys)
1356238104Sdes{
1357238104Sdes	return ldns_validate_domain_dnskey_time(
1358238104Sdes			res, domain, keys, ldns_time(NULL));
1359238104Sdes}
1360238104Sdes
1361238104Sdesldns_rr_list *
1362238104Sdesldns_validate_domain_ds_time(
1363238104Sdes		const ldns_resolver *res,
1364238104Sdes		const ldns_rdf * domain,
1365238104Sdes		const ldns_rr_list * keys,
1366238104Sdes		time_t check_time)
1367238104Sdes{
1368238104Sdes	ldns_pkt * dspkt;
1369238104Sdes	uint16_t key_i;
1370238104Sdes	ldns_rr_list * rrset = NULL;
1371238104Sdes	ldns_rr_list * sigs = NULL;
1372238104Sdes	ldns_rr_list * trusted_keys = NULL;
1373238104Sdes
1374238104Sdes	/* Fetch DS for the domain */
1375238104Sdes	dspkt = ldns_resolver_query(res, domain,
1376238104Sdes		LDNS_RR_TYPE_DS, LDNS_RR_CLASS_IN, LDNS_RD);
1377238104Sdes	if (dspkt) {
1378238104Sdes		rrset = ldns_pkt_rr_list_by_type(dspkt,
1379238104Sdes								   LDNS_RR_TYPE_DS,
1380238104Sdes								   LDNS_SECTION_ANSWER);
1381238104Sdes		sigs = ldns_pkt_rr_list_by_type(dspkt,
1382238104Sdes								  LDNS_RR_TYPE_RRSIG,
1383238104Sdes								  LDNS_SECTION_ANSWER);
1384238104Sdes
1385238104Sdes		/* Validate sigs */
1386238104Sdes		if (ldns_verify_time(rrset, sigs, keys, check_time, NULL)
1387238104Sdes			       	== LDNS_STATUS_OK) {
1388238104Sdes			trusted_keys = ldns_rr_list_new();
1389238104Sdes			for (key_i=0; key_i<ldns_rr_list_rr_count(rrset); key_i++) {
1390238104Sdes				ldns_rr_list_push_rr(trusted_keys,
1391238104Sdes								 ldns_rr_clone(ldns_rr_list_rr(rrset,
1392238104Sdes														 key_i)
1393238104Sdes											)
1394238104Sdes								 );
1395238104Sdes			}
1396238104Sdes		}
1397238104Sdes
1398238104Sdes		ldns_rr_list_deep_free(rrset);
1399238104Sdes		ldns_rr_list_deep_free(sigs);
1400238104Sdes		ldns_pkt_free(dspkt);
1401238104Sdes
1402238104Sdes	} else {
1403238104Sdes		/* LDNS_STATUS_CRYPTO_NO_DS */
1404238104Sdes	}
1405238104Sdes
1406238104Sdes	return trusted_keys;
1407238104Sdes}
1408238104Sdes
1409238104Sdesldns_rr_list *
1410238104Sdesldns_validate_domain_ds(const ldns_resolver *res,
1411238104Sdes				    const ldns_rdf * domain,
1412238104Sdes				    const ldns_rr_list * keys)
1413238104Sdes{
1414238104Sdes	return ldns_validate_domain_ds_time(res, domain, keys, ldns_time(NULL));
1415238104Sdes}
1416238104Sdes
1417238104Sdesldns_status
1418238104Sdesldns_verify_trusted_time(
1419238104Sdes		ldns_resolver *res,
1420238104Sdes		ldns_rr_list *rrset,
1421238104Sdes		ldns_rr_list * rrsigs,
1422238104Sdes		time_t check_time,
1423238104Sdes		ldns_rr_list * validating_keys
1424238104Sdes		)
1425238104Sdes{
1426238104Sdes	uint16_t sig_i; uint16_t key_i;
1427238104Sdes	ldns_rr * cur_sig; ldns_rr * cur_key;
1428238104Sdes	ldns_rr_list * trusted_keys = NULL;
1429238104Sdes	ldns_status result = LDNS_STATUS_ERR;
1430238104Sdes
1431238104Sdes	if (!res || !rrset || !rrsigs) {
1432238104Sdes		return LDNS_STATUS_ERR;
1433238104Sdes	}
1434238104Sdes
1435238104Sdes	if (ldns_rr_list_rr_count(rrset) < 1) {
1436238104Sdes		return LDNS_STATUS_ERR;
1437238104Sdes	}
1438238104Sdes
1439238104Sdes	if (ldns_rr_list_rr_count(rrsigs) < 1) {
1440238104Sdes		return LDNS_STATUS_CRYPTO_NO_RRSIG;
1441238104Sdes	}
1442238104Sdes
1443238104Sdes	/* Look at each sig */
1444238104Sdes	for (sig_i=0; sig_i < ldns_rr_list_rr_count(rrsigs); sig_i++) {
1445238104Sdes
1446238104Sdes		cur_sig = ldns_rr_list_rr(rrsigs, sig_i);
1447238104Sdes		/* Get a valid signer key and validate the sig */
1448238104Sdes		if ((trusted_keys = ldns_fetch_valid_domain_keys_time(
1449238104Sdes					res,
1450238104Sdes					ldns_rr_rrsig_signame(cur_sig),
1451238104Sdes					ldns_resolver_dnssec_anchors(res),
1452238104Sdes					check_time,
1453238104Sdes					&result))) {
1454238104Sdes
1455238104Sdes			for (key_i = 0;
1456238104Sdes				key_i < ldns_rr_list_rr_count(trusted_keys);
1457238104Sdes				key_i++) {
1458238104Sdes				cur_key = ldns_rr_list_rr(trusted_keys, key_i);
1459238104Sdes
1460238104Sdes				if ((result = ldns_verify_rrsig_time(rrset,
1461238104Sdes								cur_sig,
1462238104Sdes								cur_key,
1463238104Sdes								check_time))
1464238104Sdes				    == LDNS_STATUS_OK) {
1465238104Sdes					if (validating_keys) {
1466238104Sdes						ldns_rr_list_push_rr(validating_keys,
1467238104Sdes										 ldns_rr_clone(cur_key));
1468238104Sdes					}
1469238104Sdes					ldns_rr_list_deep_free(trusted_keys);
1470238104Sdes					return LDNS_STATUS_OK;
1471238104Sdes				}
1472238104Sdes			}
1473238104Sdes		}
1474238104Sdes	}
1475238104Sdes
1476238104Sdes	ldns_rr_list_deep_free(trusted_keys);
1477238104Sdes	return result;
1478238104Sdes}
1479238104Sdes
1480238104Sdesldns_status
1481238104Sdesldns_verify_trusted(
1482238104Sdes		ldns_resolver *res,
1483238104Sdes		ldns_rr_list *rrset,
1484238104Sdes		ldns_rr_list * rrsigs,
1485238104Sdes		ldns_rr_list * validating_keys)
1486238104Sdes{
1487238104Sdes	return ldns_verify_trusted_time(
1488238104Sdes			res, rrset, rrsigs, ldns_time(NULL), validating_keys);
1489238104Sdes}
1490238104Sdes
1491238104Sdes
1492238104Sdesldns_status
1493238104Sdesldns_dnssec_verify_denial(ldns_rr *rr,
1494238104Sdes                          ldns_rr_list *nsecs,
1495238104Sdes                          ldns_rr_list *rrsigs)
1496238104Sdes{
1497238104Sdes	ldns_rdf *rr_name;
1498238104Sdes	ldns_rdf *wildcard_name;
1499238104Sdes	ldns_rdf *chopped_dname;
1500238104Sdes	ldns_rr *cur_nsec;
1501238104Sdes	size_t i;
1502238104Sdes	ldns_status result;
1503238104Sdes	/* needed for wildcard check on exact match */
1504238104Sdes	ldns_rr *rrsig;
1505238104Sdes	bool name_covered = false;
1506238104Sdes	bool type_covered = false;
1507238104Sdes	bool wildcard_covered = false;
1508238104Sdes	bool wildcard_type_covered = false;
1509238104Sdes
1510238104Sdes	wildcard_name = ldns_dname_new_frm_str("*");
1511238104Sdes	rr_name = ldns_rr_owner(rr);
1512238104Sdes	chopped_dname = ldns_dname_left_chop(rr_name);
1513238104Sdes	result = ldns_dname_cat(wildcard_name, chopped_dname);
1514246854Sdes	ldns_rdf_deep_free(chopped_dname);
1515238104Sdes	if (result != LDNS_STATUS_OK) {
1516238104Sdes		return result;
1517238104Sdes	}
1518238104Sdes
1519238104Sdes	for  (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1520238104Sdes		cur_nsec = ldns_rr_list_rr(nsecs, i);
1521238104Sdes		if (ldns_dname_compare(rr_name, ldns_rr_owner(cur_nsec)) == 0) {
1522238104Sdes			/* see section 5.4 of RFC4035, if the label count of the NSEC's
1523238104Sdes			   RRSIG is equal, then it is proven that wildcard expansion
1524238104Sdes			   could not have been used to match the request */
1525238104Sdes			rrsig = ldns_dnssec_get_rrsig_for_name_and_type(
1526238104Sdes					  ldns_rr_owner(cur_nsec),
1527238104Sdes					  ldns_rr_get_type(cur_nsec),
1528238104Sdes					  rrsigs);
1529238104Sdes			if (rrsig && ldns_rdf2native_int8(ldns_rr_rrsig_labels(rrsig))
1530238104Sdes			    == ldns_dname_label_count(rr_name)) {
1531238104Sdes				wildcard_covered = true;
1532238104Sdes			}
1533238104Sdes
1534238104Sdes			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(cur_nsec),
1535238104Sdes									   ldns_rr_get_type(rr))) {
1536238104Sdes				type_covered = true;
1537238104Sdes			}
1538238104Sdes		}
1539238104Sdes		if (ldns_nsec_covers_name(cur_nsec, rr_name)) {
1540238104Sdes			name_covered = true;
1541238104Sdes		}
1542238104Sdes
1543238104Sdes		if (ldns_dname_compare(wildcard_name,
1544238104Sdes						   ldns_rr_owner(cur_nsec)) == 0) {
1545238104Sdes			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(cur_nsec),
1546238104Sdes									   ldns_rr_get_type(rr))) {
1547238104Sdes				wildcard_type_covered = true;
1548238104Sdes			}
1549238104Sdes		}
1550238104Sdes
1551238104Sdes		if (ldns_nsec_covers_name(cur_nsec, wildcard_name)) {
1552238104Sdes			wildcard_covered = true;
1553238104Sdes		}
1554238104Sdes
1555238104Sdes	}
1556238104Sdes
1557238104Sdes	ldns_rdf_deep_free(wildcard_name);
1558238104Sdes
1559238104Sdes	if (type_covered || !name_covered) {
1560238104Sdes		return LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1561238104Sdes	}
1562238104Sdes
1563238104Sdes	if (wildcard_type_covered || !wildcard_covered) {
1564238104Sdes		return LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED;
1565238104Sdes	}
1566238104Sdes
1567238104Sdes	return LDNS_STATUS_OK;
1568238104Sdes}
1569238104Sdes
1570238104Sdesldns_status
1571238104Sdesldns_dnssec_verify_denial_nsec3_match( ldns_rr *rr
1572238104Sdes				     , ldns_rr_list *nsecs
1573238104Sdes				     , ATTR_UNUSED(ldns_rr_list *rrsigs)
1574238104Sdes				     , ldns_pkt_rcode packet_rcode
1575238104Sdes				     , ldns_rr_type packet_qtype
1576238104Sdes				     , bool packet_nodata
1577238104Sdes				     , ldns_rr **match
1578238104Sdes				     )
1579238104Sdes{
1580238104Sdes	ldns_rdf *closest_encloser;
1581238104Sdes	ldns_rdf *wildcard;
1582238104Sdes	ldns_rdf *hashed_wildcard_name;
1583238104Sdes	bool wildcard_covered = false;
1584238104Sdes	ldns_rdf *zone_name;
1585238104Sdes	ldns_rdf *hashed_name;
1586238104Sdes	/* self assignment to suppress uninitialized warning */
1587238104Sdes	ldns_rdf *next_closer = next_closer;
1588238104Sdes	ldns_rdf *hashed_next_closer;
1589238104Sdes	size_t i;
1590238104Sdes	ldns_status result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1591238104Sdes
1592238104Sdes	if (match) {
1593238104Sdes		*match = NULL;
1594238104Sdes	}
1595238104Sdes
1596238104Sdes	zone_name = ldns_dname_left_chop(ldns_rr_owner(ldns_rr_list_rr(nsecs,0)));
1597238104Sdes
1598238104Sdes	/* section 8.4 */
1599238104Sdes	if (packet_rcode == LDNS_RCODE_NXDOMAIN) {
1600238104Sdes		closest_encloser = ldns_dnssec_nsec3_closest_encloser(
1601238104Sdes						   ldns_rr_owner(rr),
1602238104Sdes						   ldns_rr_get_type(rr),
1603238104Sdes						   nsecs);
1604238104Sdes                if(!closest_encloser) {
1605246854Sdes                        result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1606238104Sdes                        goto done;
1607238104Sdes                }
1608238104Sdes
1609238104Sdes		wildcard = ldns_dname_new_frm_str("*");
1610238104Sdes		(void) ldns_dname_cat(wildcard, closest_encloser);
1611238104Sdes
1612238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1613238104Sdes			hashed_wildcard_name =
1614238104Sdes				ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs, 0),
1615238104Sdes										 wildcard
1616238104Sdes										 );
1617238104Sdes			(void) ldns_dname_cat(hashed_wildcard_name, zone_name);
1618238104Sdes
1619238104Sdes			if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, i),
1620238104Sdes								 hashed_wildcard_name)) {
1621238104Sdes				wildcard_covered = true;
1622238104Sdes				if (match) {
1623238104Sdes					*match = ldns_rr_list_rr(nsecs, i);
1624238104Sdes				}
1625238104Sdes			}
1626238104Sdes			ldns_rdf_deep_free(hashed_wildcard_name);
1627238104Sdes		}
1628238104Sdes
1629246854Sdes		if (! wildcard_covered) {
1630246854Sdes			result = LDNS_STATUS_DNSSEC_NSEC_WILDCARD_NOT_COVERED;
1631246854Sdes		} else {
1632246854Sdes			result = LDNS_STATUS_OK;
1633246854Sdes		}
1634238104Sdes		ldns_rdf_deep_free(closest_encloser);
1635238104Sdes		ldns_rdf_deep_free(wildcard);
1636238104Sdes
1637238104Sdes	} else if (packet_nodata && packet_qtype != LDNS_RR_TYPE_DS) {
1638238104Sdes		/* section 8.5 */
1639238104Sdes		hashed_name = ldns_nsec3_hash_name_frm_nsec3(
1640238104Sdes		                   ldns_rr_list_rr(nsecs, 0),
1641238104Sdes		                   ldns_rr_owner(rr));
1642238104Sdes		(void) ldns_dname_cat(hashed_name, zone_name);
1643238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1644238104Sdes			if (ldns_dname_compare(hashed_name,
1645238104Sdes			         ldns_rr_owner(ldns_rr_list_rr(nsecs, i)))
1646238104Sdes			    == 0) {
1647238104Sdes				if (!ldns_nsec_bitmap_covers_type(
1648238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1649238104Sdes					    packet_qtype)
1650238104Sdes				    &&
1651238104Sdes				    !ldns_nsec_bitmap_covers_type(
1652238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1653238104Sdes					    LDNS_RR_TYPE_CNAME)) {
1654238104Sdes					result = LDNS_STATUS_OK;
1655238104Sdes					if (match) {
1656238104Sdes						*match = ldns_rr_list_rr(nsecs, i);
1657238104Sdes					}
1658238104Sdes					goto done;
1659238104Sdes				}
1660238104Sdes			}
1661238104Sdes		}
1662238104Sdes		result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1663238104Sdes		/* wildcard no data? section 8.7 */
1664238104Sdes		closest_encloser = ldns_dnssec_nsec3_closest_encloser(
1665238104Sdes				   ldns_rr_owner(rr),
1666238104Sdes				   ldns_rr_get_type(rr),
1667238104Sdes				   nsecs);
1668238104Sdes		if(!closest_encloser) {
1669238104Sdes			result = LDNS_STATUS_NSEC3_ERR;
1670238104Sdes			goto done;
1671238104Sdes		}
1672238104Sdes		wildcard = ldns_dname_new_frm_str("*");
1673238104Sdes		(void) ldns_dname_cat(wildcard, closest_encloser);
1674238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1675238104Sdes			hashed_wildcard_name =
1676238104Sdes				ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs, 0),
1677238104Sdes					 wildcard);
1678238104Sdes			(void) ldns_dname_cat(hashed_wildcard_name, zone_name);
1679238104Sdes
1680238104Sdes			if (ldns_dname_compare(hashed_wildcard_name,
1681238104Sdes			         ldns_rr_owner(ldns_rr_list_rr(nsecs, i)))
1682238104Sdes			    == 0) {
1683238104Sdes				if (!ldns_nsec_bitmap_covers_type(
1684238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1685238104Sdes					    packet_qtype)
1686238104Sdes				    &&
1687238104Sdes				    !ldns_nsec_bitmap_covers_type(
1688238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1689238104Sdes					    LDNS_RR_TYPE_CNAME)) {
1690238104Sdes					result = LDNS_STATUS_OK;
1691238104Sdes					if (match) {
1692238104Sdes						*match = ldns_rr_list_rr(nsecs, i);
1693238104Sdes					}
1694238104Sdes				}
1695238104Sdes			}
1696238104Sdes			ldns_rdf_deep_free(hashed_wildcard_name);
1697238104Sdes			if (result == LDNS_STATUS_OK) {
1698238104Sdes				break;
1699238104Sdes			}
1700238104Sdes		}
1701238104Sdes		ldns_rdf_deep_free(closest_encloser);
1702238104Sdes		ldns_rdf_deep_free(wildcard);
1703238104Sdes	} else if (packet_nodata && packet_qtype == LDNS_RR_TYPE_DS) {
1704238104Sdes		/* section 8.6 */
1705238104Sdes		/* note: up to XXX this is the same as for 8.5 */
1706238104Sdes		hashed_name = ldns_nsec3_hash_name_frm_nsec3(ldns_rr_list_rr(nsecs,
1707238104Sdes														 0),
1708238104Sdes											ldns_rr_owner(rr)
1709238104Sdes											);
1710238104Sdes		(void) ldns_dname_cat(hashed_name, zone_name);
1711238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1712238104Sdes			if (ldns_dname_compare(hashed_name,
1713238104Sdes							   ldns_rr_owner(ldns_rr_list_rr(nsecs,
1714238104Sdes													   i)))
1715238104Sdes			    == 0) {
1716238104Sdes				if (!ldns_nsec_bitmap_covers_type(
1717238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1718238104Sdes					    LDNS_RR_TYPE_DS)
1719238104Sdes				    &&
1720238104Sdes				    !ldns_nsec_bitmap_covers_type(
1721238104Sdes					    ldns_nsec3_bitmap(ldns_rr_list_rr(nsecs, i)),
1722238104Sdes					    LDNS_RR_TYPE_CNAME)) {
1723238104Sdes					result = LDNS_STATUS_OK;
1724238104Sdes					if (match) {
1725238104Sdes						*match = ldns_rr_list_rr(nsecs, i);
1726238104Sdes					}
1727238104Sdes					goto done;
1728238104Sdes				}
1729238104Sdes			}
1730238104Sdes		}
1731238104Sdes
1732238104Sdes		/* XXX see note above */
1733238104Sdes		result = LDNS_STATUS_DNSSEC_NSEC_RR_NOT_COVERED;
1734238104Sdes
1735238104Sdes		closest_encloser = ldns_dnssec_nsec3_closest_encloser(
1736238104Sdes				   ldns_rr_owner(rr),
1737238104Sdes				   ldns_rr_get_type(rr),
1738238104Sdes				   nsecs);
1739238104Sdes		if(!closest_encloser) {
1740238104Sdes			result = LDNS_STATUS_NSEC3_ERR;
1741238104Sdes			goto done;
1742238104Sdes		}
1743238104Sdes		/* Now check if we have a Opt-Out NSEC3 that covers the "next closer"*/
1744238104Sdes
1745238104Sdes		if (ldns_dname_label_count(closest_encloser) + 1
1746238104Sdes		    >= ldns_dname_label_count(ldns_rr_owner(rr))) {
1747238104Sdes
1748238104Sdes			/* Query name *is* the "next closer". */
1749238104Sdes			hashed_next_closer = hashed_name;
1750238104Sdes		} else {
1751238104Sdes
1752238104Sdes			/* "next closer" has less labels than the query name.
1753238104Sdes			 * Create the name and hash it.
1754238104Sdes			 */
1755238104Sdes			next_closer = ldns_dname_clone_from(
1756238104Sdes					ldns_rr_owner(rr),
1757238104Sdes					ldns_dname_label_count(ldns_rr_owner(rr))
1758238104Sdes					- (ldns_dname_label_count(closest_encloser) + 1)
1759238104Sdes					);
1760238104Sdes			hashed_next_closer = ldns_nsec3_hash_name_frm_nsec3(
1761238104Sdes					ldns_rr_list_rr(nsecs, 0),
1762238104Sdes					next_closer
1763238104Sdes					);
1764238104Sdes			(void) ldns_dname_cat(hashed_next_closer, zone_name);
1765238104Sdes		}
1766238104Sdes		/* Find the NSEC3 that covers the "next closer" */
1767238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(nsecs); i++) {
1768238104Sdes			if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, i),
1769238104Sdes			                          hashed_next_closer) &&
1770238104Sdes				ldns_nsec3_optout(ldns_rr_list_rr(nsecs, i))) {
1771238104Sdes
1772238104Sdes				result = LDNS_STATUS_OK;
1773238104Sdes				if (match) {
1774238104Sdes					*match = ldns_rr_list_rr(nsecs, i);
1775238104Sdes				}
1776238104Sdes				break;
1777238104Sdes			}
1778238104Sdes		}
1779238104Sdes		if (ldns_dname_label_count(closest_encloser) + 1
1780238104Sdes		    < ldns_dname_label_count(ldns_rr_owner(rr))) {
1781238104Sdes
1782238104Sdes			/* "next closer" has less labels than the query name.
1783238104Sdes			 * Dispose of the temporary variables that held that name.
1784238104Sdes			 */
1785238104Sdes			ldns_rdf_deep_free(hashed_next_closer);
1786238104Sdes			ldns_rdf_deep_free(next_closer);
1787238104Sdes		}
1788238104Sdes		ldns_rdf_deep_free(closest_encloser);
1789238104Sdes	}
1790238104Sdes
1791238104Sdes done:
1792238104Sdes	ldns_rdf_deep_free(zone_name);
1793238104Sdes	return result;
1794238104Sdes}
1795238104Sdes
1796238104Sdesldns_status
1797238104Sdesldns_dnssec_verify_denial_nsec3(ldns_rr *rr,
1798238104Sdes						  ldns_rr_list *nsecs,
1799238104Sdes						  ldns_rr_list *rrsigs,
1800238104Sdes						  ldns_pkt_rcode packet_rcode,
1801238104Sdes						  ldns_rr_type packet_qtype,
1802238104Sdes						  bool packet_nodata)
1803238104Sdes{
1804238104Sdes	return ldns_dnssec_verify_denial_nsec3_match(
1805238104Sdes				rr, nsecs, rrsigs, packet_rcode,
1806238104Sdes				packet_qtype, packet_nodata, NULL
1807238104Sdes	       );
1808238104Sdes}
1809238104Sdes
1810238104Sdes#ifdef USE_GOST
1811238104SdesEVP_PKEY*
1812238104Sdesldns_gost2pkey_raw(unsigned char* key, size_t keylen)
1813238104Sdes{
1814238104Sdes	/* prefix header for X509 encoding */
1815238104Sdes	uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
1816238104Sdes		0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
1817238104Sdes		0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
1818238104Sdes		0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
1819238104Sdes	unsigned char encoded[37+64];
1820238104Sdes	const unsigned char* pp;
1821238104Sdes	if(keylen != 64) {
1822238104Sdes		/* key wrong size */
1823238104Sdes		return NULL;
1824238104Sdes	}
1825238104Sdes
1826238104Sdes	/* create evp_key */
1827238104Sdes	memmove(encoded, asn, 37);
1828238104Sdes	memmove(encoded+37, key, 64);
1829238104Sdes	pp = (unsigned char*)&encoded[0];
1830238104Sdes
1831238104Sdes	return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
1832238104Sdes}
1833238104Sdes
1834238104Sdesstatic ldns_status
1835238104Sdesldns_verify_rrsig_gost_raw(unsigned char* sig, size_t siglen,
1836238104Sdes	ldns_buffer* rrset, unsigned char* key, size_t keylen)
1837238104Sdes{
1838238104Sdes	EVP_PKEY *evp_key;
1839238104Sdes	ldns_status result;
1840238104Sdes
1841238104Sdes	(void) ldns_key_EVP_load_gost_id();
1842238104Sdes	evp_key = ldns_gost2pkey_raw(key, keylen);
1843238104Sdes	if(!evp_key) {
1844238104Sdes		/* could not convert key */
1845238104Sdes		return LDNS_STATUS_CRYPTO_BOGUS;
1846238104Sdes	}
1847238104Sdes
1848238104Sdes	/* verify signature */
1849238104Sdes	result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset,
1850238104Sdes		evp_key, EVP_get_digestbyname("md_gost94"));
1851238104Sdes	EVP_PKEY_free(evp_key);
1852238104Sdes
1853238104Sdes	return result;
1854238104Sdes}
1855238104Sdes#endif
1856238104Sdes
1857238104Sdes#ifdef USE_ECDSA
1858238104SdesEVP_PKEY*
1859238104Sdesldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
1860238104Sdes{
1861238104Sdes	unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
1862238104Sdes        const unsigned char* pp = buf;
1863238104Sdes        EVP_PKEY *evp_key;
1864238104Sdes        EC_KEY *ec;
1865238104Sdes	/* check length, which uncompressed must be 2 bignums */
1866238104Sdes        if(algo == LDNS_ECDSAP256SHA256) {
1867238104Sdes		if(keylen != 2*256/8) return NULL;
1868238104Sdes                ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
1869238104Sdes        } else if(algo == LDNS_ECDSAP384SHA384) {
1870238104Sdes		if(keylen != 2*384/8) return NULL;
1871238104Sdes                ec = EC_KEY_new_by_curve_name(NID_secp384r1);
1872238104Sdes        } else    ec = NULL;
1873238104Sdes        if(!ec) return NULL;
1874238104Sdes	if(keylen+1 > sizeof(buf))
1875238104Sdes		return NULL; /* sanity check */
1876238104Sdes	/* prepend the 0x02 (from docs) (or actually 0x04 from implementation
1877238104Sdes	 * of openssl) for uncompressed data */
1878238104Sdes	buf[0] = POINT_CONVERSION_UNCOMPRESSED;
1879238104Sdes	memmove(buf+1, key, keylen);
1880238104Sdes        if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
1881238104Sdes                EC_KEY_free(ec);
1882238104Sdes                return NULL;
1883238104Sdes        }
1884238104Sdes        evp_key = EVP_PKEY_new();
1885238104Sdes        if(!evp_key) {
1886238104Sdes                EC_KEY_free(ec);
1887238104Sdes                return NULL;
1888238104Sdes        }
1889238104Sdes        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
1890238104Sdes		EVP_PKEY_free(evp_key);
1891238104Sdes		EC_KEY_free(ec);
1892238104Sdes		return NULL;
1893238104Sdes	}
1894238104Sdes        return evp_key;
1895238104Sdes}
1896238104Sdes
1897238104Sdesstatic ldns_status
1898238104Sdesldns_verify_rrsig_ecdsa_raw(unsigned char* sig, size_t siglen,
1899238104Sdes	ldns_buffer* rrset, unsigned char* key, size_t keylen, uint8_t algo)
1900238104Sdes{
1901238104Sdes        EVP_PKEY *evp_key;
1902238104Sdes        ldns_status result;
1903238104Sdes        const EVP_MD *d;
1904238104Sdes
1905238104Sdes        evp_key = ldns_ecdsa2pkey_raw(key, keylen, algo);
1906238104Sdes        if(!evp_key) {
1907238104Sdes		/* could not convert key */
1908238104Sdes		return LDNS_STATUS_CRYPTO_BOGUS;
1909238104Sdes        }
1910238104Sdes        if(algo == LDNS_ECDSAP256SHA256)
1911238104Sdes                d = EVP_sha256();
1912238104Sdes        else    d = EVP_sha384(); /* LDNS_ECDSAP384SHA384 */
1913238104Sdes	result = ldns_verify_rrsig_evp_raw(sig, siglen, rrset, evp_key, d);
1914238104Sdes	EVP_PKEY_free(evp_key);
1915238104Sdes	return result;
1916238104Sdes}
1917238104Sdes#endif
1918238104Sdes
1919238104Sdesldns_status
1920238104Sdesldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf, ldns_buffer *verify_buf,
1921238104Sdes					 ldns_buffer *key_buf, uint8_t algo)
1922238104Sdes{
1923238104Sdes	return ldns_verify_rrsig_buffers_raw(
1924238104Sdes			 (unsigned char*)ldns_buffer_begin(rawsig_buf),
1925238104Sdes			 ldns_buffer_position(rawsig_buf),
1926238104Sdes			 verify_buf,
1927238104Sdes			 (unsigned char*)ldns_buffer_begin(key_buf),
1928238104Sdes			 ldns_buffer_position(key_buf), algo);
1929238104Sdes}
1930238104Sdes
1931238104Sdesldns_status
1932238104Sdesldns_verify_rrsig_buffers_raw(unsigned char* sig, size_t siglen,
1933238104Sdes						ldns_buffer *verify_buf, unsigned char* key, size_t keylen,
1934238104Sdes						uint8_t algo)
1935238104Sdes{
1936238104Sdes	/* check for right key */
1937238104Sdes	switch(algo) {
1938238104Sdes	case LDNS_DSA:
1939238104Sdes	case LDNS_DSA_NSEC3:
1940238104Sdes		return ldns_verify_rrsig_dsa_raw(sig,
1941238104Sdes								   siglen,
1942238104Sdes								   verify_buf,
1943238104Sdes								   key,
1944238104Sdes								   keylen);
1945238104Sdes		break;
1946238104Sdes	case LDNS_RSASHA1:
1947238104Sdes	case LDNS_RSASHA1_NSEC3:
1948238104Sdes		return ldns_verify_rrsig_rsasha1_raw(sig,
1949238104Sdes									  siglen,
1950238104Sdes									  verify_buf,
1951238104Sdes									  key,
1952238104Sdes									  keylen);
1953238104Sdes		break;
1954238104Sdes#ifdef USE_SHA2
1955238104Sdes	case LDNS_RSASHA256:
1956238104Sdes		return ldns_verify_rrsig_rsasha256_raw(sig,
1957238104Sdes									    siglen,
1958238104Sdes									    verify_buf,
1959238104Sdes									    key,
1960238104Sdes									    keylen);
1961238104Sdes		break;
1962238104Sdes	case LDNS_RSASHA512:
1963238104Sdes		return ldns_verify_rrsig_rsasha512_raw(sig,
1964238104Sdes									    siglen,
1965238104Sdes									    verify_buf,
1966238104Sdes									    key,
1967238104Sdes									    keylen);
1968238104Sdes		break;
1969238104Sdes#endif
1970238104Sdes#ifdef USE_GOST
1971238104Sdes	case LDNS_ECC_GOST:
1972238104Sdes		return ldns_verify_rrsig_gost_raw(sig, siglen, verify_buf,
1973238104Sdes			key, keylen);
1974238104Sdes		break;
1975238104Sdes#endif
1976238104Sdes#ifdef USE_ECDSA
1977238104Sdes        case LDNS_ECDSAP256SHA256:
1978238104Sdes        case LDNS_ECDSAP384SHA384:
1979238104Sdes		return ldns_verify_rrsig_ecdsa_raw(sig, siglen, verify_buf,
1980238104Sdes			key, keylen, algo);
1981238104Sdes		break;
1982238104Sdes#endif
1983238104Sdes	case LDNS_RSAMD5:
1984238104Sdes		return ldns_verify_rrsig_rsamd5_raw(sig,
1985238104Sdes									 siglen,
1986238104Sdes									 verify_buf,
1987238104Sdes									 key,
1988238104Sdes									 keylen);
1989238104Sdes		break;
1990238104Sdes	default:
1991238104Sdes		/* do you know this alg?! */
1992238104Sdes		return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
1993238104Sdes	}
1994238104Sdes}
1995238104Sdes
1996238104Sdes
1997238104Sdes/**
1998238104Sdes * Reset the ttl in the rrset with the orig_ttl from the sig
1999238104Sdes * and update owner name if it was wildcard
2000238104Sdes * Also canonicalizes the rrset.
2001238104Sdes * @param rrset: rrset to modify
2002238104Sdes * @param sig: signature to take TTL and wildcard values from
2003238104Sdes */
2004238104Sdesstatic void
2005238104Sdesldns_rrset_use_signature_ttl(ldns_rr_list* rrset_clone, ldns_rr* rrsig)
2006238104Sdes{
2007238104Sdes	uint32_t orig_ttl;
2008238104Sdes	uint16_t i;
2009238104Sdes	uint8_t label_count;
2010238104Sdes	ldns_rdf *wildcard_name;
2011238104Sdes	ldns_rdf *wildcard_chopped;
2012238104Sdes	ldns_rdf *wildcard_chopped_tmp;
2013238104Sdes
2014238104Sdes	if ((rrsig == NULL) || ldns_rr_rd_count(rrsig) < 4) {
2015238104Sdes		return;
2016238104Sdes	}
2017238104Sdes
2018238104Sdes	orig_ttl = ldns_rdf2native_int32( ldns_rr_rdf(rrsig, 3));
2019238104Sdes	label_count = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 2));
2020238104Sdes
2021238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
2022238104Sdes		if (label_count <
2023238104Sdes		    ldns_dname_label_count(
2024238104Sdes			   ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)))) {
2025238104Sdes			(void) ldns_str2rdf_dname(&wildcard_name, "*");
2026238104Sdes			wildcard_chopped = ldns_rdf_clone(ldns_rr_owner(
2027238104Sdes				ldns_rr_list_rr(rrset_clone, i)));
2028238104Sdes			while (label_count < ldns_dname_label_count(wildcard_chopped)) {
2029238104Sdes				wildcard_chopped_tmp = ldns_dname_left_chop(
2030238104Sdes					wildcard_chopped);
2031238104Sdes				ldns_rdf_deep_free(wildcard_chopped);
2032238104Sdes				wildcard_chopped = wildcard_chopped_tmp;
2033238104Sdes			}
2034238104Sdes			(void) ldns_dname_cat(wildcard_name, wildcard_chopped);
2035238104Sdes			ldns_rdf_deep_free(wildcard_chopped);
2036238104Sdes			ldns_rdf_deep_free(ldns_rr_owner(ldns_rr_list_rr(
2037238104Sdes				rrset_clone, i)));
2038238104Sdes			ldns_rr_set_owner(ldns_rr_list_rr(rrset_clone, i),
2039238104Sdes				wildcard_name);
2040238104Sdes		}
2041238104Sdes		ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i), orig_ttl);
2042238104Sdes		/* convert to lowercase */
2043238104Sdes		ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i));
2044238104Sdes	}
2045238104Sdes}
2046238104Sdes
2047238104Sdes/**
2048238104Sdes * Make raw signature buffer out of rrsig
2049238104Sdes * @param rawsig_buf: raw signature buffer for result
2050238104Sdes * @param rrsig: signature to convert
2051238104Sdes * @return OK or more specific error.
2052238104Sdes */
2053238104Sdesstatic ldns_status
2054238104Sdesldns_rrsig2rawsig_buffer(ldns_buffer* rawsig_buf, ldns_rr* rrsig)
2055238104Sdes{
2056238104Sdes	uint8_t sig_algo;
2057238104Sdes
2058238104Sdes	if (rrsig == NULL) {
2059238104Sdes		return LDNS_STATUS_CRYPTO_NO_RRSIG;
2060238104Sdes	}
2061238104Sdes	if (ldns_rr_rdf(rrsig, 1) == NULL) {
2062238104Sdes		return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
2063238104Sdes	}
2064238104Sdes	sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1));
2065238104Sdes	/* check for known and implemented algo's now (otherwise
2066238104Sdes	 * the function could return a wrong error
2067238104Sdes	 */
2068238104Sdes	/* create a buffer with signature rdata */
2069238104Sdes	/* for some algorithms we need other data than for others... */
2070238104Sdes	/* (the DSA API wants DER encoding for instance) */
2071238104Sdes
2072238104Sdes	switch(sig_algo) {
2073238104Sdes	case LDNS_RSAMD5:
2074238104Sdes	case LDNS_RSASHA1:
2075238104Sdes	case LDNS_RSASHA1_NSEC3:
2076238104Sdes#ifdef USE_SHA2
2077238104Sdes	case LDNS_RSASHA256:
2078238104Sdes	case LDNS_RSASHA512:
2079238104Sdes#endif
2080238104Sdes#ifdef USE_GOST
2081238104Sdes	case LDNS_ECC_GOST:
2082238104Sdes#endif
2083238104Sdes		if (ldns_rr_rdf(rrsig, 8) == NULL) {
2084238104Sdes			return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
2085238104Sdes		}
2086238104Sdes		if (ldns_rdf2buffer_wire(rawsig_buf, ldns_rr_rdf(rrsig, 8))
2087238104Sdes			       	!= LDNS_STATUS_OK) {
2088238104Sdes			return LDNS_STATUS_MEM_ERR;
2089238104Sdes		}
2090238104Sdes		break;
2091238104Sdes	case LDNS_DSA:
2092238104Sdes	case LDNS_DSA_NSEC3:
2093238104Sdes		/* EVP takes rfc2459 format, which is a tad longer than dns format */
2094238104Sdes		if (ldns_rr_rdf(rrsig, 8) == NULL) {
2095238104Sdes			return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
2096238104Sdes		}
2097238104Sdes		if (ldns_convert_dsa_rrsig_rdf2asn1(
2098238104Sdes					rawsig_buf, ldns_rr_rdf(rrsig, 8))
2099238104Sdes				!= LDNS_STATUS_OK) {
2100238104Sdes			/*
2101238104Sdes			  if (ldns_rdf2buffer_wire(rawsig_buf,
2102238104Sdes			  ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) {
2103238104Sdes			*/
2104238104Sdes			return LDNS_STATUS_MEM_ERR;
2105238104Sdes		}
2106238104Sdes		break;
2107238104Sdes#ifdef USE_ECDSA
2108238104Sdes        case LDNS_ECDSAP256SHA256:
2109238104Sdes        case LDNS_ECDSAP384SHA384:
2110238104Sdes                /* EVP produces an ASN prefix on the signature, which is
2111238104Sdes                 * not used in the DNS */
2112238104Sdes		if (ldns_rr_rdf(rrsig, 8) == NULL) {
2113238104Sdes			return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
2114238104Sdes		}
2115238104Sdes		if (ldns_convert_ecdsa_rrsig_rdf2asn1(
2116238104Sdes					rawsig_buf, ldns_rr_rdf(rrsig, 8))
2117238104Sdes				!= LDNS_STATUS_OK) {
2118238104Sdes			return LDNS_STATUS_MEM_ERR;
2119238104Sdes                }
2120238104Sdes                break;
2121238104Sdes#endif
2122238104Sdes	case LDNS_DH:
2123238104Sdes	case LDNS_ECC:
2124238104Sdes	case LDNS_INDIRECT:
2125238104Sdes		return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL;
2126238104Sdes	default:
2127238104Sdes		return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
2128238104Sdes	}
2129238104Sdes	return LDNS_STATUS_OK;
2130238104Sdes}
2131238104Sdes
2132238104Sdes/**
2133238104Sdes * Check RRSIG timestamps against the given 'now' time.
2134238104Sdes * @param rrsig: signature to check.
2135238104Sdes * @param now: the current time in seconds epoch.
2136238104Sdes * @return status code LDNS_STATUS_OK if all is fine.
2137238104Sdes */
2138238104Sdesstatic ldns_status
2139238104Sdesldns_rrsig_check_timestamps(ldns_rr* rrsig, time_t now)
2140238104Sdes{
2141238104Sdes	int32_t inception, expiration;
2142238104Sdes
2143238104Sdes	/* check the signature time stamps */
2144238104Sdes	inception = (int32_t)ldns_rdf2native_time_t(
2145238104Sdes		ldns_rr_rrsig_inception(rrsig));
2146238104Sdes	expiration = (int32_t)ldns_rdf2native_time_t(
2147238104Sdes		ldns_rr_rrsig_expiration(rrsig));
2148238104Sdes
2149238104Sdes	if (expiration - inception < 0) {
2150238104Sdes		/* bad sig, expiration before inception?? Tsssg */
2151238104Sdes		return LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION;
2152238104Sdes	}
2153238104Sdes	if (((int32_t) now) - inception < 0) {
2154238104Sdes		/* bad sig, inception date has not yet come to pass */
2155238104Sdes		return LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED;
2156238104Sdes	}
2157238104Sdes	if (expiration - ((int32_t) now) < 0) {
2158238104Sdes		/* bad sig, expiration date has passed */
2159238104Sdes		return LDNS_STATUS_CRYPTO_SIG_EXPIRED;
2160238104Sdes	}
2161238104Sdes	return LDNS_STATUS_OK;
2162238104Sdes}
2163238104Sdes
2164238104Sdes/**
2165238104Sdes * Prepare for verification.
2166238104Sdes * @param rawsig_buf: raw signature buffer made ready.
2167238104Sdes * @param verify_buf: data for verification buffer made ready.
2168238104Sdes * @param rrset_clone: made ready.
2169238104Sdes * @param rrsig: signature to prepare for.
2170238104Sdes * @return LDNS_STATUS_OK is all went well. Otherwise specific error.
2171238104Sdes */
2172238104Sdesstatic ldns_status
2173238104Sdesldns_prepare_for_verify(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf,
2174238104Sdes	ldns_rr_list* rrset_clone, ldns_rr* rrsig)
2175238104Sdes{
2176238104Sdes	ldns_status result;
2177238104Sdes
2178238104Sdes	/* canonicalize the sig */
2179238104Sdes	ldns_dname2canonical(ldns_rr_owner(rrsig));
2180238104Sdes
2181238104Sdes	/* check if the typecovered is equal to the type checked */
2182238104Sdes	if (ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rrsig)) !=
2183238104Sdes	    ldns_rr_get_type(ldns_rr_list_rr(rrset_clone, 0)))
2184238104Sdes		return LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR;
2185238104Sdes
2186238104Sdes	/* create a buffer with b64 signature rdata */
2187238104Sdes	result = ldns_rrsig2rawsig_buffer(rawsig_buf, rrsig);
2188238104Sdes	if(result != LDNS_STATUS_OK)
2189238104Sdes		return result;
2190238104Sdes
2191238104Sdes	/* use TTL from signature. Use wildcard names for wildcards */
2192238104Sdes	/* also canonicalizes rrset_clone */
2193238104Sdes	ldns_rrset_use_signature_ttl(rrset_clone, rrsig);
2194238104Sdes
2195238104Sdes	/* sort the rrset in canonical order  */
2196238104Sdes	ldns_rr_list_sort(rrset_clone);
2197238104Sdes
2198238104Sdes	/* put the signature rr (without the b64) to the verify_buf */
2199238104Sdes	if (ldns_rrsig2buffer_wire(verify_buf, rrsig) != LDNS_STATUS_OK)
2200238104Sdes		return LDNS_STATUS_MEM_ERR;
2201238104Sdes
2202238104Sdes	/* add the rrset in verify_buf */
2203238104Sdes	if(ldns_rr_list2buffer_wire(verify_buf, rrset_clone)
2204238104Sdes		!= LDNS_STATUS_OK)
2205238104Sdes		return LDNS_STATUS_MEM_ERR;
2206238104Sdes
2207238104Sdes	return LDNS_STATUS_OK;
2208238104Sdes}
2209238104Sdes
2210238104Sdes/**
2211238104Sdes * Check if a key matches a signature.
2212238104Sdes * Checks keytag, sigalgo and signature.
2213238104Sdes * @param rawsig_buf: raw signature buffer for verify
2214238104Sdes * @param verify_buf: raw data buffer for verify
2215238104Sdes * @param rrsig: the rrsig
2216238104Sdes * @param key: key to attempt.
2217238104Sdes * @return LDNS_STATUS_OK if OK, else some specific error.
2218238104Sdes */
2219238104Sdesstatic ldns_status
2220238104Sdesldns_verify_test_sig_key(ldns_buffer* rawsig_buf, ldns_buffer* verify_buf,
2221238104Sdes	ldns_rr* rrsig, ldns_rr* key)
2222238104Sdes{
2223238104Sdes	uint8_t sig_algo;
2224238104Sdes
2225238104Sdes	if (rrsig == NULL) {
2226238104Sdes		return LDNS_STATUS_CRYPTO_NO_RRSIG;
2227238104Sdes	}
2228238104Sdes	if (ldns_rr_rdf(rrsig, 1) == NULL) {
2229238104Sdes		return LDNS_STATUS_MISSING_RDATA_FIELDS_RRSIG;
2230238104Sdes	}
2231238104Sdes	sig_algo = ldns_rdf2native_int8(ldns_rr_rdf(rrsig, 1));
2232238104Sdes
2233238104Sdes	/* before anything, check if the keytags match */
2234238104Sdes	if (ldns_calc_keytag(key)
2235238104Sdes	    ==
2236238104Sdes	    ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig))
2237238104Sdes	    ) {
2238238104Sdes		ldns_buffer* key_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
2239238104Sdes		ldns_status result = LDNS_STATUS_ERR;
2240238104Sdes
2241238104Sdes		/* put the key-data in a buffer, that's the third rdf, with
2242238104Sdes		 * the base64 encoded key data */
2243238104Sdes		if (ldns_rr_rdf(key, 3) == NULL) {
2244238104Sdes			ldns_buffer_free(key_buf);
2245238104Sdes			return LDNS_STATUS_MISSING_RDATA_FIELDS_KEY;
2246238104Sdes		}
2247238104Sdes		if (ldns_rdf2buffer_wire(key_buf, ldns_rr_rdf(key, 3))
2248238104Sdes			       	!= LDNS_STATUS_OK) {
2249238104Sdes			ldns_buffer_free(key_buf);
2250238104Sdes			/* returning is bad might screw up
2251238104Sdes			   good keys later in the list
2252238104Sdes			   what to do? */
2253238104Sdes			return LDNS_STATUS_ERR;
2254238104Sdes		}
2255238104Sdes
2256238104Sdes		if (ldns_rr_rdf(key, 2) == NULL) {
2257238104Sdes			result = LDNS_STATUS_MISSING_RDATA_FIELDS_KEY;
2258238104Sdes		}
2259238104Sdes		else if (sig_algo == ldns_rdf2native_int8(
2260238104Sdes					ldns_rr_rdf(key, 2))) {
2261238104Sdes			result = ldns_verify_rrsig_buffers(rawsig_buf,
2262238104Sdes				verify_buf, key_buf, sig_algo);
2263238104Sdes		} else {
2264238104Sdes			/* No keys with the corresponding algorithm are found */
2265238104Sdes			result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
2266238104Sdes		}
2267238104Sdes
2268238104Sdes		ldns_buffer_free(key_buf);
2269238104Sdes		return result;
2270238104Sdes	}
2271238104Sdes	else {
2272238104Sdes		/* No keys with the corresponding keytag are found */
2273238104Sdes		return LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
2274238104Sdes	}
2275238104Sdes}
2276238104Sdes
2277238104Sdes/*
2278238104Sdes * to verify:
2279238104Sdes * - create the wire fmt of the b64 key rdata
2280238104Sdes * - create the wire fmt of the sorted rrset
2281238104Sdes * - create the wire fmt of the b64 sig rdata
2282238104Sdes * - create the wire fmt of the sig without the b64 rdata
2283238104Sdes * - cat the sig data (without b64 rdata) to the rrset
2284238104Sdes * - verify the rrset+sig, with the b64 data and the b64 key data
2285238104Sdes */
2286238104Sdesldns_status
2287238104Sdesldns_verify_rrsig_keylist_time(
2288238104Sdes		ldns_rr_list *rrset,
2289238104Sdes		ldns_rr *rrsig,
2290238104Sdes		const ldns_rr_list *keys,
2291238104Sdes		time_t check_time,
2292238104Sdes		ldns_rr_list *good_keys)
2293238104Sdes{
2294238104Sdes	ldns_status result;
2295238104Sdes	ldns_rr_list *valid = ldns_rr_list_new();
2296238104Sdes	if (!valid)
2297238104Sdes		return LDNS_STATUS_MEM_ERR;
2298238104Sdes
2299238104Sdes	result = ldns_verify_rrsig_keylist_notime(rrset, rrsig, keys, valid);
2300238104Sdes	if(result != LDNS_STATUS_OK) {
2301238104Sdes		ldns_rr_list_free(valid);
2302238104Sdes		return result;
2303238104Sdes	}
2304238104Sdes
2305238104Sdes	/* check timestamps last; its OK except time */
2306238104Sdes	result = ldns_rrsig_check_timestamps(rrsig, check_time);
2307238104Sdes	if(result != LDNS_STATUS_OK) {
2308238104Sdes		ldns_rr_list_free(valid);
2309238104Sdes		return result;
2310238104Sdes	}
2311238104Sdes
2312238104Sdes	ldns_rr_list_cat(good_keys, valid);
2313238104Sdes	ldns_rr_list_free(valid);
2314238104Sdes	return LDNS_STATUS_OK;
2315238104Sdes}
2316238104Sdes
2317238104Sdes/*
2318238104Sdes * to verify:
2319238104Sdes * - create the wire fmt of the b64 key rdata
2320238104Sdes * - create the wire fmt of the sorted rrset
2321238104Sdes * - create the wire fmt of the b64 sig rdata
2322238104Sdes * - create the wire fmt of the sig without the b64 rdata
2323238104Sdes * - cat the sig data (without b64 rdata) to the rrset
2324238104Sdes * - verify the rrset+sig, with the b64 data and the b64 key data
2325238104Sdes */
2326238104Sdesldns_status
2327238104Sdesldns_verify_rrsig_keylist(ldns_rr_list *rrset,
2328238104Sdes					 ldns_rr *rrsig,
2329238104Sdes					 const ldns_rr_list *keys,
2330238104Sdes					 ldns_rr_list *good_keys)
2331238104Sdes{
2332238104Sdes	return ldns_verify_rrsig_keylist_time(
2333238104Sdes			rrset, rrsig, keys, ldns_time(NULL), good_keys);
2334238104Sdes}
2335238104Sdes
2336238104Sdesldns_status
2337238104Sdesldns_verify_rrsig_keylist_notime(ldns_rr_list *rrset,
2338238104Sdes					 ldns_rr *rrsig,
2339238104Sdes					 const ldns_rr_list *keys,
2340238104Sdes					 ldns_rr_list *good_keys)
2341238104Sdes{
2342238104Sdes	ldns_buffer *rawsig_buf;
2343238104Sdes	ldns_buffer *verify_buf;
2344238104Sdes	uint16_t i;
2345238104Sdes	ldns_status result, status;
2346238104Sdes	ldns_rr_list *rrset_clone;
2347238104Sdes	ldns_rr_list *validkeys;
2348238104Sdes
2349238104Sdes	if (!rrset) {
2350238104Sdes		return LDNS_STATUS_ERR;
2351238104Sdes	}
2352238104Sdes
2353238104Sdes	validkeys = ldns_rr_list_new();
2354238104Sdes	if (!validkeys) {
2355238104Sdes		return LDNS_STATUS_MEM_ERR;
2356238104Sdes	}
2357238104Sdes
2358238104Sdes	/* clone the rrset so that we can fiddle with it */
2359238104Sdes	rrset_clone = ldns_rr_list_clone(rrset);
2360238104Sdes
2361238104Sdes	/* create the buffers which will certainly hold the raw data */
2362238104Sdes	rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
2363238104Sdes	verify_buf  = ldns_buffer_new(LDNS_MAX_PACKETLEN);
2364238104Sdes
2365238104Sdes	result = ldns_prepare_for_verify(rawsig_buf, verify_buf,
2366238104Sdes		rrset_clone, rrsig);
2367238104Sdes	if(result != LDNS_STATUS_OK) {
2368238104Sdes		ldns_buffer_free(verify_buf);
2369238104Sdes		ldns_buffer_free(rawsig_buf);
2370238104Sdes		ldns_rr_list_deep_free(rrset_clone);
2371238104Sdes		ldns_rr_list_free(validkeys);
2372238104Sdes		return result;
2373238104Sdes	}
2374238104Sdes
2375238104Sdes	result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
2376238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(keys); i++) {
2377238104Sdes		status = ldns_verify_test_sig_key(rawsig_buf, verify_buf,
2378238104Sdes			rrsig, ldns_rr_list_rr(keys, i));
2379238104Sdes		if (status == LDNS_STATUS_OK) {
2380238104Sdes			/* one of the keys has matched, don't break
2381238104Sdes			 * here, instead put the 'winning' key in
2382238104Sdes			 * the validkey list and return the list
2383238104Sdes			 * later */
2384238104Sdes			if (!ldns_rr_list_push_rr(validkeys,
2385238104Sdes				ldns_rr_list_rr(keys,i))) {
2386238104Sdes				/* couldn't push the key?? */
2387238104Sdes				ldns_buffer_free(rawsig_buf);
2388238104Sdes				ldns_buffer_free(verify_buf);
2389238104Sdes				ldns_rr_list_deep_free(rrset_clone);
2390238104Sdes				ldns_rr_list_free(validkeys);
2391238104Sdes				return LDNS_STATUS_MEM_ERR;
2392238104Sdes			}
2393238104Sdes
2394238104Sdes			result = status;
2395238104Sdes		}
2396238104Sdes
2397238104Sdes		if (result == LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY) {
2398238104Sdes			result = status;
2399238104Sdes		}
2400238104Sdes	}
2401238104Sdes
2402238104Sdes	/* no longer needed */
2403238104Sdes	ldns_rr_list_deep_free(rrset_clone);
2404238104Sdes	ldns_buffer_free(rawsig_buf);
2405238104Sdes	ldns_buffer_free(verify_buf);
2406238104Sdes
2407238104Sdes	if (ldns_rr_list_rr_count(validkeys) == 0) {
2408238104Sdes		/* no keys were added, return last error */
2409238104Sdes		ldns_rr_list_free(validkeys);
2410238104Sdes		return result;
2411238104Sdes	}
2412238104Sdes
2413238104Sdes	/* do not check timestamps */
2414238104Sdes
2415238104Sdes	ldns_rr_list_cat(good_keys, validkeys);
2416238104Sdes	ldns_rr_list_free(validkeys);
2417238104Sdes	return LDNS_STATUS_OK;
2418238104Sdes}
2419238104Sdes
2420238104Sdesldns_status
2421238104Sdesldns_verify_rrsig_time(
2422238104Sdes		ldns_rr_list *rrset,
2423238104Sdes		ldns_rr *rrsig,
2424238104Sdes		ldns_rr *key,
2425238104Sdes		time_t check_time)
2426238104Sdes{
2427238104Sdes	ldns_buffer *rawsig_buf;
2428238104Sdes	ldns_buffer *verify_buf;
2429238104Sdes	ldns_status result;
2430238104Sdes	ldns_rr_list *rrset_clone;
2431238104Sdes
2432238104Sdes	if (!rrset) {
2433238104Sdes		return LDNS_STATUS_NO_DATA;
2434238104Sdes	}
2435238104Sdes	/* clone the rrset so that we can fiddle with it */
2436238104Sdes	rrset_clone = ldns_rr_list_clone(rrset);
2437238104Sdes	/* create the buffers which will certainly hold the raw data */
2438238104Sdes	rawsig_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
2439238104Sdes	verify_buf  = ldns_buffer_new(LDNS_MAX_PACKETLEN);
2440238104Sdes
2441238104Sdes	result = ldns_prepare_for_verify(rawsig_buf, verify_buf,
2442238104Sdes		rrset_clone, rrsig);
2443238104Sdes	if(result != LDNS_STATUS_OK) {
2444238104Sdes		ldns_rr_list_deep_free(rrset_clone);
2445238104Sdes		ldns_buffer_free(rawsig_buf);
2446238104Sdes		ldns_buffer_free(verify_buf);
2447238104Sdes		return result;
2448238104Sdes	}
2449238104Sdes	result = ldns_verify_test_sig_key(rawsig_buf, verify_buf,
2450238104Sdes		rrsig, key);
2451238104Sdes	/* no longer needed */
2452238104Sdes	ldns_rr_list_deep_free(rrset_clone);
2453238104Sdes	ldns_buffer_free(rawsig_buf);
2454238104Sdes	ldns_buffer_free(verify_buf);
2455238104Sdes
2456238104Sdes	/* check timestamp last, apart from time its OK */
2457238104Sdes	if(result == LDNS_STATUS_OK)
2458238104Sdes		result = ldns_rrsig_check_timestamps(rrsig, check_time);
2459238104Sdes
2460238104Sdes	return result;
2461238104Sdes}
2462238104Sdes
2463238104Sdesldns_status
2464238104Sdesldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key)
2465238104Sdes{
2466238104Sdes	return ldns_verify_rrsig_time(rrset, rrsig, key, ldns_time(NULL));
2467238104Sdes}
2468238104Sdes
2469238104Sdes
2470238104Sdesldns_status
2471238104Sdesldns_verify_rrsig_evp(ldns_buffer *sig,
2472238104Sdes				  ldns_buffer *rrset,
2473238104Sdes				  EVP_PKEY *key,
2474238104Sdes				  const EVP_MD *digest_type)
2475238104Sdes{
2476238104Sdes	return ldns_verify_rrsig_evp_raw(
2477238104Sdes			 (unsigned char*)ldns_buffer_begin(sig),
2478238104Sdes			 ldns_buffer_position(sig),
2479238104Sdes			 rrset,
2480238104Sdes			 key,
2481238104Sdes			 digest_type);
2482238104Sdes}
2483238104Sdes
2484238104Sdesldns_status
2485238104Sdesldns_verify_rrsig_evp_raw(unsigned char *sig, size_t siglen,
2486238104Sdes					 ldns_buffer *rrset, EVP_PKEY *key, const EVP_MD *digest_type)
2487238104Sdes{
2488238104Sdes	EVP_MD_CTX ctx;
2489238104Sdes	int res;
2490238104Sdes
2491238104Sdes	EVP_MD_CTX_init(&ctx);
2492238104Sdes
2493238104Sdes	EVP_VerifyInit(&ctx, digest_type);
2494238104Sdes	EVP_VerifyUpdate(&ctx,
2495238104Sdes				  ldns_buffer_begin(rrset),
2496238104Sdes				  ldns_buffer_position(rrset));
2497238104Sdes	res = EVP_VerifyFinal(&ctx, sig, (unsigned int) siglen, key);
2498238104Sdes
2499238104Sdes	EVP_MD_CTX_cleanup(&ctx);
2500238104Sdes
2501238104Sdes	if (res == 1) {
2502238104Sdes		return LDNS_STATUS_OK;
2503238104Sdes	} else if (res == 0) {
2504238104Sdes		return LDNS_STATUS_CRYPTO_BOGUS;
2505238104Sdes	}
2506238104Sdes	/* TODO how to communicate internal SSL error?
2507238104Sdes	   let caller use ssl's get_error() */
2508238104Sdes	return LDNS_STATUS_SSL_ERR;
2509238104Sdes}
2510238104Sdes
2511238104Sdesldns_status
2512238104Sdesldns_verify_rrsig_dsa(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
2513238104Sdes{
2514238104Sdes	return ldns_verify_rrsig_dsa_raw(
2515238104Sdes			 (unsigned char*) ldns_buffer_begin(sig),
2516238104Sdes			 ldns_buffer_position(sig),
2517238104Sdes			 rrset,
2518238104Sdes			 (unsigned char*) ldns_buffer_begin(key),
2519238104Sdes			 ldns_buffer_position(key));
2520238104Sdes}
2521238104Sdes
2522238104Sdesldns_status
2523238104Sdesldns_verify_rrsig_rsasha1(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
2524238104Sdes{
2525238104Sdes	return ldns_verify_rrsig_rsasha1_raw(
2526238104Sdes			 (unsigned char*)ldns_buffer_begin(sig),
2527238104Sdes			 ldns_buffer_position(sig),
2528238104Sdes			 rrset,
2529238104Sdes			 (unsigned char*) ldns_buffer_begin(key),
2530238104Sdes			 ldns_buffer_position(key));
2531238104Sdes}
2532238104Sdes
2533238104Sdesldns_status
2534238104Sdesldns_verify_rrsig_rsamd5(ldns_buffer *sig, ldns_buffer *rrset, ldns_buffer *key)
2535238104Sdes{
2536238104Sdes	return ldns_verify_rrsig_rsamd5_raw(
2537238104Sdes			 (unsigned char*)ldns_buffer_begin(sig),
2538238104Sdes			 ldns_buffer_position(sig),
2539238104Sdes			 rrset,
2540238104Sdes			 (unsigned char*) ldns_buffer_begin(key),
2541238104Sdes			 ldns_buffer_position(key));
2542238104Sdes}
2543238104Sdes
2544238104Sdesldns_status
2545238104Sdesldns_verify_rrsig_dsa_raw(unsigned char* sig, size_t siglen,
2546238104Sdes					 ldns_buffer* rrset, unsigned char* key, size_t keylen)
2547238104Sdes{
2548238104Sdes	EVP_PKEY *evp_key;
2549238104Sdes	ldns_status result;
2550238104Sdes
2551238104Sdes	evp_key = EVP_PKEY_new();
2552238104Sdes	if (EVP_PKEY_assign_DSA(evp_key, ldns_key_buf2dsa_raw(key, keylen))) {
2553238104Sdes		result = ldns_verify_rrsig_evp_raw(sig,
2554238104Sdes								siglen,
2555238104Sdes								rrset,
2556238104Sdes								evp_key,
2557238104Sdes								EVP_dss1());
2558238104Sdes	} else {
2559238104Sdes		result = LDNS_STATUS_SSL_ERR;
2560238104Sdes	}
2561238104Sdes	EVP_PKEY_free(evp_key);
2562238104Sdes	return result;
2563238104Sdes
2564238104Sdes}
2565238104Sdes
2566238104Sdesldns_status
2567238104Sdesldns_verify_rrsig_rsasha1_raw(unsigned char* sig, size_t siglen,
2568238104Sdes						ldns_buffer* rrset, unsigned char* key, size_t keylen)
2569238104Sdes{
2570238104Sdes	EVP_PKEY *evp_key;
2571238104Sdes	ldns_status result;
2572238104Sdes
2573238104Sdes	evp_key = EVP_PKEY_new();
2574238104Sdes	if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
2575238104Sdes		result = ldns_verify_rrsig_evp_raw(sig,
2576238104Sdes								siglen,
2577238104Sdes								rrset,
2578238104Sdes								evp_key,
2579238104Sdes								EVP_sha1());
2580238104Sdes	} else {
2581238104Sdes		result = LDNS_STATUS_SSL_ERR;
2582238104Sdes	}
2583238104Sdes	EVP_PKEY_free(evp_key);
2584238104Sdes
2585238104Sdes	return result;
2586238104Sdes}
2587238104Sdes
2588238104Sdesldns_status
2589238104Sdesldns_verify_rrsig_rsasha256_raw(unsigned char* sig,
2590238104Sdes						  size_t siglen,
2591238104Sdes						  ldns_buffer* rrset,
2592238104Sdes						  unsigned char* key,
2593238104Sdes						  size_t keylen)
2594238104Sdes{
2595238104Sdes#ifdef USE_SHA2
2596238104Sdes	EVP_PKEY *evp_key;
2597238104Sdes	ldns_status result;
2598238104Sdes
2599238104Sdes	evp_key = EVP_PKEY_new();
2600238104Sdes	if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
2601238104Sdes		result = ldns_verify_rrsig_evp_raw(sig,
2602238104Sdes								siglen,
2603238104Sdes								rrset,
2604238104Sdes								evp_key,
2605238104Sdes								EVP_sha256());
2606238104Sdes	} else {
2607238104Sdes		result = LDNS_STATUS_SSL_ERR;
2608238104Sdes	}
2609238104Sdes	EVP_PKEY_free(evp_key);
2610238104Sdes
2611238104Sdes	return result;
2612238104Sdes#else
2613238104Sdes	/* touch these to prevent compiler warnings */
2614238104Sdes	(void) sig;
2615238104Sdes	(void) siglen;
2616238104Sdes	(void) rrset;
2617238104Sdes	(void) key;
2618238104Sdes	(void) keylen;
2619238104Sdes	return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
2620238104Sdes#endif
2621238104Sdes}
2622238104Sdes
2623238104Sdesldns_status
2624238104Sdesldns_verify_rrsig_rsasha512_raw(unsigned char* sig,
2625238104Sdes						  size_t siglen,
2626238104Sdes						  ldns_buffer* rrset,
2627238104Sdes						  unsigned char* key,
2628238104Sdes						  size_t keylen)
2629238104Sdes{
2630238104Sdes#ifdef USE_SHA2
2631238104Sdes	EVP_PKEY *evp_key;
2632238104Sdes	ldns_status result;
2633238104Sdes
2634238104Sdes	evp_key = EVP_PKEY_new();
2635238104Sdes	if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
2636238104Sdes		result = ldns_verify_rrsig_evp_raw(sig,
2637238104Sdes								siglen,
2638238104Sdes								rrset,
2639238104Sdes								evp_key,
2640238104Sdes								EVP_sha512());
2641238104Sdes	} else {
2642238104Sdes		result = LDNS_STATUS_SSL_ERR;
2643238104Sdes	}
2644238104Sdes	EVP_PKEY_free(evp_key);
2645238104Sdes
2646238104Sdes	return result;
2647238104Sdes#else
2648238104Sdes	/* touch these to prevent compiler warnings */
2649238104Sdes	(void) sig;
2650238104Sdes	(void) siglen;
2651238104Sdes	(void) rrset;
2652238104Sdes	(void) key;
2653238104Sdes	(void) keylen;
2654238104Sdes	return LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
2655238104Sdes#endif
2656238104Sdes}
2657238104Sdes
2658238104Sdes
2659238104Sdesldns_status
2660238104Sdesldns_verify_rrsig_rsamd5_raw(unsigned char* sig,
2661238104Sdes					    size_t siglen,
2662238104Sdes					    ldns_buffer* rrset,
2663238104Sdes					    unsigned char* key,
2664238104Sdes					    size_t keylen)
2665238104Sdes{
2666238104Sdes	EVP_PKEY *evp_key;
2667238104Sdes	ldns_status result;
2668238104Sdes
2669238104Sdes	evp_key = EVP_PKEY_new();
2670238104Sdes	if (EVP_PKEY_assign_RSA(evp_key, ldns_key_buf2rsa_raw(key, keylen))) {
2671238104Sdes		result = ldns_verify_rrsig_evp_raw(sig,
2672238104Sdes								siglen,
2673238104Sdes								rrset,
2674238104Sdes								evp_key,
2675238104Sdes								EVP_md5());
2676238104Sdes	} else {
2677238104Sdes		result = LDNS_STATUS_SSL_ERR;
2678238104Sdes	}
2679238104Sdes	EVP_PKEY_free(evp_key);
2680238104Sdes
2681238104Sdes	return result;
2682238104Sdes}
2683238104Sdes
2684238104Sdes#endif
2685