/*
 * securechasetrace.c
 * Where all the hard work concerning secure tracing is done
 *
 * (c) 2005, 2006 NLnet Labs
 *
 * See the file LICENSE for the license
 *
 */

#include "drill.h"
#include <ldns/ldns.h>

#define SELF "[S]"  /* self sig ok */
#define TRUST "[T]" /* chain from parent */
#define BOGUS "[B]" /* bogus */
#define UNSIGNED "[U]" /* no relevant dnssec data found */

#if 0
/* See if there is a key/ds in trusted that matches
 * a ds in *ds. 
 */
static ldns_rr_list *
ds_key_match(ldns_rr_list *ds, ldns_rr_list *trusted)
{
	size_t i, j;
	bool match;
	ldns_rr *rr_i, *rr_j;
	ldns_rr_list *keys;

	if (!trusted || !ds) {
		return NULL;
	}

	match = false;
	keys = ldns_rr_list_new();
	if (!keys) {
		return NULL;
	}

	if (!ds || !trusted) {
		return NULL;
	}

	for (i = 0; i < ldns_rr_list_rr_count(trusted); i++) {
		rr_i = ldns_rr_list_rr(trusted, i);
		for (j = 0; j < ldns_rr_list_rr_count(ds); j++) {

			rr_j = ldns_rr_list_rr(ds, j);
			if (ldns_rr_compare_ds(rr_i, rr_j)) {
				match = true;
				/* only allow unique RRs to match */
				ldns_rr_set_push_rr(keys, rr_i); 
			}
		}
	}
	if (match) {
		return keys;
	} else {
		return NULL;
	}
}
#endif

static ldns_pkt *
get_dnssec_pkt(ldns_resolver *r, ldns_rdf *name, ldns_rr_type t) 
{
	ldns_pkt *p = NULL;
	p = ldns_resolver_query(r, name, t, LDNS_RR_CLASS_IN, 0); 
	if (!p) {
		return NULL;
	} else {
		if (verbosity >= 5) {
			ldns_pkt_print(stdout, p);
		}
		return p;
	}
}

#ifdef HAVE_SSL
/* 
 * retrieve keys for this zone
 */
static ldns_pkt_type
get_key(ldns_pkt *p, ldns_rdf *apexname, ldns_rr_list **rrlist, ldns_rr_list **opt_sig)
{
	return get_dnssec_rr(p, apexname, LDNS_RR_TYPE_DNSKEY, rrlist, opt_sig);
}

/*
 * check to see if we can find a DS rrset here which we can then follow
 */
static ldns_pkt_type
get_ds(ldns_pkt *p, ldns_rdf *ownername, ldns_rr_list **rrlist, ldns_rr_list **opt_sig)
{
	return get_dnssec_rr(p, ownername, LDNS_RR_TYPE_DS, rrlist, opt_sig);
}
#endif /* HAVE_SSL */

static void
remove_resolver_nameservers(ldns_resolver *res)
{
	ldns_rdf *pop;
	
	/* remove the old nameserver from the resolver */
	while((pop = ldns_resolver_pop_nameserver(res))) {
		ldns_rdf_deep_free(pop);
	}

}

/*ldns_pkt **/
#ifdef HAVE_SSL
int
do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
                ldns_rr_class c, ldns_rr_list *trusted_keys, ldns_rdf *start_name
               )
{
	ldns_resolver *res;
	ldns_pkt *p, *local_p;
	ldns_rr_list *new_nss;
	ldns_rr_list *ns_addr;
	ldns_rdf *pop;
	ldns_rdf **labels = NULL;
	ldns_status status, st;
	ssize_t i;
	size_t j;
	size_t k;
	size_t l;
	uint8_t labels_count = 0;

	/* dnssec */
	ldns_rr_list *key_list;
	ldns_rr_list *key_sig_list;
	ldns_rr_list *ds_list;
	ldns_rr_list *ds_sig_list;
	ldns_rr_list *correct_key_list;
	ldns_rr_list *trusted_ds_rrs;
	bool new_keys_trusted = false;
	ldns_rr_list *current_correct_keys = NULL;
	ldns_rr_list *dataset;

	ldns_rr_list *nsec_rrs = NULL;
	ldns_rr_list *nsec_rr_sigs = NULL;

	/* empty non-terminal check */
	bool ent;
	ldns_rr  *nsecrr;      /* The nsec that proofs the non-terminal */
	ldns_rdf *hashed_name; /* The query hashed with nsec3 params */
	ldns_rdf *label0;      /* The first label of an nsec3 owner name */

	/* glue handling */
	ldns_rr_list *new_ns_addr;
	ldns_rr_list *old_ns_addr;
	ldns_rr *ns_rr;

	int result = 0;

	/* printing niceness */
	const ldns_rr_descriptor *descriptor;

	descriptor = ldns_rr_descript(t);

	new_nss = NULL;
	ns_addr = NULL;
	key_list = NULL;
	ds_list = NULL;

	p = NULL;
	local_p = NULL;
	res = ldns_resolver_new();
	key_sig_list = NULL;
	ds_sig_list = NULL;

	if (!res) {
		error("Memory allocation failed");
		result = -1;
		return result;
	}

	correct_key_list = ldns_rr_list_new();
	if (!correct_key_list) {
		error("Memory allocation failed");
		result = -1;
		return result;
	}

	trusted_ds_rrs = ldns_rr_list_new();
	if (!trusted_ds_rrs) {
		error("Memory allocation failed");
		result = -1;
		return result;
	}
        /* Add all preset trusted DS signatures to the list of trusted DS RRs. */
        for (j = 0; j < ldns_rr_list_rr_count(trusted_keys); j++) {
            ldns_rr* one_rr = ldns_rr_list_rr(trusted_keys, j);
            if (ldns_rr_get_type(one_rr)  == LDNS_RR_TYPE_DS) {
                ldns_rr_list_push_rr(trusted_ds_rrs, ldns_rr_clone(one_rr));
            }
        }

	/* transfer some properties of local_res to res */
	ldns_resolver_set_ip6(res,
			ldns_resolver_ip6(local_res));
	ldns_resolver_set_port(res,
			ldns_resolver_port(local_res));
	ldns_resolver_set_debug(res,
			ldns_resolver_debug(local_res));
	ldns_resolver_set_fail(res,
			ldns_resolver_fail(local_res));
	ldns_resolver_set_usevc(res,
			ldns_resolver_usevc(local_res));
	ldns_resolver_set_random(res,
			ldns_resolver_random(local_res));
	ldns_resolver_set_source(res,
			ldns_resolver_source(local_res));
	ldns_resolver_set_recursive(local_res, true);

	ldns_resolver_set_recursive(res, false);
	ldns_resolver_set_dnssec_cd(res, false);
	ldns_resolver_set_dnssec(res, true);

	/* setup the root nameserver in the new resolver */
	status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
	if (status != LDNS_STATUS_OK) {
		printf("ERRRRR: %s\n", ldns_get_errorstr_by_id(status));
		ldns_rr_list_print(stdout, global_dns_root);
		result = status;
		goto done;
	}
	labels_count = ldns_dname_label_count(name);
	if (start_name) {
		if (ldns_dname_is_subdomain(name, start_name)) {
			labels_count -= ldns_dname_label_count(start_name);
		} else {
			fprintf(stderr, "Error; ");
			ldns_rdf_print(stderr, name);
			fprintf(stderr, " is not a subdomain of ");
			ldns_rdf_print(stderr, start_name);
			fprintf(stderr, "\n");
			goto done;
		}
	}
	labels = LDNS_CALLOC(ldns_rdf*, labels_count + 2);
	if (!labels) {
		goto done;
	}
	labels[0] = ldns_dname_new_frm_str(LDNS_ROOT_LABEL_STR);
	labels[1] = ldns_rdf_clone(name);
	for(i = 2 ; i < (ssize_t)labels_count + 2; i++) {
		labels[i] = ldns_dname_left_chop(labels[i - 1]);
	}

	/* get the nameserver for the label
	 * ask: dnskey and ds for the label
	 */
	for(i = (ssize_t)labels_count + 1; i > 0; i--) {
		status = ldns_resolver_send(&local_p, res, labels[i], LDNS_RR_TYPE_NS, c, 0);
		if (status != LDNS_STATUS_OK) {
			fprintf(stderr, "Error sending query: %s\n", ldns_get_errorstr_by_id(status));
			result = status;
			goto done;
		}

		/* TODO: handle status */

		if (verbosity >= 5) {
			ldns_pkt_print(stdout, local_p);
		}

		new_nss = ldns_pkt_rr_list_by_type(local_p,
					LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
 		if (!new_nss) {
			/* if it's a delegation, servers put them in the auth section */
			new_nss = ldns_pkt_rr_list_by_type(local_p,
					LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
		}

		/* if this is the final step there might not be nameserver records
		   of course if the data is in the apex, there are, so cover both
		   cases */
		if (new_nss || i > 1) {
			for(j = 0; j < ldns_rr_list_rr_count(new_nss); j++) {
				ns_rr = ldns_rr_list_rr(new_nss, j);
				pop = ldns_rr_rdf(ns_rr, 0);
				if (!pop) {
					printf("nopo\n");
					break;
				}
				/* retrieve it's addresses */
				/* trust glue? */
				new_ns_addr = NULL;
				if (ldns_dname_is_subdomain(pop, labels[i])) {
					if (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6) {
						new_ns_addr = ldns_pkt_rr_list_by_name_and_type(local_p, pop, LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
					} else {
						/* If IPv4 is specified, or no IP version is specified, default to A record and use IPv4 */
						new_ns_addr = ldns_pkt_rr_list_by_name_and_type(local_p, pop, LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
					}
				}
				if (!new_ns_addr || ldns_rr_list_rr_count(new_ns_addr) == 0) {
					new_ns_addr = ldns_get_rr_list_addr_by_name(res, pop, c, 0);
				}
				if (!new_ns_addr || ldns_rr_list_rr_count(new_ns_addr) == 0) {
					new_ns_addr = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0);
				}

				if (new_ns_addr) {
					old_ns_addr = ns_addr;
					ns_addr = ldns_rr_list_cat_clone(ns_addr, new_ns_addr);
					ldns_rr_list_deep_free(old_ns_addr);
				}
				ldns_rr_list_deep_free(new_ns_addr);
			}
			ldns_rr_list_deep_free(new_nss);

			if (ns_addr) {
				remove_resolver_nameservers(res);

				if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
						LDNS_STATUS_OK) {
					error("Error adding new nameservers");
					ldns_pkt_free(local_p);
					goto done;
				}
				ldns_rr_list_deep_free(ns_addr);
			} else {
				status = ldns_verify_denial(local_p, labels[i], LDNS_RR_TYPE_NS, &nsec_rrs, &nsec_rr_sigs);

				/* verify the nsec3 themselves*/
				if (verbosity >= 4) {
					printf("NSEC(3) Records to verify:\n");
					ldns_rr_list_print(stdout, nsec_rrs);
					printf("With signatures:\n");
					ldns_rr_list_print(stdout, nsec_rr_sigs);
					printf("correct keys:\n");
					ldns_rr_list_print(stdout, correct_key_list);
				}

				if (status == LDNS_STATUS_OK) {
					if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", TRUST);
						fprintf(stdout, "Existence denied: ");
						ldns_rdf_print(stdout, labels[i]);
	/*
						if (descriptor && descriptor->_name) {
							printf(" %s", descriptor->_name);
						} else {
							printf(" TYPE%u", t);
						}
	*/					fprintf(stdout, " NS\n");
					} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", SELF);
						fprintf(stdout, "Existence denied: ");
						ldns_rdf_print(stdout, labels[i]);
	/*
						if (descriptor && descriptor->_name) {
							printf(" %s", descriptor->_name);
						} else {
							printf(" TYPE%u", t);
						}
	*/
						fprintf(stdout, " NS\n");
					} else {
						fprintf(stdout, "%s ", BOGUS);
						result = 1;
						printf(";; Error verifying denial of existence for name ");
						ldns_rdf_print(stdout, labels[i]);
	/*
						printf(" type ");
						if (descriptor && descriptor->_name) {
							printf("%s", descriptor->_name);
						} else {
							printf("TYPE%u", t);
						}
	*/					printf("NS: %s\n", ldns_get_errorstr_by_id(st));
					}
				} else {
					fprintf(stdout, "%s ", BOGUS);
					result = 1;
					printf(";; Error verifying denial of existence for name ");
					ldns_rdf_print(stdout, labels[i]);
					printf("NS: %s\n", ldns_get_errorstr_by_id(status));
				}

				/* there might be an empty non-terminal, in which case we need to continue */
				ent = false;
				for (j = 0; j < ldns_rr_list_rr_count(nsec_rrs); j++) {
					nsecrr = ldns_rr_list_rr(nsec_rrs, j);
					/* For NSEC when the next name is a subdomain of the question */
					if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC &&
							ldns_dname_is_subdomain(ldns_rr_rdf(nsecrr, 0), labels[i])) {
						ent = true;

					/* For NSEC3, the hash matches the name and the type bitmap is empty*/
					} else if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC3) {
						hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsecrr, labels[i]);
						label0 = ldns_dname_label(ldns_rr_owner(nsecrr), 0);
						if (hashed_name && label0 &&
								ldns_dname_compare(hashed_name, label0) == 0 &&
								ldns_nsec3_bitmap(nsecrr) == NULL) {
							ent = true;
						}
						if (label0) {
							LDNS_FREE(label0);
						}
						if (hashed_name) {
							LDNS_FREE(hashed_name);
						}
					}
				}
				if (!ent) {
					ldns_rr_list_deep_free(nsec_rrs);
					ldns_rr_list_deep_free(nsec_rr_sigs);
					ldns_pkt_free(local_p);
					goto done;
				} else {
					printf(";; There is an empty non-terminal here, continue\n");
					continue;
				}
			}

			if (ldns_resolver_nameserver_count(res) == 0) {
				error("No nameservers found for this node");
				goto done;
			}
		}
		ldns_pkt_free(local_p);

		fprintf(stdout, ";; Domain: ");
		ldns_rdf_print(stdout, labels[i]);
		fprintf(stdout, "\n");

		/* retrieve keys for current domain, and verify them
		   if they match an already trusted DS, or if one of the
		   keys used to sign these is trusted, add the keys to
		   the trusted list */
		p = get_dnssec_pkt(res, labels[i], LDNS_RR_TYPE_DNSKEY);
		(void) get_key(p, labels[i], &key_list, &key_sig_list);
		if (key_sig_list) {
			if (key_list) {
				current_correct_keys = ldns_rr_list_new();
				if ((st = ldns_verify(key_list, key_sig_list, key_list, current_correct_keys)) ==
						LDNS_STATUS_OK) {
					/* add all signed keys (don't just add current_correct, you'd miss
					 * the zsk's then */
					for (j = 0; j < ldns_rr_list_rr_count(key_list); j++) {
						ldns_rr_list_push_rr(correct_key_list, ldns_rr_clone(ldns_rr_list_rr(key_list, j)));
					}

					/* check whether these keys were signed
					 * by a trusted keys. if so, these
					 * keys are also trusted */
					new_keys_trusted = false;
					for (k = 0; k < ldns_rr_list_rr_count(current_correct_keys); k++) {
						for (j = 0; j < ldns_rr_list_rr_count(trusted_ds_rrs); j++) {
							if (ldns_rr_compare_ds(ldns_rr_list_rr(current_correct_keys, k),
								    ldns_rr_list_rr(trusted_ds_rrs, j))) {
								new_keys_trusted = true;
							}
						}
					}

					/* also all keys are trusted if one of the current correct keys is trusted */
					for (k = 0; k < ldns_rr_list_rr_count(current_correct_keys); k++) {
						for (j = 0; j < ldns_rr_list_rr_count(trusted_keys); j++) {
							if (ldns_rr_compare(ldns_rr_list_rr(current_correct_keys, k),
								            ldns_rr_list_rr(trusted_keys, j)) == 0) {
								            new_keys_trusted = true;
							}
						}
					}


					if (new_keys_trusted) {
						ldns_rr_list_push_rr_list(trusted_keys, key_list);
						print_rr_list_abbr(stdout, key_list, TRUST);
						ldns_rr_list_free(key_list);
						key_list = NULL;
					} else {
						if (verbosity >= 2) {
							printf(";; Signature ok but no chain to a trusted key or ds record\n");
						}
						print_rr_list_abbr(stdout, key_list, SELF);
						ldns_rr_list_deep_free(key_list);
						key_list = NULL;
					}
				} else {
					print_rr_list_abbr(stdout, key_list, BOGUS);
					result = 2;
					ldns_rr_list_deep_free(key_list);
					key_list = NULL;
				}
				ldns_rr_list_free(current_correct_keys);
				current_correct_keys = NULL;
			} else {
				printf(";; No DNSKEY record found for ");
				ldns_rdf_print(stdout, labels[i]);
				printf("\n");
			}
		}

		ldns_pkt_free(p);
		ldns_rr_list_deep_free(key_sig_list);
		key_sig_list = NULL;

		/* check the DS records for the next child domain */
		if (i > 1) {
			p = get_dnssec_pkt(res, labels[i-1], LDNS_RR_TYPE_DS);
			(void) get_ds(p, labels[i-1], &ds_list, &ds_sig_list);
			if (!ds_list) {
				ldns_rr_list_deep_free(ds_sig_list);
				(void) get_dnssec_rr( p, labels[i-1]
				                    , LDNS_RR_TYPE_CNAME
				                    , &ds_list, &ds_sig_list);
				if (ds_list) {
					st = ldns_verify( ds_list, ds_sig_list
					                , correct_key_list
					                , current_correct_keys);

					if (st == LDNS_STATUS_OK) {
						printf(";; No DS record found "
						       "for ");
						ldns_rdf_print(stdout,
							labels[i-1]);
						printf(", but valid CNAME");
					} else {
						printf(BOGUS " Unable to verify "
						       "denial of existence for ");
						ldns_rdf_print(stdout,
							labels[i-1]);
						printf(", because of BOGUS CNAME");
					}
					printf("\n");
					ldns_rr_list_deep_free(ds_sig_list);
					ldns_pkt_free(p);
					ldns_rr_list_deep_free(ds_list);
					ds_list = NULL;
					ds_sig_list = NULL;
					p = NULL;
				} else {
					ldns_rr_list_deep_free(ds_sig_list);
					ldns_pkt_free(p);
					p = get_dnssec_pkt(res, name,
							LDNS_RR_TYPE_DNSKEY);
					(void) get_ds(p, NULL
					             , &ds_list, &ds_sig_list); 
				}
			}
			if (ds_sig_list) {
				if (ds_list) {
					if (verbosity >= 4) {
						printf("VERIFYING:\n");
						printf("DS LIST:\n");
						ldns_rr_list_print(stdout, ds_list);
						printf("SIGS:\n");
						ldns_rr_list_print(stdout, ds_sig_list);
						printf("KEYS:\n");
						ldns_rr_list_print(stdout, correct_key_list);
					}

					current_correct_keys = ldns_rr_list_new();

					if ((st = ldns_verify(ds_list, ds_sig_list, correct_key_list, current_correct_keys)) ==
							LDNS_STATUS_OK) {
						/* if the ds is signed by a trusted key and a key from correct keys
						   matches that ds, add that key to the trusted keys */
						new_keys_trusted = false;
						if (verbosity >= 2) {
							printf("Checking if signing key is trusted:\n");
						}
						for (j = 0; j < ldns_rr_list_rr_count(current_correct_keys); j++) {
							if (verbosity >= 2) {
								printf("New key: ");
								ldns_rr_print(stdout, ldns_rr_list_rr(current_correct_keys, j));
							}
							for (k = 0; k < ldns_rr_list_rr_count(trusted_keys); k++) {
								if (verbosity >= 2) {
									printf("\tTrusted key: ");
									ldns_rr_print(stdout, ldns_rr_list_rr(trusted_keys, k));
								}
								if (ldns_rr_compare(ldns_rr_list_rr(current_correct_keys, j),
								    ldns_rr_list_rr(trusted_keys, k)) == 0) {
								    	if (verbosity >= 2) {
								    		printf("Key is now trusted!\n");
									}
									for (l = 0; l < ldns_rr_list_rr_count(ds_list); l++) {
										ldns_rr_list_push_rr(trusted_ds_rrs, ldns_rr_clone(ldns_rr_list_rr(ds_list, l)));
										new_keys_trusted = true;
									}
								}
							}
						}
						if (new_keys_trusted) {
							print_rr_list_abbr(stdout, ds_list, TRUST);
						} else {
							print_rr_list_abbr(stdout, ds_list, SELF);
						}
					} else {
						result = 3;
						print_rr_list_abbr(stdout, ds_list, BOGUS);
					}

					ldns_rr_list_free(current_correct_keys);
					current_correct_keys = NULL;
				} else {
					/* wait apparently there were no keys either, go back to the ds packet */
					ldns_pkt_free(p);
					ldns_rr_list_deep_free(ds_sig_list);
					p = get_dnssec_pkt(res, labels[i-1], LDNS_RR_TYPE_DS);
					(void) get_ds(p, labels[i-1], &ds_list, &ds_sig_list);
					
					status = ldns_verify_denial(p, labels[i-1], LDNS_RR_TYPE_DS, &nsec_rrs, &nsec_rr_sigs);

					if (verbosity >= 4) {
						printf("NSEC(3) Records to verify:\n");
						ldns_rr_list_print(stdout, nsec_rrs);
						printf("With signatures:\n");
						ldns_rr_list_print(stdout, nsec_rr_sigs);
						printf("correct keys:\n");
						ldns_rr_list_print(stdout, correct_key_list);
					}

					if (status == LDNS_STATUS_OK) {
						if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
							fprintf(stdout, "%s ", TRUST);
							fprintf(stdout, "Existence denied: ");
							ldns_rdf_print(stdout, labels[i-1]);
							printf(" DS");
							fprintf(stdout, "\n");
						} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
							fprintf(stdout, "%s ", SELF);
							fprintf(stdout, "Existence denied: ");
							ldns_rdf_print(stdout, labels[i-1]);
							printf(" DS");
							fprintf(stdout, "\n");
						} else {
							result = 4;
							fprintf(stdout, "%s ", BOGUS);
							printf("Error verifying denial of existence for ");
							ldns_rdf_print(stdout, labels[i-1]);
							printf(" DS");
							printf(": %s\n", ldns_get_errorstr_by_id(st));
						}
						
					
					} else {
						if (status == LDNS_STATUS_CRYPTO_NO_RRSIG) {
							printf(";; No DS for ");
							ldns_rdf_print(stdout, labels[i - 1]);
						} else {
							printf(BOGUS " Unable to verify denial of existence for ");
							ldns_rdf_print(stdout, labels[i - 1]);
							printf(" DS: %s\n", ldns_get_errorstr_by_id(status));
						}
					}
					if (verbosity >= 2) {
						printf(";; No ds record for delegation\n");
					}
				}
			}
			ldns_rr_list_deep_free(ds_list);
			ldns_pkt_free(p);
		} else {
			/* if this is the last label, just verify the data and stop */
			p = get_dnssec_pkt(res, labels[i], t);
			(void) get_dnssec_rr(p, labels[i], t, &dataset, &key_sig_list);
			if (dataset && ldns_rr_list_rr_count(dataset) > 0) {
				if (key_sig_list && ldns_rr_list_rr_count(key_sig_list) > 0) {

					/* If this is a wildcard, you must be able to deny exact match */
					if ((st = ldns_verify(dataset, key_sig_list, trusted_keys, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", TRUST);
						ldns_rr_list_print(stdout, dataset);
					} else if ((st = ldns_verify(dataset, key_sig_list, correct_key_list, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", SELF);
						ldns_rr_list_print(stdout, dataset);
					} else {
						result = 5;
						fprintf(stdout, "%s ", BOGUS);
						ldns_rr_list_print(stdout, dataset);
						printf(";; Error: %s\n", ldns_get_errorstr_by_id(st));
					}
				} else {
					fprintf(stdout, "%s ", UNSIGNED);
					ldns_rr_list_print(stdout, dataset);
				}
				ldns_rr_list_deep_free(dataset);
			} else {
				status = ldns_verify_denial(p, name, t, &nsec_rrs, &nsec_rr_sigs);
				if (status == LDNS_STATUS_OK) {
					/* verify the nsec3 themselves*/
					if (verbosity >= 5) {
						printf("NSEC(3) Records to verify:\n");
						ldns_rr_list_print(stdout, nsec_rrs);
						printf("With signatures:\n");
						ldns_rr_list_print(stdout, nsec_rr_sigs);
						printf("correct keys:\n");
						ldns_rr_list_print(stdout, correct_key_list);
/*
						printf("trusted keys at %p:\n", trusted_keys);
						ldns_rr_list_print(stdout, trusted_keys);
*/					}
					
					if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", TRUST);
						fprintf(stdout, "Existence denied: ");
						ldns_rdf_print(stdout, name);
						if (descriptor && descriptor->_name) {
							printf(" %s", descriptor->_name);
						} else {
							printf(" TYPE%u", t);
						}
						fprintf(stdout, "\n");
					} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
						fprintf(stdout, "%s ", SELF);
						fprintf(stdout, "Existence denied: ");
						ldns_rdf_print(stdout, name);
						if (descriptor && descriptor->_name) {
							printf(" %s", descriptor->_name);
						} else {
							printf(" TYPE%u", t);
						}
						fprintf(stdout, "\n");
					} else {
						result = 6;
						fprintf(stdout, "%s ", BOGUS);
						printf("Error verifying denial of existence for ");
						ldns_rdf_print(stdout, name);
						printf(" type ");
						if (descriptor && descriptor->_name) {
							printf("%s", descriptor->_name);
						} else {
							printf("TYPE%u", t);
						}
						printf(": %s\n", ldns_get_errorstr_by_id(st));
					}
					
					ldns_rr_list_deep_free(nsec_rrs);
					ldns_rr_list_deep_free(nsec_rr_sigs);
				} else {
/*
*/
					if (status == LDNS_STATUS_CRYPTO_NO_RRSIG) {
						printf("%s ", UNSIGNED);
						printf("No data found for: ");
						ldns_rdf_print(stdout, name);
						printf(" type ");
						if (descriptor && descriptor->_name) {
							printf("%s", descriptor->_name);
						} else {
							printf("TYPE%u", t);
						}
						printf("\n");
					} else {
						printf(BOGUS " Unable to verify denial of existence for ");
						ldns_rdf_print(stdout, name);
						printf(" type ");
						if (descriptor && descriptor->_name) {
							printf("%s", descriptor->_name);
						} else {
							printf("TYPE%u", t);
						}
						printf("\n");
					}
				
				}
			}
			ldns_pkt_free(p);
		}

		new_nss = NULL;
		ns_addr = NULL;
		ldns_rr_list_deep_free(key_list);
		key_list = NULL;
		ldns_rr_list_deep_free(key_sig_list);
		key_sig_list = NULL;
		ds_list = NULL;
		ldns_rr_list_deep_free(ds_sig_list);
		ds_sig_list = NULL;
	}
	printf(";;" SELF " self sig OK; " BOGUS " bogus; " TRUST " trusted; " UNSIGNED " unsigned\n");
	/* verbose mode?
	printf("Trusted keys:\n");
	ldns_rr_list_print(stdout, trusted_keys);
	printf("trusted dss:\n");
	ldns_rr_list_print(stdout, trusted_ds_rrs);
	*/

	done:
	ldns_rr_list_deep_free(trusted_ds_rrs);
	ldns_rr_list_deep_free(correct_key_list);
	ldns_resolver_deep_free(res);
	if (labels) {
		for(i = 0 ; i < (ssize_t)labels_count + 2; i++) {
			ldns_rdf_deep_free(labels[i]);
		}
		LDNS_FREE(labels);
	}
	return result;
}
#endif /* HAVE_SSL */
