コード例 #1
0
ファイル: cachedump.c プロジェクト: ChaosJohn/freebsd
/** convert to ldns rr */
static ldns_rr*
to_rr(struct ub_packed_rrset_key* k, struct packed_rrset_data* d, 
	uint32_t now, size_t i, uint16_t type)
{
	ldns_rr* rr = ldns_rr_new();
	ldns_rdf* rdf;
	ldns_status status;
	size_t pos;
	log_assert(i < d->count + d->rrsig_count);
	if(!rr) {
		return NULL;
	}
	ldns_rr_set_type(rr, type);
	ldns_rr_set_class(rr, ntohs(k->rk.rrset_class));
	if(d->rr_ttl[i] < now)
		ldns_rr_set_ttl(rr, 0);
	else	ldns_rr_set_ttl(rr, d->rr_ttl[i] - now);
	pos = 0;
	status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos);
	if(status != LDNS_STATUS_OK) {
		/* we drop detailed error in status */
		ldns_rr_free(rr);
		return NULL;
	}
	ldns_rr_set_owner(rr, rdf);
	pos = 0;
	status = ldns_wire2rdf(rr, d->rr_data[i], d->rr_len[i], &pos);
	if(status != LDNS_STATUS_OK) {
		/* we drop detailed error in status */
		ldns_rr_free(rr);
		return NULL;
	}
	return rr;
}
コード例 #2
0
/**
 * Publish the NSEC3 parameters as indicated by the signer configuration.
 *
 */
ods_status
zone_publish_nsec3param(zone_type* zone)
{
    rrset_type* rrset = NULL;
    rr_type* n3prr = NULL;
    ldns_rr* rr = NULL;
    ods_status status = ODS_STATUS_OK;

    if (!zone || !zone->name || !zone->db || !zone->signconf) {
        return ODS_STATUS_ASSERT_ERR;
    }
    if (!zone->signconf->nsec3params) {
        /* NSEC */
        ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
        return ODS_STATUS_OK;
    }

    if (!zone->signconf->nsec3params->rr) {
        rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
        if (!rr) {
            ods_log_error("[%s] unable to publish nsec3params for zone %s: "
                "error creating rr (%s)", zone_str, zone->name,
                ods_status2str(status));
            return ODS_STATUS_MALLOC_ERR;
        }
        ldns_rr_set_class(rr, zone->klass);
        ldns_rr_set_ttl(rr, 0);
        ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
        ldns_nsec3_add_param_rdfs(rr,
            zone->signconf->nsec3params->algorithm, 0,
            zone->signconf->nsec3params->iterations,
            zone->signconf->nsec3params->salt_len,
            zone->signconf->nsec3params->salt_data);
        /**
         * Always set bit 7 of the flags to zero,
         * according to rfc5155 section 11
         */
        ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
        zone->signconf->nsec3params->rr = rr;
    }
    ods_log_assert(zone->signconf->nsec3params->rr);
    status = zone_add_rr(zone, zone->signconf->nsec3params->rr, 0);
    if (status == ODS_STATUS_UNCHANGED) {
        /* rr already exists, adjust pointer */
        rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
        ods_log_assert(rrset);
        n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
        ods_log_assert(n3prr);
        if (n3prr->rr != zone->signconf->nsec3params->rr) {
            ldns_rr_free(zone->signconf->nsec3params->rr);
        }
        zone->signconf->nsec3params->rr = n3prr->rr;
        status = ODS_STATUS_OK;
    } else if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to publish nsec3params for zone %s: "
            "error adding nsec3params (%s)", zone_str,
            zone->name, ods_status2str(status));
    }
    return status;
}
コード例 #3
0
ファイル: adapi.c プロジェクト: opendnssec/opendnssec
/**
 * Process DNSKEY.
 *
 */
static void
adapi_process_dnskey(zone_type* zone, ldns_rr* rr)
{
    uint32_t tmp = 0;
    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);
    tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
    ods_log_verbose("[%s] zone %s set dnskey ttl to %u",
        adapi_str, zone->name, tmp);
    ldns_rr_set_ttl(rr, tmp);
}
コード例 #4
0
ファイル: dnssec_sign.c プロジェクト: kaloyan13/passivedns
ldns_status
ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
                              ldns_rr_list *new_rrs)
{

	ldns_rbnode_t *first_node, *cur_node, *next_node;
	ldns_dnssec_name *cur_name, *next_name;
	ldns_rr *nsec_rr;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	
	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
	
	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(
		                                     soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}
	
	first_node = ldns_dnssec_name_node_next_nonglue(
			       ldns_rbtree_first(zone->names));
	cur_node = first_node;
	if (cur_node) {
		next_node = ldns_dnssec_name_node_next_nonglue(
			           ldns_rbtree_next(cur_node));
	} else {
		next_node = NULL;
	}

	while (cur_node && next_node) {
		cur_name = (ldns_dnssec_name *)cur_node->data;
		next_name = (ldns_dnssec_name *)next_node->data;
		nsec_rr = ldns_dnssec_create_nsec(cur_name,
		                                  next_name,
		                                  LDNS_RR_TYPE_NSEC);
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(cur_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		cur_node = next_node;
		if (cur_node) {
			next_node = ldns_dnssec_name_node_next_nonglue(
                               ldns_rbtree_next(cur_node));
		}
	}

	if (cur_node && !next_node) {
		cur_name = (ldns_dnssec_name *)cur_node->data;
		next_name = (ldns_dnssec_name *)first_node->data;
		nsec_rr = ldns_dnssec_create_nsec(cur_name,
		                                  next_name,
		                                  LDNS_RR_TYPE_NSEC);
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(cur_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
	} else {
		printf("error\n");
	}

	return LDNS_STATUS_OK;
}
コード例 #5
0
ファイル: dnssec_sign.c プロジェクト: kaloyan13/passivedns
ldns_rr *
ldns_create_empty_rrsig(ldns_rr_list *rrset,
                        ldns_key *current_key)
{
	uint32_t orig_ttl;
	time_t now;
	ldns_rr *current_sig;
	uint8_t label_count;

	label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset,
	                                                   0)));
	
	current_sig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
	
	/* set the type on the new signature */
	orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));

	ldns_rr_set_ttl(current_sig, orig_ttl);
	ldns_rr_set_owner(current_sig, 
			  ldns_rdf_clone(
			       ldns_rr_owner(
				    ldns_rr_list_rr(rrset,
						    0))));

	/* fill in what we know of the signature */
	
	/* set the orig_ttl */
	(void)ldns_rr_rrsig_set_origttl(
		   current_sig, 
		   ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
					 orig_ttl));
	/* the signers name */
	(void)ldns_rr_rrsig_set_signame(
			current_sig, 
			ldns_rdf_clone(ldns_key_pubkey_owner(current_key)));
	/* label count - get it from the first rr in the rr_list */
	(void)ldns_rr_rrsig_set_labels(
			current_sig, 
			ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
			                     label_count));
	/* inception, expiration */
	now = time(NULL);
	if (ldns_key_inception(current_key) != 0) {
		(void)ldns_rr_rrsig_set_inception(
				current_sig,
				ldns_native2rdf_int32(
				    LDNS_RDF_TYPE_TIME, 
				    ldns_key_inception(current_key)));
	} else {
		(void)ldns_rr_rrsig_set_inception(
				current_sig,
				ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
	}
	if (ldns_key_expiration(current_key) != 0) {
		(void)ldns_rr_rrsig_set_expiration(
				current_sig,
				ldns_native2rdf_int32(
				    LDNS_RDF_TYPE_TIME, 
				    ldns_key_expiration(current_key)));
	} else {
		(void)ldns_rr_rrsig_set_expiration(
			     current_sig,
				ldns_native2rdf_int32(
				    LDNS_RDF_TYPE_TIME, 
				    now + LDNS_DEFAULT_EXP_TIME));
	}

	(void)ldns_rr_rrsig_set_keytag(
		   current_sig,
		   ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 
		                         ldns_key_keytag(current_key)));

	(void)ldns_rr_rrsig_set_algorithm(
			current_sig,
			ldns_native2rdf_int8(
			    LDNS_RDF_TYPE_ALG, 
			    ldns_key_algorithm(current_key)));

	(void)ldns_rr_rrsig_set_typecovered(
			current_sig,
			ldns_native2rdf_int16(
			    LDNS_RDF_TYPE_TYPE,
			    ldns_rr_get_type(ldns_rr_list_rr(rrset,
			                                     0))));
	return current_sig;
}
コード例 #6
0
static uint16_t 
dnskey_from_id(std::string &dnskey,
               const char *id,
               ::ods::keystate::keyrole role,
               const char *zone,
               int algorithm,
               int bDS,
               uint32_t ttl)
{
    hsm_key_t *key;
    hsm_sign_params_t *sign_params;
    ldns_rr *dnskey_rr;
    ldns_algorithm algo = (ldns_algorithm)algorithm;
    
    /* Code to output the DNSKEY record  (stolen from hsmutil) */
    hsm_ctx_t *hsm_ctx = hsm_create_context();
    if (!hsm_ctx) {
        ods_log_error("[%s] Could not connect to HSM", module_str);
        return false;
    }
    key = hsm_find_key_by_id(hsm_ctx, id);
    
    if (!key) {
        // printf("Key %s in DB but not repository\n", id);
        hsm_destroy_context(hsm_ctx);
        return 0;
    }
    
    /*
     * Sign params only need to be kept around 
     * for the hsm_get_dnskey() call.
     */
    sign_params = hsm_sign_params_new();
    sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone);
    sign_params->algorithm = algo;
    sign_params->flags = LDNS_KEY_ZONE_KEY;
    if (role == ::ods::keystate::KSK)
        sign_params->flags += LDNS_KEY_SEP_KEY; /*KSK=>SEP*/
    /* Get the DNSKEY record */
    dnskey_rr = hsm_get_dnskey(hsm_ctx, key, sign_params);
    hsm_sign_params_free(sign_params);
    /* Calculate the keytag for this key, we return it. */
    uint16_t keytag = ldns_calc_keytag(dnskey_rr);
    /* Override the TTL in the dnskey rr */
    if (ttl)
        ldns_rr_set_ttl(dnskey_rr, ttl);
    
    char *rrstr;
    if (!bDS) {
#if 0
        ldns_rr_print(stdout, dnskey_rr);
#endif
        rrstr = ldns_rr2str(dnskey_rr);
        dnskey = rrstr;
        LDNS_FREE(rrstr);
    } else {
    
        switch (algo) {
            case LDNS_RSASHA1: // 5
            {
                /* DS record (SHA1) */
                ldns_rr *ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
#if 0
                ldns_rr_print(stdout, ds_sha1_rr);
#endif
                rrstr = ldns_rr2str(ds_sha1_rr);
                dnskey = rrstr;
                LDNS_FREE(rrstr);

                ldns_rr_free(ds_sha1_rr);
                break;
            }
            case LDNS_RSASHA256: // 8 - RFC 5702
            {
        
                /* DS record (SHA256) */
                ldns_rr *ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
#if 0
                ldns_rr_print(stdout, ds_sha256_rr);
#endif
                rrstr = ldns_rr2str(ds_sha256_rr);
                dnskey = rrstr;
                LDNS_FREE(rrstr);

                ldns_rr_free(ds_sha256_rr);
                break;
            }
            default:
                keytag = 0;
        }
    }
    ldns_rr_free(dnskey_rr);
    hsm_key_free(key);
    hsm_destroy_context(hsm_ctx);
    
    return keytag;
}
コード例 #7
0
ファイル: host2wire.c プロジェクト: LANJr4D/iEnum
ldns_status
ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
{
	ldns_rr_list *rr_list;
	uint16_t i;
	
	/* edns tmp vars */
	ldns_rr *edns_rr;
	uint8_t edata[4];
	
	(void) ldns_hdr2buffer_wire(buffer, packet);

	rr_list = ldns_pkt_question(packet);
	if (rr_list) {
		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
			(void) ldns_rr2buffer_wire(buffer, 
			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
		}
	}
	rr_list = ldns_pkt_answer(packet);
	if (rr_list) {
		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
			(void) ldns_rr2buffer_wire(buffer, 
			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
		}
	}
	rr_list = ldns_pkt_authority(packet);
	if (rr_list) {
		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
			(void) ldns_rr2buffer_wire(buffer, 
			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
		}
	}
	rr_list = ldns_pkt_additional(packet);
	if (rr_list) {
		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
			(void) ldns_rr2buffer_wire(buffer, 
			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
		}
	}
	
	/* add EDNS to additional if it is needed */
	if (ldns_pkt_edns(packet)) {
		edns_rr = ldns_rr_new();
		ldns_rr_set_owner(edns_rr,
				ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
		ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
		ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
		edata[0] = ldns_pkt_edns_extended_rcode(packet);
		edata[1] = ldns_pkt_edns_version(packet);
		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
		(void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
		ldns_rr_free(edns_rr);
	}
	
	/* add TSIG to additional if it is there */
	if (ldns_pkt_tsig(packet)) {
		(void) ldns_rr2buffer_wire(buffer,
		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
	}
	
	return LDNS_STATUS_OK;
}
コード例 #8
0
ファイル: adapi.c プロジェクト: opendnssec/opendnssec
/**
 * Process RR.
 *
 */
static ods_status
adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup)
{
    ods_status status = ODS_STATUS_OK;
    uint32_t tmp = 0;
    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->db);
    ods_log_assert(zone->signconf);
    /* We only support IN class */
    if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) {
        ods_log_warning("[%s] only class in is supported, changing class "
            "to in", adapi_str);
        ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
    }
    /* RR processing */
    if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
        if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) {
            ods_log_error("[%s] unable to %s rr to zone: soa record has "
                "invalid owner name", adapi_str, add?"add":"delete");
            return ODS_STATUS_ERR;
        }
        status = adapi_process_soa(zone, rr, add, backup);
        if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to %s rr: failed to process soa "
                "record", adapi_str, add?"add":"delete");
            return status;
        }
    } else {
        if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) &&
            !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) {
            ods_log_warning("[%s] zone %s contains out-of-zone data, "
                "skipping", adapi_str, zone->name);
            return ODS_STATUS_UNCHANGED;
        } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) {
            adapi_process_dnskey(zone, rr);
        } else if (util_is_dnssec_rr(rr) && !backup) {
            ods_log_warning("[%s] zone %s contains dnssec data (type=%u), "
                "skipping", adapi_str, zone->name,
                (unsigned) ldns_rr_get_type(rr));
            return ODS_STATUS_UNCHANGED;
        } else if (zone->signconf->max_zone_ttl) {
            /* Convert MaxZoneTTL */
            tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl);
        }
    }
    /* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */
    if (tmp && tmp < ldns_rr_ttl(rr)) {
        char* str = ldns_rdf2str(ldns_rr_owner(rr));
        if (str) {
            size_t i = 0;
            str[(strlen(str))-1] = '\0';
            /* replace tabs with white space */
            for (i=0; i < strlen(str); i++) {
                if (str[i] == '\t') {
                    str[i] = ' ';
                }
            }
            ods_log_debug("[%s] capping ttl %u to MaxZoneTTL %u for rrset "
                "<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str,
                rrset_type2str(ldns_rr_get_type(rr)));
        }
        ldns_rr_set_ttl(rr, tmp);
    }

    /* TODO: DNAME and CNAME checks */
    /* TODO: NS and DS checks */

    if (add) {
        return zone_add_rr(zone, rr, 1);
    } else {
        return zone_del_rr(zone, rr, 1);
    }
    /* not reached */
    return ODS_STATUS_ERR;
}
コード例 #9
0
ファイル: dnssec_sign.c プロジェクト: mbuij/ldns-cga-tsig
/**
 * use this function to sign with a public/private key alg
 * return the created signatures
 */
ldns_rr_list *
ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys)
{
	ldns_rr_list *signatures;
	ldns_rr_list *rrset_clone;
	ldns_rr *current_sig;
	ldns_rdf *b64rdf;
	ldns_key *current_key;
	size_t key_count;
	uint16_t i;
	ldns_buffer *sign_buf;
	ldns_rdf *new_owner;

	if (!rrset || ldns_rr_list_rr_count(rrset) < 1 || !keys) {
		return NULL;
	}

	new_owner = NULL;

	signatures = ldns_rr_list_new();

	/* prepare a signature and add all the know data
	 * prepare the rrset. Sign this together.  */
	rrset_clone = ldns_rr_list_clone(rrset);
	if (!rrset_clone) {
		return NULL;
	}

	/* make it canonical */
	for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
		ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i), 
			ldns_rr_ttl(ldns_rr_list_rr(rrset, 0)));
		ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i));
	}
	/* sort */
	ldns_rr_list_sort(rrset_clone);

	for (key_count = 0;
		key_count < ldns_key_list_key_count(keys);
		key_count++) {
		if (!ldns_key_use(ldns_key_list_key(keys, key_count))) {
			continue;
		}
		sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
		if (!sign_buf) {
			ldns_rr_list_free(rrset_clone);
			ldns_rr_list_free(signatures);
			ldns_rdf_free(new_owner);
			return NULL;
		}
		b64rdf = NULL;

		current_key = ldns_key_list_key(keys, key_count);
		/* sign all RRs with keys that have ZSKbit, !SEPbit.
		   sign DNSKEY RRs with keys that have ZSKbit&SEPbit */
		if (ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY) {
			current_sig = ldns_create_empty_rrsig(rrset_clone,
			                                      current_key);

			/* right now, we have: a key, a semi-sig and an rrset. For
			 * which we can create the sig and base64 encode that and
			 * add that to the signature */

			if (ldns_rrsig2buffer_wire(sign_buf, current_sig)
			    != LDNS_STATUS_OK) {
				ldns_buffer_free(sign_buf);
				/* ERROR */
				ldns_rr_list_deep_free(rrset_clone);
				ldns_rr_free(current_sig);
				ldns_rr_list_deep_free(signatures);
				return NULL;
			}

			/* add the rrset in sign_buf */
			if (ldns_rr_list2buffer_wire(sign_buf, rrset_clone)
			    != LDNS_STATUS_OK) {
				ldns_buffer_free(sign_buf);
				ldns_rr_list_deep_free(rrset_clone);
				ldns_rr_free(current_sig);
				ldns_rr_list_deep_free(signatures);
				return NULL;
			}

			b64rdf = ldns_sign_public_buffer(sign_buf, current_key);

			if (!b64rdf) {
				/* signing went wrong */
				ldns_rr_list_deep_free(rrset_clone);
				ldns_rr_free(current_sig);
				ldns_rr_list_deep_free(signatures);
				return NULL;
			}

			ldns_rr_rrsig_set_sig(current_sig, b64rdf);

			/* push the signature to the signatures list */
			ldns_rr_list_push_rr(signatures, current_sig);
		}
		ldns_buffer_free(sign_buf); /* restart for the next key */
	}
	ldns_rr_list_deep_free(rrset_clone);

	return signatures;
}
コード例 #10
0
ファイル: dnssec_sign.c プロジェクト: mbuij/ldns-cga-tsig
static ldns_status
ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone,
		ldns_rr_list *new_rrs,
		uint8_t algorithm,
		uint8_t flags,
		uint16_t iterations,
		uint8_t salt_length,
		uint8_t *salt,
		ldns_rbtree_t **map)
{
	ldns_rbnode_t *first_name_node;
	ldns_rbnode_t *current_name_node;
	ldns_dnssec_name *current_name;
	ldns_status result = LDNS_STATUS_OK;
	ldns_rr *nsec_rr;
	ldns_rr_list *nsec3_list;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	ldns_rbnode_t *hashmap_node;

	if (!zone || !new_rrs || !zone->names) {
		return LDNS_STATUS_ERR;
	}

	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);

	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr
			&& ldns_rr_rdf(soa->rrs->rr, 6) != NULL) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}

	if (zone->hashed_names) {
		ldns_traverse_postorder(zone->hashed_names,
				ldns_hashed_names_node_free, NULL);
		LDNS_FREE(zone->hashed_names);
	}
	zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
	if (zone->hashed_names && map) {
		*map = zone->hashed_names;
	}

	first_name_node = ldns_dnssec_name_node_next_nonglue(
					  ldns_rbtree_first(zone->names));

	current_name_node = first_name_node;

	while (current_name_node && current_name_node != LDNS_RBTREE_NULL &&
			result == LDNS_STATUS_OK) {

		current_name = (ldns_dnssec_name *) current_name_node->data;
		nsec_rr = ldns_dnssec_create_nsec3(current_name,
		                                   NULL,
		                                   zone->soa->name,
		                                   algorithm,
		                                   flags,
		                                   iterations,
		                                   salt_length,
		                                   salt);
		/* by default, our nsec based generator adds rrsigs
		 * remove the bitmap for empty nonterminals */
		if (!current_name->rrsets) {
			ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
		}
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		result = ldns_dnssec_name_add_rr(current_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		if (ldns_rr_owner(nsec_rr)) {
			hashmap_node = LDNS_MALLOC(ldns_rbnode_t);
			if (hashmap_node == NULL) {
				return LDNS_STATUS_MEM_ERR;
			}
			current_name->hashed_name = 
				ldns_dname_label(ldns_rr_owner(nsec_rr), 0);

			if (current_name->hashed_name == NULL) {
				LDNS_FREE(hashmap_node);
				return LDNS_STATUS_MEM_ERR;
			}
			hashmap_node->key  = current_name->hashed_name;
			hashmap_node->data = current_name;

			if (! ldns_rbtree_insert(zone->hashed_names
						, hashmap_node)) {
				LDNS_FREE(hashmap_node);
			}
		}
		current_name_node = ldns_dnssec_name_node_next_nonglue(
		                   ldns_rbtree_next(current_name_node));
	}
	if (result != LDNS_STATUS_OK) {
		return result;
	}

	/* Make sorted list of nsec3s (via zone->hashed_names)
	 */
	nsec3_list = ldns_rr_list_new();
	if (nsec3_list == NULL) {
		return LDNS_STATUS_MEM_ERR;
	}
	for ( hashmap_node  = ldns_rbtree_first(zone->hashed_names)
	    ; hashmap_node != LDNS_RBTREE_NULL
	    ; hashmap_node  = ldns_rbtree_next(hashmap_node)
	    ) {
		current_name = (ldns_dnssec_name *) hashmap_node->data;
		nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec;
		if (nsec_rr) {
			ldns_rr_list_push_rr(nsec3_list, nsec_rr);
		}
	}
	result = ldns_dnssec_chain_nsec3_list(nsec3_list);
	ldns_rr_list_free(nsec3_list);

	return result;
}
コード例 #11
0
ファイル: dnssec.c プロジェクト: AbrahamJewowich/FreeSWITCH
ldns_status
ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
{
	uint16_t nsec_i;

	ldns_rr_list *nsecs;
	ldns_status result;
	
	if (verbosity >= 5) {
		printf("VERIFY DENIAL FROM:\n");
		ldns_pkt_print(stdout, pkt);
	}

	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
	/* Try to see if there are NSECS in the packet */
	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
	if (nsecs) {
		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
			/* there are four options:
			 * - name equals ownername and is covered by the type bitmap
			 * - name equals ownername but is not covered by the type bitmap
			 * - name falls within nsec coverage but is not equal to the owner name
			 * - name falls outside of nsec coverage
			 */
			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
				/*
				printf("CHECKING NSEC:\n");
				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
				printf("DAWASEM\n");
				*/
				if (ldns_nsec_bitmap_covers_type(
					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
													nsec_i)),
					   type)) {
					/* Error, according to the nsec this rrset is signed */
					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
				} else {
					/* ok nsec denies existence */
					if (verbosity >= 3) {
						printf(";; Existence of data set with this type denied by NSEC\n");
					}
						/*printf(";; Verifiably insecure.\n");*/
						if (nsec_rrs && nsec_rr_sigs) {
							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
						}
						ldns_rr_list_deep_free(nsecs);
						return LDNS_STATUS_OK;
				}
			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
				if (verbosity >= 3) {
					printf(";; Existence of data set with this name denied by NSEC\n");
				}
				if (nsec_rrs && nsec_rr_sigs) {
					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
				}
				ldns_rr_list_deep_free(nsecs);
				return LDNS_STATUS_OK;
			} else {
				/* nsec has nothing to do with this data */
			}
		}
		ldns_rr_list_deep_free(nsecs);
	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
                ldns_rr* q = ldns_rr_new();
                if(!sigs) return LDNS_STATUS_MEM_ERR;
                if(!q) return LDNS_STATUS_MEM_ERR;
                ldns_rr_set_question(q, 1);
                ldns_rr_set_ttl(q, 0);
                ldns_rr_set_owner(q, ldns_rdf_clone(name));
                if(!ldns_rr_owner(q)) return LDNS_STATUS_MEM_ERR;
                ldns_rr_set_type(q, type);
                
                result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0);
                ldns_rr_free(q);
		ldns_rr_list_deep_free(nsecs);
		ldns_rr_list_deep_free(sigs);
        }
	return result;
}
コード例 #12
0
ファイル: ldns_utils.c プロジェクト: pencil/monitoringplug
ldns_rr_list* loadAnchorfile(const char *filename) {

    int     col = 0;
    int     line = 0;
    int     grouped = 0;
    int     tk_section = 0;
    FILE    *key_file;
    char    c;
    char    linebuffer[LDNS_MAX_PACKETLEN];

    ldns_rdf        *rd;
    ldns_rr         *rr;
    ldns_rr_list    *trusted_keys;

    // Try open trusted key file
    key_file = fopen(filename, "r");
    if (!key_file) {
        if (mp_verbose >= 1)
            fprintf(stderr,"Error opening trusted-key file %s: %s\n", filename,
                                                           strerror(errno));
        return NULL;
    }

    // Create empty list
    trusted_keys = ldns_rr_list_new();

    // Read File
    do {
        c = getc(key_file);

        if ((c == '\n' && grouped == 0) || c == EOF) {
            linebuffer[col] = '\0';
            line++;

            if(strstr(linebuffer, "trusted-keys")) {
                col = 0;
                tk_section = 1;
                continue;
            }

            // Strip leading spaces.
            char *cur = linebuffer;
            cur += strspn(linebuffer," \t\n");

            if (cur[0] == ';' || strncmp(cur,"//",2) == 0 || col == 0
                || tk_section == 0) {
                col = 0;
                continue;
            }
            col = 0;

            rr = ldns_rr_new();
            ldns_rr_set_class(rr, LDNS_RR_CLASS_IN);
            ldns_rr_set_type(rr, LDNS_RR_TYPE_DNSKEY);
            ldns_rr_set_ttl(rr, 3600);

            char *t = strsep(&cur, " \t");

            ldns_str2rdf_dname(&rd, t);
            ldns_rr_set_owner(rr, rd);

            t = strsep(&cur, " \t");

            ldns_str2rdf_int16(&rd, t);
            ldns_rr_push_rdf(rr, rd);

            t = strsep(&cur, " \t");

            ldns_str2rdf_int8(&rd, t);
            ldns_rr_push_rdf(rr, rd);

            t = strsep(&cur, " \t");

            ldns_str2rdf_alg(&rd, t);
            ldns_rr_push_rdf(rr, rd);

            if (cur[strlen(cur)-1] == ';')
                cur[strlen(cur)-1] = '\0';

            ldns_str2rdf_b64(&rd, cur);
            ldns_rr_push_rdf(rr, rd);

            ldns_rr_list_push_rr(trusted_keys,rr);

        } else {
            if (c == '}') {
                tk_section = 0;
            } else if (c == '"') {
                grouped = (grouped+1)%2;
            } else {
                linebuffer[col++] = c;
            }
        }

    } while (c != EOF);

    fclose(key_file);

    return trusted_keys;
}
コード例 #13
0
/**
 * Add RR.
 *
 */
ods_status
zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
{
    domain_type* domain = NULL;
    rrset_type* rrset = NULL;
    rr_type* record = NULL;
    ods_status status = ODS_STATUS_OK;

    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->db);
    ods_log_assert(zone->signconf);
    /* If we already have this RR, return ODS_STATUS_UNCHANGED */
    domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
    if (!domain) {
        domain = namedb_add_domain(zone->db, ldns_rr_owner(rr));
        if (!domain) {
            ods_log_error("[%s] unable to add RR to zone %s: "
                "failed to add domain", zone_str, zone->name);
            return ODS_STATUS_ERR;
        }
        if (ldns_dname_compare(domain->dname, zone->apex) == 0) {
            domain->is_apex = 1;
        } else {
            status = namedb_domain_entize(zone->db, domain, zone->apex);
            if (status != ODS_STATUS_OK) {
                ods_log_error("[%s] unable to add RR to zone %s: "
                    "failed to entize domain", zone_str, zone->name);
                return ODS_STATUS_ERR;
            }
        }
    }
    rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
    if (!rrset) {
        rrset = rrset_create(domain->zone, ldns_rr_get_type(rr));
        if (!rrset) {
            ods_log_error("[%s] unable to add RR to zone %s: "
                "failed to add RRset", zone_str, zone->name);
            return ODS_STATUS_ERR;
        }
        domain_add_rrset(domain, rrset);
    }
    record = rrset_lookup_rr(rrset, rr);
    if (record) {
        record->is_added = 1; /* already exists, just mark added */
        record->is_removed = 0; /* unset is_removed */
        if (ldns_rr_ttl(rr) != ldns_rr_ttl(record->rr)) {
            ldns_rr_set_ttl(record->rr, ldns_rr_ttl(rr));
            rrset->needs_signing = 1;
        }
        return ODS_STATUS_UNCHANGED;
    } else {
        record = rrset_add_rr(rrset, rr);
        ods_log_assert(record);
        ods_log_assert(record->rr);
        ods_log_assert(record->is_added);
    }
    /* update stats */
    if (do_stats && zone->stats) {
        zone->stats->sort_count += 1;
    }
    return ODS_STATUS_OK;
}
コード例 #14
0
ファイル: dnssec_sign.c プロジェクト: kaloyan13/passivedns
ldns_status
ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone,
						 ldns_rr_list *new_rrs,
						 uint8_t algorithm,
						 uint8_t flags,
						 uint16_t iterations,
						 uint8_t salt_length,
						 uint8_t *salt)
{
	ldns_rbnode_t *first_name_node;
	ldns_rbnode_t *current_name_node;
	ldns_dnssec_name *current_name;
	ldns_status result = LDNS_STATUS_OK;
	ldns_rr *nsec_rr;
	ldns_rr_list *nsec3_list;
	uint32_t nsec_ttl;
	ldns_dnssec_rrsets *soa;
	
	if (!zone || !new_rrs || !zone->names) {
		return LDNS_STATUS_ERR;
	}
	
	/* the TTL of NSEC rrs should be set to the minimum TTL of
	 * the zone SOA (RFC4035 Section 2.3)
	 */
	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
	
	/* did the caller actually set it? if not,
	 * fall back to default ttl
	 */
	if (soa && soa->rrs && soa->rrs->rr) {
		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(
		                                     soa->rrs->rr, 6));
	} else {
		nsec_ttl = LDNS_DEFAULT_TTL;
	}

	nsec3_list = ldns_rr_list_new();

	first_name_node = ldns_dnssec_name_node_next_nonglue(
					  ldns_rbtree_first(zone->names));
	
	current_name_node = first_name_node;

	while (current_name_node &&
	       current_name_node != LDNS_RBTREE_NULL) {
		current_name = (ldns_dnssec_name *) current_name_node->data;
		nsec_rr = ldns_dnssec_create_nsec3(current_name,
		                                   NULL,
		                                   zone->soa->name,
		                                   algorithm,
		                                   flags,
		                                   iterations,
		                                   salt_length,
		                                   salt);
		/* by default, our nsec based generator adds rrsigs
		 * remove the bitmap for empty nonterminals */
		if (!current_name->rrsets) {
			ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
		}
		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
		ldns_dnssec_name_add_rr(current_name, nsec_rr);
		ldns_rr_list_push_rr(new_rrs, nsec_rr);
		ldns_rr_list_push_rr(nsec3_list, nsec_rr);
		current_name_node = ldns_dnssec_name_node_next_nonglue(
		                   ldns_rbtree_next(current_name_node));
	}

	ldns_rr_list_sort_nsec3(nsec3_list);
	ldns_dnssec_chain_nsec3_list(nsec3_list);
	if (result != LDNS_STATUS_OK) {
		return result;
	}
	
	ldns_rr_list_free(nsec3_list);
	return result;
}
コード例 #15
0
ファイル: adapi.c プロジェクト: opendnssec/opendnssec
/**
 * Process SOA.
 *
 */
static ods_status
adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup)
{
    uint32_t tmp = 0;
    ldns_rdf* soa_rdata = NULL;
    ods_status status = ODS_STATUS_OK;

    ods_log_assert(rr);
    ods_log_assert(zone);
    ods_log_assert(zone->name);
    ods_log_assert(zone->signconf);

    if (backup) {
        /* no need to do processing */
        return ODS_STATUS_OK;
    }
    if (zone->signconf->soa_ttl) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
        ods_log_verbose("[%s] zone %s set soa ttl to %u",
            adapi_str, zone->name, tmp);
        ldns_rr_set_ttl(rr, tmp);
    }
    if (zone->signconf->soa_min) {
        tmp = (uint32_t) duration2time(zone->signconf->soa_min);
        ods_log_verbose("[%s] zone %s set soa minimum to %u",
            adapi_str, zone->name, tmp);
        soa_rdata = ldns_rr_set_rdf(rr,
            ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
            SE_SOA_RDATA_MINIMUM);
        if (soa_rdata) {
            ldns_rdf_deep_free(soa_rdata);
            soa_rdata = NULL;
        } else {
            ods_log_error("[%s] unable to %s soa to zone %s: failed to replace "
                "soa minimum rdata", adapi_str, add?"add":"delete",
                zone->name);
            return ODS_STATUS_ASSERT_ERR;
        }
    }
    if (!add) {
        /* we are done */
        return ODS_STATUS_OK;
    }
    tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
    status = namedb_update_serial(zone->db, zone->name,
        zone->signconf->soa_serial, tmp);
    if (status != ODS_STATUS_OK) {
        ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
            "soa serial rdata (%s)", adapi_str, zone->name,
            ods_status2str(status));
        if (status == ODS_STATUS_CONFLICT_ERR) {
            ods_log_error("[%s] If this is the result of a key rollover, "
                "please increment the serial in the unsigned zone %s",
                adapi_str, zone->name);
        }
        return status;
    }
    ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_str,
        zone->name, zone->db->intserial);
    soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
        zone->db->intserial), SE_SOA_RDATA_SERIAL);
    if (soa_rdata) {
        ldns_rdf_deep_free(soa_rdata);
        soa_rdata = NULL;
    } else {
        ods_log_error("[%s] unable to add soa to zone %s: failed to replace "
            "soa serial rdata", adapi_str, zone->name);
        return ODS_STATUS_ERR;
    }
    zone->db->serial_updated = 1;
    return ODS_STATUS_OK;
}
コード例 #16
0
ldns_status
ldns_pkt_tsig_sign_next(ldns_pkt *pkt, const char *key_name, const char *key_data,
	uint16_t fudge, const char *algorithm_name, ldns_rdf *query_mac, int tsig_timers_only)
{
	ldns_rr *tsig_rr;
	ldns_rdf *key_name_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, key_name);
	ldns_rdf *fudge_rdf = NULL;
	ldns_rdf *orig_id_rdf = NULL;
	ldns_rdf *algorithm_rdf;
	ldns_rdf *error_rdf = NULL;
	ldns_rdf *mac_rdf = NULL;
	ldns_rdf *other_data_rdf = NULL;

	ldns_status status = LDNS_STATUS_OK;

	uint8_t *pkt_wire = NULL;
	size_t pkt_wire_len;

	struct timeval tv_time_signed;
	uint8_t *time_signed = NULL;
	ldns_rdf *time_signed_rdf = NULL;

	algorithm_rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, algorithm_name);
	if(!key_name_rdf || !algorithm_rdf) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}

	/* eww don't have create tsigtime rdf yet :( */
	/* bleh :p */
	if (gettimeofday(&tv_time_signed, NULL) == 0) {
		time_signed = LDNS_XMALLOC(uint8_t, 6);
		if(!time_signed) {
			status = LDNS_STATUS_MEM_ERR;
			goto clean;
		}
		ldns_write_uint64_as_uint48(time_signed,
				(uint64_t)tv_time_signed.tv_sec);
	} else {
		status = LDNS_STATUS_INTERNAL_ERR;
		goto clean;
	}

	time_signed_rdf = ldns_rdf_new(LDNS_RDF_TYPE_TSIGTIME, 6, time_signed);
	if(!time_signed_rdf) {
		LDNS_FREE(time_signed);
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}

	fudge_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, fudge);

	orig_id_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, ldns_pkt_id(pkt));

	error_rdf = ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, 0);

	other_data_rdf = ldns_native2rdf_int16_data(0, NULL);

	if(!fudge_rdf || !orig_id_rdf || !error_rdf || !other_data_rdf) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}

	if (ldns_pkt2wire(&pkt_wire, pkt, &pkt_wire_len) != LDNS_STATUS_OK) {
		status = LDNS_STATUS_ERR;
		goto clean;
	}

	status = ldns_tsig_mac_new(&mac_rdf, pkt_wire, pkt_wire_len,
			key_data, key_name_rdf, fudge_rdf, algorithm_rdf,
			time_signed_rdf, error_rdf, other_data_rdf, query_mac, tsig_timers_only);

	if (!mac_rdf) {
		goto clean;
	}

	LDNS_FREE(pkt_wire);

	/* Create the TSIG RR */
	tsig_rr = ldns_rr_new();
	if(!tsig_rr) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}
	ldns_rr_set_owner(tsig_rr, key_name_rdf);
	ldns_rr_set_class(tsig_rr, LDNS_RR_CLASS_ANY);
	ldns_rr_set_type(tsig_rr, LDNS_RR_TYPE_TSIG);
	ldns_rr_set_ttl(tsig_rr, 0);

	ldns_rr_push_rdf(tsig_rr, algorithm_rdf);
	ldns_rr_push_rdf(tsig_rr, time_signed_rdf);
	ldns_rr_push_rdf(tsig_rr, fudge_rdf);
	ldns_rr_push_rdf(tsig_rr, mac_rdf);
	ldns_rr_push_rdf(tsig_rr, orig_id_rdf);
	ldns_rr_push_rdf(tsig_rr, error_rdf);
	ldns_rr_push_rdf(tsig_rr, other_data_rdf);

	ldns_pkt_set_tsig(pkt, tsig_rr);

	return status;

  clean:
	LDNS_FREE(pkt_wire);
	ldns_rdf_free(key_name_rdf);
	ldns_rdf_free(algorithm_rdf);
	ldns_rdf_free(time_signed_rdf);
	ldns_rdf_free(fudge_rdf);
	ldns_rdf_free(orig_id_rdf);
	ldns_rdf_free(error_rdf);
	ldns_rdf_free(other_data_rdf);
	return status;
}
コード例 #17
0
/**
 * Publish the keys as indicated by the signer configuration.
 *
 */
ods_status
zone_publish_dnskeys(zone_type* zone)
{
    hsm_ctx_t* ctx = NULL;
    uint32_t ttl = 0;
    uint16_t i = 0;
    ods_status status = ODS_STATUS_OK;
    rrset_type* rrset = NULL;
    rr_type* dnskey = NULL;

    if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
        return ODS_STATUS_ASSERT_ERR;
    }
    ods_log_assert(zone->name);

    /* hsm access */
    ctx = hsm_create_context();
    if (ctx == NULL) {
        ods_log_error("[%s] unable to publish keys for zone %s: "
            "error creating libhsm context", zone_str, zone->name);
        return ODS_STATUS_HSM_ERR;
    }
    /* dnskey ttl */
    ttl = zone->default_ttl;
    if (zone->signconf->dnskey_ttl) {
        ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
    }
    /* publish keys */
    for (i=0; i < zone->signconf->keys->count; i++) {
        if (!zone->signconf->keys->keys[i].publish) {
            continue;
        }
        if (!zone->signconf->keys->keys[i].dnskey) {
            /* get dnskey */
            status = lhsm_get_key(ctx, zone->apex,
                &zone->signconf->keys->keys[i]);
            if (status != ODS_STATUS_OK) {
                ods_log_error("[%s] unable to publish dnskeys for zone %s: "
                    "error creating dnskey", zone_str, zone->name);
                break;
            }
        }
        ods_log_assert(zone->signconf->keys->keys[i].dnskey);
        ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
        ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
        status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
        if (status == ODS_STATUS_UNCHANGED) {
            /* rr already exists, adjust pointer */
            rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
            ods_log_assert(rrset);
            dnskey = rrset_lookup_rr(rrset,
                zone->signconf->keys->keys[i].dnskey);
            ods_log_assert(dnskey);
            if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
                ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
            }
            zone->signconf->keys->keys[i].dnskey = dnskey->rr;
            status = ODS_STATUS_OK;
        } else if (status != ODS_STATUS_OK) {
            ods_log_error("[%s] unable to publish dnskeys for zone %s: "
                "error adding dnskey", zone_str, zone->name);
            break;
        }
    }
    /* done */
    hsm_destroy_context(ctx);
    return status;
}