freebsd-dev/contrib/ldns/dnssec_sign.c
Dag-Erling Smørgrav 986ba33c7a Upgrade LDNS to 1.7.0.
I've been holding back on this because 1.7.0 requires OpenSSL 1.1.0 or
newer for full DANE support.  But we can't wait forever, and nothing in
base uses DANE anyway, so here we go.
2018-05-12 12:00:18 +00:00

1600 lines
41 KiB
C

#include <ldns/config.h>
#include <ldns/ldns.h>
#include <ldns/dnssec.h>
#include <ldns/dnssec_sign.h>
#include <strings.h>
#include <time.h>
#ifdef HAVE_SSL
/* this entire file is rather useless when you don't have
* crypto...
*/
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#endif /* HAVE_SSL */
ldns_rr *
ldns_create_empty_rrsig(const ldns_rr_list *rrset,
const ldns_key *current_key)
{
uint32_t orig_ttl;
ldns_rr_class orig_class;
time_t now;
ldns_rr *current_sig;
uint8_t label_count;
ldns_rdf *signame;
label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset,
0)));
/* RFC4035 2.2: not counting the leftmost label if it is a wildcard */
if(ldns_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0))))
label_count --;
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));
orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
ldns_rr_set_ttl(current_sig, orig_ttl);
ldns_rr_set_class(current_sig, orig_class);
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 */
signame = ldns_rdf_clone(ldns_key_pubkey_owner(current_key));
ldns_dname2canonical(signame);
(void)ldns_rr_rrsig_set_signame(
current_sig,
signame);
/* 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;
}
#ifdef HAVE_SSL
ldns_rdf *
ldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *current_key)
{
ldns_rdf *b64rdf = NULL;
switch(ldns_key_algorithm(current_key)) {
#ifdef USE_DSA
case LDNS_SIGN_DSA:
case LDNS_SIGN_DSA_NSEC3:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
# ifdef HAVE_EVP_DSS1
EVP_dss1()
# else
EVP_sha1()
# endif
);
break;
#endif /* USE_DSA */
case LDNS_SIGN_RSASHA1:
case LDNS_SIGN_RSASHA1_NSEC3:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha1());
break;
#ifdef USE_SHA2
case LDNS_SIGN_RSASHA256:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha256());
break;
case LDNS_SIGN_RSASHA512:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha512());
break;
#endif /* USE_SHA2 */
#ifdef USE_GOST
case LDNS_SIGN_ECC_GOST:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_get_digestbyname("md_gost94"));
break;
#endif /* USE_GOST */
#ifdef USE_ECDSA
case LDNS_SIGN_ECDSAP256SHA256:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha256());
break;
case LDNS_SIGN_ECDSAP384SHA384:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha384());
break;
#endif
#ifdef USE_ED25519
case LDNS_SIGN_ED25519:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha512());
break;
#endif
#ifdef USE_ED448
case LDNS_SIGN_ED448:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_sha512());
break;
#endif
case LDNS_SIGN_RSAMD5:
b64rdf = ldns_sign_public_evp(
sign_buf,
ldns_key_evp_key(current_key),
EVP_md5());
break;
default:
/* do _you_ know this alg? */
printf("unknown algorithm, ");
printf("is the one used available on this system?\n");
break;
}
return b64rdf;
}
/**
* 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;
}
/**
* Sign data with DSA
*
* \param[in] to_sign The ldns_buffer containing raw data that is
* to be signed
* \param[in] key The DSA key structure to sign with
* \return ldns_rdf for the RRSIG ldns_rr
*/
ldns_rdf *
ldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key)
{
#ifdef USE_DSA
unsigned char *sha1_hash;
ldns_rdf *sigdata_rdf;
ldns_buffer *b64sig;
DSA_SIG *sig;
const BIGNUM *R, *S;
uint8_t *data;
size_t pad;
b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (!b64sig) {
return NULL;
}
sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
ldns_buffer_position(to_sign), NULL);
if (!sha1_hash) {
ldns_buffer_free(b64sig);
return NULL;
}
sig = DSA_do_sign(sha1_hash, SHA_DIGEST_LENGTH, key);
if(!sig) {
ldns_buffer_free(b64sig);
return NULL;
}
data = LDNS_XMALLOC(uint8_t, 1 + 2 * SHA_DIGEST_LENGTH);
if(!data) {
ldns_buffer_free(b64sig);
DSA_SIG_free(sig);
return NULL;
}
data[0] = 1;
# ifdef HAVE_DSA_SIG_GET0
DSA_SIG_get0(sig, &R, &S);
# else
R = sig->r;
S = sig->s;
# endif
pad = 20 - (size_t) BN_num_bytes(R);
if (pad > 0) {
memset(data + 1, 0, pad);
}
BN_bn2bin(R, (unsigned char *) (data + 1) + pad);
pad = 20 - (size_t) BN_num_bytes(S);
if (pad > 0) {
memset(data + 1 + SHA_DIGEST_LENGTH, 0, pad);
}
BN_bn2bin(S, (unsigned char *) (data + 1 + SHA_DIGEST_LENGTH + pad));
sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
1 + 2 * SHA_DIGEST_LENGTH,
data);
ldns_buffer_free(b64sig);
LDNS_FREE(data);
DSA_SIG_free(sig);
return sigdata_rdf;
#else
(void)to_sign; (void)key;
return NULL;
#endif
}
#ifdef USE_ECDSA
#ifndef S_SPLINT_S
/** returns the number of bytes per signature-component (i.e. bits/8), or 0. */
static int
ldns_pkey_is_ecdsa(EVP_PKEY* pkey)
{
EC_KEY* ec;
const EC_GROUP* g;
#ifdef HAVE_EVP_PKEY_BASE_ID
if(EVP_PKEY_base_id(pkey) != EVP_PKEY_EC)
return 0;
#else
if(EVP_PKEY_type(key->type) != EVP_PKEY_EC)
return 0;
#endif
ec = EVP_PKEY_get1_EC_KEY(pkey);
g = EC_KEY_get0_group(ec);
if(!g) {
EC_KEY_free(ec);
return 0;
}
if(EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1) {
EC_KEY_free(ec);
return 32; /* 256/8 */
}
if(EC_GROUP_get_curve_name(g) == NID_secp384r1) {
EC_KEY_free(ec);
return 48; /* 384/8 */
}
/* downref the eckey, the original is still inside the pkey */
EC_KEY_free(ec);
return 0;
}
#endif /* splint */
#endif /* USE_ECDSA */
ldns_rdf *
ldns_sign_public_evp(ldns_buffer *to_sign,
EVP_PKEY *key,
const EVP_MD *digest_type)
{
unsigned int siglen;
ldns_rdf *sigdata_rdf = NULL;
ldns_buffer *b64sig;
EVP_MD_CTX *ctx;
const EVP_MD *md_type;
int r;
siglen = 0;
b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (!b64sig) {
return NULL;
}
/* initializes a signing context */
md_type = digest_type;
if(!md_type) {
/* unknown message difest */
ldns_buffer_free(b64sig);
return NULL;
}
#ifdef HAVE_EVP_MD_CTX_NEW
ctx = EVP_MD_CTX_new();
#else
ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
if(ctx) EVP_MD_CTX_init(ctx);
#endif
if(!ctx) {
ldns_buffer_free(b64sig);
return NULL;
}
r = EVP_SignInit(ctx, md_type);
if(r == 1) {
r = EVP_SignUpdate(ctx, (unsigned char*)
ldns_buffer_begin(to_sign),
ldns_buffer_position(to_sign));
} else {
ldns_buffer_free(b64sig);
EVP_MD_CTX_destroy(ctx);
return NULL;
}
if(r == 1) {
r = EVP_SignFinal(ctx, (unsigned char*)
ldns_buffer_begin(b64sig), &siglen, key);
} else {
ldns_buffer_free(b64sig);
EVP_MD_CTX_destroy(ctx);
return NULL;
}
if(r != 1) {
ldns_buffer_free(b64sig);
EVP_MD_CTX_destroy(ctx);
return NULL;
}
/* OpenSSL output is different, convert it */
r = 0;
#ifdef USE_DSA
#ifndef S_SPLINT_S
/* unfortunately, OpenSSL output is different from DNS DSA format */
# ifdef HAVE_EVP_PKEY_BASE_ID
if (EVP_PKEY_base_id(key) == EVP_PKEY_DSA) {
# else
if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) {
# endif
r = 1;
sigdata_rdf = ldns_convert_dsa_rrsig_asn12rdf(b64sig, siglen);
}
#endif
#endif
#if defined(USE_ECDSA) || defined(USE_ED25519) || defined(USE_ED448)
if(
# ifdef HAVE_EVP_PKEY_BASE_ID
EVP_PKEY_base_id(key)
# else
EVP_PKEY_type(key->type)
# endif
== EVP_PKEY_EC) {
# ifdef USE_ECDSA
if(ldns_pkey_is_ecdsa(key)) {
r = 1;
sigdata_rdf = ldns_convert_ecdsa_rrsig_asn1len2rdf(
b64sig, (long)siglen, ldns_pkey_is_ecdsa(key));
}
# endif /* USE_ECDSA */
# ifdef USE_ED25519
if(EVP_PKEY_id(key) == NID_X25519) {
r = 1;
sigdata_rdf = ldns_convert_ed25519_rrsig_asn12rdf(
b64sig, siglen);
}
# endif /* USE_ED25519 */
# ifdef USE_ED448
if(EVP_PKEY_id(key) == NID_X448) {
r = 1;
sigdata_rdf = ldns_convert_ed448_rrsig_asn12rdf(
b64sig, siglen);
}
# endif /* USE_ED448 */
}
#endif /* PKEY_EC */
if(r == 0) {
/* ok output for other types is the same */
sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
ldns_buffer_begin(b64sig));
}
ldns_buffer_free(b64sig);
EVP_MD_CTX_destroy(ctx);
return sigdata_rdf;
}
ldns_rdf *
ldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key)
{
unsigned char *sha1_hash;
unsigned int siglen;
ldns_rdf *sigdata_rdf;
ldns_buffer *b64sig;
int result;
siglen = 0;
b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (!b64sig) {
return NULL;
}
sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
ldns_buffer_position(to_sign), NULL);
if (!sha1_hash) {
ldns_buffer_free(b64sig);
return NULL;
}
result = RSA_sign(NID_sha1, sha1_hash, SHA_DIGEST_LENGTH,
(unsigned char*)ldns_buffer_begin(b64sig),
&siglen, key);
if (result != 1) {
ldns_buffer_free(b64sig);
return NULL;
}
sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
ldns_buffer_begin(b64sig));
ldns_buffer_free(b64sig); /* can't free this buffer ?? */
return sigdata_rdf;
}
ldns_rdf *
ldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key)
{
unsigned char *md5_hash;
unsigned int siglen;
ldns_rdf *sigdata_rdf;
ldns_buffer *b64sig;
b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (!b64sig) {
return NULL;
}
md5_hash = MD5((unsigned char*)ldns_buffer_begin(to_sign),
ldns_buffer_position(to_sign), NULL);
if (!md5_hash) {
ldns_buffer_free(b64sig);
return NULL;
}
RSA_sign(NID_md5, md5_hash, MD5_DIGEST_LENGTH,
(unsigned char*)ldns_buffer_begin(b64sig),
&siglen, key);
sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
ldns_buffer_begin(b64sig));
ldns_buffer_free(b64sig);
return sigdata_rdf;
}
#endif /* HAVE_SSL */
/**
* Pushes all rrs from the rrsets of type A and AAAA on gluelist.
*/
static ldns_status
ldns_dnssec_addresses_on_glue_list(
ldns_dnssec_rrsets *cur_rrset,
ldns_rr_list *glue_list)
{
ldns_dnssec_rrs *cur_rrs;
while (cur_rrset) {
if (cur_rrset->type == LDNS_RR_TYPE_A
|| cur_rrset->type == LDNS_RR_TYPE_AAAA) {
for (cur_rrs = cur_rrset->rrs;
cur_rrs;
cur_rrs = cur_rrs->next) {
if (cur_rrs->rr) {
if (!ldns_rr_list_push_rr(glue_list,
cur_rrs->rr)) {
return LDNS_STATUS_MEM_ERR;
/* ldns_rr_list_push_rr()
* returns false when unable
* to increase the capacity
* of the ldsn_rr_list
*/
}
}
}
}
cur_rrset = cur_rrset->next;
}
return LDNS_STATUS_OK;
}
/**
* Marks the names in the zone that are occluded. Those names will be skipped
* when walking the tree with the ldns_dnssec_name_node_next_nonglue()
* function. But watch out! Names that are partially occluded (like glue with
* the same name as the delegation) will not be marked and should specifically
* be taken into account separately.
*
* When glue_list is given (not NULL), in the process of marking the names, all
* glue resource records will be pushed to that list, even glue at delegation names.
*
* \param[in] zone the zone in which to mark the names
* \param[in] glue_list the list to which to push the glue rrs
* \return LDNS_STATUS_OK on success, an error code otherwise
*/
ldns_status
ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
ldns_rr_list *glue_list)
{
ldns_rbnode_t *node;
ldns_dnssec_name *name;
ldns_rdf *owner;
ldns_rdf *cut = NULL; /* keeps track of zone cuts */
/* When the cut is caused by a delegation, below_delegation will be 1.
* When caused by a DNAME, below_delegation will be 0.
*/
int below_delegation = -1; /* init suppresses comiler warning */
ldns_status s;
if (!zone || !zone->names) {
return LDNS_STATUS_NULL;
}
for (node = ldns_rbtree_first(zone->names);
node != LDNS_RBTREE_NULL;
node = ldns_rbtree_next(node)) {
name = (ldns_dnssec_name *) node->data;
owner = ldns_dnssec_name_name(name);
if (cut) {
/* The previous node was a zone cut, or a subdomain
* below a zone cut. Is this node (still) a subdomain
* below the cut? Then the name is occluded. Unless
* the name contains a SOA, after which we are
* authoritative again.
*
* FIXME! If there are labels in between the SOA and
* the cut, going from the authoritative space (below
* the SOA) up into occluded space again, will not be
* detected with the contruct below!
*/
if (ldns_dname_is_subdomain(owner, cut) &&
!ldns_dnssec_rrsets_contains_type(
name->rrsets, LDNS_RR_TYPE_SOA)) {
if (below_delegation && glue_list) {
s = ldns_dnssec_addresses_on_glue_list(
name->rrsets, glue_list);
if (s != LDNS_STATUS_OK) {
return s;
}
}
name->is_glue = true; /* Mark occluded name! */
continue;
} else {
cut = NULL;
}
}
/* The node is not below a zone cut. Is it a zone cut itself?
* Everything below a SOA is authoritative of course; Except
* when the name also contains a DNAME :).
*/
if (ldns_dnssec_rrsets_contains_type(
name->rrsets, LDNS_RR_TYPE_NS)
&& !ldns_dnssec_rrsets_contains_type(
name->rrsets, LDNS_RR_TYPE_SOA)) {
cut = owner;
below_delegation = 1;
if (glue_list) { /* record glue on the zone cut */
s = ldns_dnssec_addresses_on_glue_list(
name->rrsets, glue_list);
if (s != LDNS_STATUS_OK) {
return s;
}
}
} else if (ldns_dnssec_rrsets_contains_type(
name->rrsets, LDNS_RR_TYPE_DNAME)) {
cut = owner;
below_delegation = 0;
}
}
return LDNS_STATUS_OK;
}
/**
* Marks the names in the zone that are occluded. Those names will be skipped
* when walking the tree with the ldns_dnssec_name_node_next_nonglue()
* function. But watch out! Names that are partially occluded (like glue with
* the same name as the delegation) will not be marked and should specifically
* be taken into account separately.
*
* \param[in] zone the zone in which to mark the names
* \return LDNS_STATUS_OK on success, an error code otherwise
*/
ldns_status
ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone)
{
return ldns_dnssec_zone_mark_and_get_glue(zone, NULL);
}
ldns_rbnode_t *
ldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node)
{
ldns_rbnode_t *next_node = NULL;
ldns_dnssec_name *next_name = NULL;
bool done = false;
if (node == LDNS_RBTREE_NULL) {
return NULL;
}
next_node = node;
while (!done) {
if (next_node == LDNS_RBTREE_NULL) {
return NULL;
} else {
next_name = (ldns_dnssec_name *)next_node->data;
if (!next_name->is_glue) {
done = true;
} else {
next_node = ldns_rbtree_next(next_node);
}
}
}
return next_node;
}
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
&& (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;
}
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);
if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
ldns_rr_free(nsec_rr);
return LDNS_STATUS_ERR;
}
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);
if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
ldns_rr_free(nsec_rr);
return LDNS_STATUS_ERR;
}
ldns_rr_list_push_rr(new_rrs, nsec_rr);
} else {
printf("error\n");
}
return LDNS_STATUS_OK;
}
#ifdef HAVE_SSL
static void
ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
(void) arg;
LDNS_FREE(node);
}
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 (ldns_rdf_size(zone->soa->name) > 222) {
return LDNS_STATUS_NSEC3_DOMAINNAME_OVERFLOW;
}
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;
}
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)
{
return ldns_dnssec_zone_create_nsec3s_mkmap(zone, new_rrs, algorithm,
flags, iterations, salt_length, salt, NULL);
}
#endif /* HAVE_SSL */
ldns_dnssec_rrs *
ldns_dnssec_remove_signatures( ldns_dnssec_rrs *signatures
, ATTR_UNUSED(ldns_key_list *key_list)
, int (*func)(ldns_rr *, void *)
, void *arg
)
{
ldns_dnssec_rrs *base_rrs = signatures;
ldns_dnssec_rrs *cur_rr = base_rrs;
ldns_dnssec_rrs *prev_rr = NULL;
ldns_dnssec_rrs *next_rr;
uint16_t keytag;
size_t i;
if (!cur_rr) {
switch(func(NULL, arg)) {
case LDNS_SIGNATURE_LEAVE_ADD_NEW:
case LDNS_SIGNATURE_REMOVE_ADD_NEW:
break;
case LDNS_SIGNATURE_LEAVE_NO_ADD:
case LDNS_SIGNATURE_REMOVE_NO_ADD:
ldns_key_list_set_use(key_list, false);
break;
default:
#ifdef STDERR_MSGS
fprintf(stderr, "[XX] unknown return value from callback\n");
#endif
break;
}
return NULL;
}
(void)func(cur_rr->rr, arg);
while (cur_rr) {
next_rr = cur_rr->next;
switch (func(cur_rr->rr, arg)) {
case LDNS_SIGNATURE_LEAVE_ADD_NEW:
prev_rr = cur_rr;
break;
case LDNS_SIGNATURE_LEAVE_NO_ADD:
keytag = ldns_rdf2native_int16(
ldns_rr_rrsig_keytag(cur_rr->rr));
for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
if (ldns_key_keytag(ldns_key_list_key(key_list, i)) ==
keytag) {
ldns_key_set_use(ldns_key_list_key(key_list, i),
false);
}
}
prev_rr = cur_rr;
break;
case LDNS_SIGNATURE_REMOVE_NO_ADD:
keytag = ldns_rdf2native_int16(
ldns_rr_rrsig_keytag(cur_rr->rr));
for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
if (ldns_key_keytag(ldns_key_list_key(key_list, i))
== keytag) {
ldns_key_set_use(ldns_key_list_key(key_list, i),
false);
}
}
if (prev_rr) {
prev_rr->next = next_rr;
} else {
base_rrs = next_rr;
}
LDNS_FREE(cur_rr);
break;
case LDNS_SIGNATURE_REMOVE_ADD_NEW:
if (prev_rr) {
prev_rr->next = next_rr;
} else {
base_rrs = next_rr;
}
LDNS_FREE(cur_rr);
break;
default:
#ifdef STDERR_MSGS
fprintf(stderr, "[XX] unknown return value from callback\n");
#endif
break;
}
cur_rr = next_rr;
}
return base_rrs;
}
#ifdef HAVE_SSL
ldns_status
ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void*),
void *arg)
{
return ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list,
func, arg, 0);
}
/** If there are KSKs use only them and mark ZSKs unused */
static void
ldns_key_list_filter_for_dnskey(ldns_key_list *key_list, int flags)
{
bool algos[256]
#ifndef S_SPLINT_S
= { false }
#endif
;
ldns_signing_algorithm saw_ksk = 0;
ldns_key *key;
size_t i;
if (!ldns_key_list_key_count(key_list))
return;
for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
key = ldns_key_list_key(key_list, i);
if ((ldns_key_flags(key) & LDNS_KEY_SEP_KEY) && !saw_ksk)
saw_ksk = ldns_key_algorithm(key);
algos[ldns_key_algorithm(key)] = true;
}
if (!saw_ksk)
return;
else
algos[saw_ksk] = 0;
for (i =0; i < ldns_key_list_key_count(key_list); i++) {
key = ldns_key_list_key(key_list, i);
if (!(ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
/* We have a ZSK.
* Still use it if it has a unique algorithm though!
*/
if ((flags & LDNS_SIGN_WITH_ALL_ALGORITHMS) &&
algos[ldns_key_algorithm(key)])
algos[ldns_key_algorithm(key)] = false;
else
ldns_key_set_use(key, 0);
}
}
}
/** If there are no ZSKs use KSK as ZSK */
static void
ldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list, int flags)
{
bool algos[256]
#ifndef S_SPLINT_S
= { false }
#endif
;
ldns_signing_algorithm saw_zsk = 0;
ldns_key *key;
size_t i;
if (!ldns_key_list_key_count(key_list))
return;
for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
key = ldns_key_list_key(key_list, i);
if (!(ldns_key_flags(key) & LDNS_KEY_SEP_KEY) && !saw_zsk)
saw_zsk = ldns_key_algorithm(key);
algos[ldns_key_algorithm(key)] = true;
}
if (!saw_zsk)
return;
else
algos[saw_zsk] = 0;
for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
key = ldns_key_list_key(key_list, i);
if((ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) {
/* We have a KSK.
* Still use it if it has a unique algorithm though!
*/
if ((flags & LDNS_SIGN_WITH_ALL_ALGORITHMS) &&
algos[ldns_key_algorithm(key)])
algos[ldns_key_algorithm(key)] = false;
else
ldns_key_set_use(key, 0);
}
}
}
ldns_status
ldns_dnssec_zone_create_rrsigs_flg( ldns_dnssec_zone *zone
, ldns_rr_list *new_rrs
, ldns_key_list *key_list
, int (*func)(ldns_rr *, void*)
, void *arg
, int flags
)
{
ldns_status result = LDNS_STATUS_OK;
ldns_rbnode_t *cur_node;
ldns_rr_list *rr_list;
ldns_dnssec_name *cur_name;
ldns_dnssec_rrsets *cur_rrset;
ldns_dnssec_rrs *cur_rr;
ldns_rr_list *siglist;
size_t i;
int on_delegation_point = 0; /* handle partially occluded names */
ldns_rr_list *pubkey_list = ldns_rr_list_new();
for (i = 0; i<ldns_key_list_key_count(key_list); i++) {
ldns_rr_list_push_rr( pubkey_list
, ldns_key2rr(ldns_key_list_key(
key_list, i))
);
}
/* TODO: callback to see is list should be signed */
/* TODO: remove 'old' signatures from signature list */
cur_node = ldns_rbtree_first(zone->names);
while (cur_node != LDNS_RBTREE_NULL) {
cur_name = (ldns_dnssec_name *) cur_node->data;
if (!cur_name->is_glue) {
on_delegation_point = ldns_dnssec_rrsets_contains_type(
cur_name->rrsets, LDNS_RR_TYPE_NS)
&& !ldns_dnssec_rrsets_contains_type(
cur_name->rrsets, LDNS_RR_TYPE_SOA);
cur_rrset = cur_name->rrsets;
while (cur_rrset) {
/* reset keys to use */
ldns_key_list_set_use(key_list, true);
/* walk through old sigs, remove the old,
and mark which keys (not) to use) */
cur_rrset->signatures =
ldns_dnssec_remove_signatures(cur_rrset->signatures,
key_list,
func,
arg);
if(!(flags&LDNS_SIGN_DNSKEY_WITH_ZSK) &&
cur_rrset->type == LDNS_RR_TYPE_DNSKEY)
ldns_key_list_filter_for_dnskey(key_list, flags);
if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY)
ldns_key_list_filter_for_non_dnskey(key_list, flags);
/* TODO: just set count to zero? */
rr_list = ldns_rr_list_new();
cur_rr = cur_rrset->rrs;
while (cur_rr) {
ldns_rr_list_push_rr(rr_list, cur_rr->rr);
cur_rr = cur_rr->next;
}
/* only sign non-delegation RRsets */
/* (glue should have been marked earlier,
* except on the delegation points itself) */
if (!on_delegation_point ||
ldns_rr_list_type(rr_list)
== LDNS_RR_TYPE_DS ||
ldns_rr_list_type(rr_list)
== LDNS_RR_TYPE_NSEC ||
ldns_rr_list_type(rr_list)
== LDNS_RR_TYPE_NSEC3) {
siglist = ldns_sign_public(rr_list, key_list);
for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
if (cur_rrset->signatures) {
result = ldns_dnssec_rrs_add_rr(cur_rrset->signatures,
ldns_rr_list_rr(siglist,
i));
} else {
cur_rrset->signatures = ldns_dnssec_rrs_new();
cur_rrset->signatures->rr =
ldns_rr_list_rr(siglist, i);
}
if (new_rrs) {
ldns_rr_list_push_rr(new_rrs,
ldns_rr_list_rr(siglist,
i));
}
}
ldns_rr_list_free(siglist);
}
ldns_rr_list_free(rr_list);
cur_rrset = cur_rrset->next;
}
/* sign the nsec */
ldns_key_list_set_use(key_list, true);
cur_name->nsec_signatures =
ldns_dnssec_remove_signatures(cur_name->nsec_signatures,
key_list,
func,
arg);
ldns_key_list_filter_for_non_dnskey(key_list, flags);
rr_list = ldns_rr_list_new();
ldns_rr_list_push_rr(rr_list, cur_name->nsec);
siglist = ldns_sign_public(rr_list, key_list);
for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
if (cur_name->nsec_signatures) {
result = ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures,
ldns_rr_list_rr(siglist, i));
} else {
cur_name->nsec_signatures = ldns_dnssec_rrs_new();
cur_name->nsec_signatures->rr =
ldns_rr_list_rr(siglist, i);
}
if (new_rrs) {
ldns_rr_list_push_rr(new_rrs,
ldns_rr_list_rr(siglist, i));
}
}
ldns_rr_list_free(siglist);
ldns_rr_list_free(rr_list);
}
cur_node = ldns_rbtree_next(cur_node);
}
ldns_rr_list_deep_free(pubkey_list);
return result;
}
ldns_status
ldns_dnssec_zone_sign(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void *),
void *arg)
{
return ldns_dnssec_zone_sign_flg(zone, new_rrs, key_list, func, arg, 0);
}
ldns_status
ldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void *),
void *arg,
int flags)
{
ldns_status result = LDNS_STATUS_OK;
if (!zone || !new_rrs || !key_list) {
return LDNS_STATUS_ERR;
}
/* zone is already sorted */
result = ldns_dnssec_zone_mark_glue(zone);
if (result != LDNS_STATUS_OK) {
return result;
}
/* check whether we need to add nsecs */
if (zone->names && !((ldns_dnssec_name *)zone->names->root->data)->nsec) {
result = ldns_dnssec_zone_create_nsecs(zone, new_rrs);
if (result != LDNS_STATUS_OK) {
return result;
}
}
result = ldns_dnssec_zone_create_rrsigs_flg(zone,
new_rrs,
key_list,
func,
arg,
flags);
return result;
}
ldns_status
ldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void *),
void *arg,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
uint8_t *salt)
{
return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
func, arg, algorithm, flags, iterations, salt_length, salt, 0,
NULL);
}
ldns_status
ldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void *),
void *arg,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
uint8_t *salt,
int signflags,
ldns_rbtree_t **map)
{
ldns_rr *nsec3, *nsec3param;
ldns_status result = LDNS_STATUS_OK;
/* zone is already sorted */
result = ldns_dnssec_zone_mark_glue(zone);
if (result != LDNS_STATUS_OK) {
return result;
}
/* TODO if there are already nsec3s presents and their
* parameters are the same as these, we don't have to recreate
*/
if (zone->names) {
/* add empty nonterminals */
result = ldns_dnssec_zone_add_empty_nonterminals(zone);
if (result != LDNS_STATUS_OK) {
return result;
}
nsec3 = ((ldns_dnssec_name *)zone->names->root->data)->nsec;
if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) {
/* no need to recreate */
} else {
if (!ldns_dnssec_zone_find_rrset(zone,
zone->soa->name,
LDNS_RR_TYPE_NSEC3PARAM)) {
/* create and add the nsec3param rr */
nsec3param =
ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAM);
ldns_rr_set_owner(nsec3param,
ldns_rdf_clone(zone->soa->name));
ldns_nsec3_add_param_rdfs(nsec3param,
algorithm,
flags,
iterations,
salt_length,
salt);
/* always set bit 7 of the flags to zero, according to
* rfc5155 section 11. The bits are counted from right to left,
* so bit 7 in rfc5155 is bit 0 in ldns */
ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3param, 1)), 0, 0);
result = ldns_dnssec_zone_add_rr(zone, nsec3param);
if (result != LDNS_STATUS_OK) {
return result;
}
ldns_rr_list_push_rr(new_rrs, nsec3param);
}
result = ldns_dnssec_zone_create_nsec3s_mkmap(zone,
new_rrs,
algorithm,
flags,
iterations,
salt_length,
salt,
map);
if (result != LDNS_STATUS_OK) {
return result;
}
}
result = ldns_dnssec_zone_create_rrsigs_flg(zone,
new_rrs,
key_list,
func,
arg,
signflags);
}
return result;
}
ldns_status
ldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone,
ldns_rr_list *new_rrs,
ldns_key_list *key_list,
int (*func)(ldns_rr *, void *),
void *arg,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
uint8_t *salt,
int signflags)
{
return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
func, arg, algorithm, flags, iterations, salt_length, salt,
signflags, NULL);
}
ldns_zone *
ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
{
ldns_dnssec_zone *dnssec_zone;
ldns_zone *signed_zone;
ldns_rr_list *new_rrs;
size_t i;
signed_zone = ldns_zone_new();
dnssec_zone = ldns_dnssec_zone_new();
(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
(void) ldns_dnssec_zone_add_rr(dnssec_zone,
ldns_rr_list_rr(ldns_zone_rrs(zone),
i));
ldns_zone_push_rr(signed_zone,
ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
i)));
}
new_rrs = ldns_rr_list_new();
(void) ldns_dnssec_zone_sign(dnssec_zone,
new_rrs,
key_list,
ldns_dnssec_default_replace_signatures,
NULL);
for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
}
ldns_rr_list_deep_free(new_rrs);
ldns_dnssec_zone_free(dnssec_zone);
return signed_zone;
}
ldns_zone *
ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt)
{
ldns_dnssec_zone *dnssec_zone;
ldns_zone *signed_zone;
ldns_rr_list *new_rrs;
size_t i;
signed_zone = ldns_zone_new();
dnssec_zone = ldns_dnssec_zone_new();
(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
(void) ldns_dnssec_zone_add_rr(dnssec_zone,
ldns_rr_list_rr(ldns_zone_rrs(zone),
i));
ldns_zone_push_rr(signed_zone,
ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
i)));
}
new_rrs = ldns_rr_list_new();
(void) ldns_dnssec_zone_sign_nsec3(dnssec_zone,
new_rrs,
key_list,
ldns_dnssec_default_replace_signatures,
NULL,
algorithm,
flags,
iterations,
salt_length,
salt);
for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
}
ldns_rr_list_deep_free(new_rrs);
ldns_dnssec_zone_free(dnssec_zone);
return signed_zone;
}
#endif /* HAVE_SSL */