1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00
freebsd/contrib/ldns/dnssec.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

2011 lines
51 KiB
C

/*
* dnssec.c
*
* contains the cryptographic function needed for DNSSEC in ldns
* The crypto library used is openssl
*
* (c) NLnet Labs, 2004-2008
*
* See the file LICENSE for the license
*/
#include <ldns/config.h>
#include <ldns/ldns.h>
#include <ldns/dnssec.h>
#include <strings.h>
#include <time.h>
#ifdef HAVE_SSL
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#endif
ldns_rr *
ldns_dnssec_get_rrsig_for_name_and_type(const ldns_rdf *name,
const ldns_rr_type type,
const ldns_rr_list *rrs)
{
size_t i;
ldns_rr *candidate;
if (!name || !rrs) {
return NULL;
}
for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
candidate = ldns_rr_list_rr(rrs, i);
if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_RRSIG) {
if (ldns_dname_compare(ldns_rr_owner(candidate),
name) == 0 &&
ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(candidate))
== type
) {
return candidate;
}
}
}
return NULL;
}
ldns_rr *
ldns_dnssec_get_dnskey_for_rrsig(const ldns_rr *rrsig,
const ldns_rr_list *rrs)
{
size_t i;
ldns_rr *candidate;
if (!rrsig || !rrs) {
return NULL;
}
for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
candidate = ldns_rr_list_rr(rrs, i);
if (ldns_rr_get_type(candidate) == LDNS_RR_TYPE_DNSKEY) {
if (ldns_dname_compare(ldns_rr_owner(candidate),
ldns_rr_rrsig_signame(rrsig)) == 0 &&
ldns_rdf2native_int16(ldns_rr_rrsig_keytag(rrsig)) ==
ldns_calc_keytag(candidate)
) {
return candidate;
}
}
}
return NULL;
}
ldns_rdf *
ldns_nsec_get_bitmap(const ldns_rr *nsec) {
if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) {
return ldns_rr_rdf(nsec, 1);
} else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) {
return ldns_rr_rdf(nsec, 5);
} else {
return NULL;
}
}
/*return the owner name of the closest encloser for name from the list of rrs */
/* this is NOT the hash, but the original name! */
ldns_rdf *
ldns_dnssec_nsec3_closest_encloser(const ldns_rdf *qname,
ATTR_UNUSED(ldns_rr_type qtype),
const ldns_rr_list *nsec3s)
{
/* remember parameters, they must match */
uint8_t algorithm;
uint32_t iterations;
uint8_t salt_length;
uint8_t *salt;
ldns_rdf *sname, *hashed_sname, *tmp;
bool flag;
bool exact_match_found;
bool in_range_found;
ldns_status status;
ldns_rdf *zone_name;
size_t nsec_i;
ldns_rr *nsec;
ldns_rdf *result = NULL;
if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
return NULL;
}
nsec = ldns_rr_list_rr(nsec3s, 0);
algorithm = ldns_nsec3_algorithm(nsec);
salt_length = ldns_nsec3_salt_length(nsec);
salt = ldns_nsec3_salt_data(nsec);
iterations = ldns_nsec3_iterations(nsec);
sname = ldns_rdf_clone(qname);
flag = false;
zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
/* algorithm from nsec3-07 8.3 */
while (ldns_dname_label_count(sname) > 0) {
exact_match_found = false;
in_range_found = false;
hashed_sname = ldns_nsec3_hash_name(sname,
algorithm,
iterations,
salt_length,
salt);
status = ldns_dname_cat(hashed_sname, zone_name);
if(status != LDNS_STATUS_OK) {
LDNS_FREE(salt);
ldns_rdf_deep_free(zone_name);
ldns_rdf_deep_free(sname);
return NULL;
}
for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
nsec = ldns_rr_list_rr(nsec3s, nsec_i);
/* check values of iterations etc! */
/* exact match? */
if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
exact_match_found = true;
} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
in_range_found = true;
}
}
if (!exact_match_found && in_range_found) {
flag = true;
} else if (exact_match_found && flag) {
result = ldns_rdf_clone(sname);
/* RFC 5155: 8.3. 2.** "The proof is complete" */
ldns_rdf_deep_free(hashed_sname);
goto done;
} else if (exact_match_found && !flag) {
/* error! */
ldns_rdf_deep_free(hashed_sname);
goto done;
} else {
flag = false;
}
ldns_rdf_deep_free(hashed_sname);
tmp = sname;
sname = ldns_dname_left_chop(sname);
ldns_rdf_deep_free(tmp);
}
done:
LDNS_FREE(salt);
ldns_rdf_deep_free(zone_name);
ldns_rdf_deep_free(sname);
return result;
}
bool
ldns_dnssec_pkt_has_rrsigs(const ldns_pkt *pkt)
{
size_t i;
for (i = 0; i < ldns_pkt_ancount(pkt); i++) {
if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_answer(pkt), i)) ==
LDNS_RR_TYPE_RRSIG) {
return true;
}
}
for (i = 0; i < ldns_pkt_nscount(pkt); i++) {
if (ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_authority(pkt), i)) ==
LDNS_RR_TYPE_RRSIG) {
return true;
}
}
return false;
}
ldns_rr_list *
ldns_dnssec_pkt_get_rrsigs_for_name_and_type(const ldns_pkt *pkt,
const ldns_rdf *name,
ldns_rr_type type)
{
uint16_t t_netorder;
ldns_rr_list *sigs;
ldns_rr_list *sigs_covered;
ldns_rdf *rdf_t;
sigs = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_ANY_NOQUESTION
);
t_netorder = htons(type); /* rdf are in network order! */
rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, LDNS_RDF_SIZE_WORD, &t_netorder);
sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
ldns_rdf_free(rdf_t);
ldns_rr_list_deep_free(sigs);
return sigs_covered;
}
ldns_rr_list *
ldns_dnssec_pkt_get_rrsigs_for_type(const ldns_pkt *pkt, ldns_rr_type type)
{
uint16_t t_netorder;
ldns_rr_list *sigs;
ldns_rr_list *sigs_covered;
ldns_rdf *rdf_t;
sigs = ldns_pkt_rr_list_by_type(pkt,
LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_ANY_NOQUESTION
);
t_netorder = htons(type); /* rdf are in network order! */
rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE,
2,
&t_netorder);
sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
ldns_rdf_free(rdf_t);
ldns_rr_list_deep_free(sigs);
return sigs_covered;
}
/* used only on the public key RR */
uint16_t
ldns_calc_keytag(const ldns_rr *key)
{
uint16_t ac16;
ldns_buffer *keybuf;
size_t keysize;
if (!key) {
return 0;
}
if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY &&
ldns_rr_get_type(key) != LDNS_RR_TYPE_KEY
) {
return 0;
}
/* rdata to buf - only put the rdata in a buffer */
keybuf = ldns_buffer_new(LDNS_MIN_BUFLEN); /* grows */
if (!keybuf) {
return 0;
}
(void)ldns_rr_rdata2buffer_wire(keybuf, key);
/* the current pos in the buffer is the keysize */
keysize= ldns_buffer_position(keybuf);
ac16 = ldns_calc_keytag_raw(ldns_buffer_begin(keybuf), keysize);
ldns_buffer_free(keybuf);
return ac16;
}
uint16_t ldns_calc_keytag_raw(const uint8_t* key, size_t keysize)
{
unsigned int i;
uint32_t ac32;
uint16_t ac16;
if(keysize < 4) {
return 0;
}
/* look at the algorithm field, copied from 2535bis */
if (key[3] == LDNS_RSAMD5) {
ac16 = 0;
if (keysize > 4) {
memmove(&ac16, key + keysize - 3, 2);
}
ac16 = ntohs(ac16);
return (uint16_t) ac16;
} else {
ac32 = 0;
for (i = 0; (size_t)i < keysize; ++i) {
ac32 += (i & 1) ? key[i] : key[i] << 8;
}
ac32 += (ac32 >> 16) & 0xFFFF;
return (uint16_t) (ac32 & 0xFFFF);
}
}
#ifdef HAVE_SSL
DSA *
ldns_key_buf2dsa(const ldns_buffer *key)
{
return ldns_key_buf2dsa_raw((const unsigned char*)ldns_buffer_begin(key),
ldns_buffer_position(key));
}
DSA *
ldns_key_buf2dsa_raw(const unsigned char* key, size_t len)
{
uint8_t T;
uint16_t length;
uint16_t offset;
DSA *dsa;
BIGNUM *Q; BIGNUM *P;
BIGNUM *G; BIGNUM *Y;
if(len == 0)
return NULL;
T = (uint8_t)key[0];
length = (64 + T * 8);
offset = 1;
if (T > 8) {
return NULL;
}
if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
return NULL;
Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
offset += SHA_DIGEST_LENGTH;
P = BN_bin2bn(key+offset, (int)length, NULL);
offset += length;
G = BN_bin2bn(key+offset, (int)length, NULL);
offset += length;
Y = BN_bin2bn(key+offset, (int)length, NULL);
offset += length;
/* create the key and set its properties */
if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
BN_free(Q);
BN_free(P);
BN_free(G);
BN_free(Y);
return NULL;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
#ifndef S_SPLINT_S
dsa->p = P;
dsa->q = Q;
dsa->g = G;
dsa->pub_key = Y;
#endif /* splint */
#else /* OPENSSL_VERSION_NUMBER */
if (!DSA_set0_pqg(dsa, P, Q, G)) {
/* QPG not yet attached, need to free */
BN_free(Q);
BN_free(P);
BN_free(G);
DSA_free(dsa);
BN_free(Y);
return NULL;
}
if (!DSA_set0_key(dsa, Y, NULL)) {
/* QPG attached, cleaned up by DSA_fre() */
DSA_free(dsa);
BN_free(Y);
return NULL;
}
#endif /* OPENSSL_VERSION_NUMBER */
return dsa;
}
RSA *
ldns_key_buf2rsa(const ldns_buffer *key)
{
return ldns_key_buf2rsa_raw((const unsigned char*)ldns_buffer_begin(key),
ldns_buffer_position(key));
}
RSA *
ldns_key_buf2rsa_raw(const unsigned char* key, size_t len)
{
uint16_t offset;
uint16_t exp;
uint16_t int16;
RSA *rsa;
BIGNUM *modulus;
BIGNUM *exponent;
if (len == 0)
return NULL;
if (key[0] == 0) {
if(len < 3)
return NULL;
/* need some smart comment here XXX*/
/* the exponent is too large so it's places
* futher...???? */
memmove(&int16, key+1, 2);
exp = ntohs(int16);
offset = 3;
} else {
exp = key[0];
offset = 1;
}
/* key length at least one */
if(len < (size_t)offset + exp + 1)
return NULL;
/* Exponent */
exponent = BN_new();
if(!exponent) return NULL;
(void) BN_bin2bn(key+offset, (int)exp, exponent);
offset += exp;
/* Modulus */
modulus = BN_new();
if(!modulus) {
BN_free(exponent);
return NULL;
}
/* length of the buffer must match the key length! */
(void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
rsa = RSA_new();
if(!rsa) {
BN_free(exponent);
BN_free(modulus);
return NULL;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
#ifndef S_SPLINT_S
rsa->n = modulus;
rsa->e = exponent;
#endif /* splint */
#else /* OPENSSL_VERSION_NUMBER */
if (!RSA_set0_key(rsa, modulus, exponent, NULL)) {
BN_free(exponent);
BN_free(modulus);
RSA_free(rsa);
return NULL;
}
#endif /* OPENSSL_VERSION_NUMBER */
return rsa;
}
int
ldns_digest_evp(const unsigned char* data, unsigned int len, unsigned char* dest,
const EVP_MD* md)
{
EVP_MD_CTX* ctx;
ctx = EVP_MD_CTX_create();
if(!ctx)
return false;
if(!EVP_DigestInit_ex(ctx, md, NULL) ||
!EVP_DigestUpdate(ctx, data, len) ||
!EVP_DigestFinal_ex(ctx, dest, NULL)) {
EVP_MD_CTX_destroy(ctx);
return false;
}
EVP_MD_CTX_destroy(ctx);
return true;
}
#endif /* HAVE_SSL */
ldns_rr *
ldns_key_rr2ds(const ldns_rr *key, ldns_hash h)
{
ldns_rdf *tmp;
ldns_rr *ds;
uint16_t keytag;
uint8_t sha1hash;
uint8_t *digest;
ldns_buffer *data_buf;
#ifdef USE_GOST
const EVP_MD* md = NULL;
#endif
if (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY) {
return NULL;
}
ds = ldns_rr_new();
if (!ds) {
return NULL;
}
ldns_rr_set_type(ds, LDNS_RR_TYPE_DS);
ldns_rr_set_owner(ds, ldns_rdf_clone(
ldns_rr_owner(key)));
ldns_rr_set_ttl(ds, ldns_rr_ttl(key));
ldns_rr_set_class(ds, ldns_rr_get_class(key));
switch(h) {
default:
case LDNS_SHA1:
digest = LDNS_XMALLOC(uint8_t, LDNS_SHA1_DIGEST_LENGTH);
if (!digest) {
ldns_rr_free(ds);
return NULL;
}
break;
case LDNS_SHA256:
digest = LDNS_XMALLOC(uint8_t, LDNS_SHA256_DIGEST_LENGTH);
if (!digest) {
ldns_rr_free(ds);
return NULL;
}
break;
case LDNS_HASH_GOST:
#ifdef USE_GOST
(void)ldns_key_EVP_load_gost_id();
md = EVP_get_digestbyname("md_gost94");
if(!md) {
ldns_rr_free(ds);
return NULL;
}
digest = LDNS_XMALLOC(uint8_t, EVP_MD_size(md));
if (!digest) {
ldns_rr_free(ds);
return NULL;
}
break;
#else
/* not implemented */
ldns_rr_free(ds);
return NULL;
#endif
case LDNS_SHA384:
#ifdef USE_ECDSA
digest = LDNS_XMALLOC(uint8_t, SHA384_DIGEST_LENGTH);
if (!digest) {
ldns_rr_free(ds);
return NULL;
}
break;
#else
/* not implemented */
ldns_rr_free(ds);
return NULL;
#endif
}
data_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if (!data_buf) {
LDNS_FREE(digest);
ldns_rr_free(ds);
return NULL;
}
/* keytag */
keytag = htons(ldns_calc_keytag((ldns_rr*)key));
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16,
sizeof(uint16_t),
&keytag);
ldns_rr_push_rdf(ds, tmp);
/* copy the algorithm field */
if ((tmp = ldns_rr_rdf(key, 2)) == NULL) {
LDNS_FREE(digest);
ldns_buffer_free(data_buf);
ldns_rr_free(ds);
return NULL;
} else {
ldns_rr_push_rdf(ds, ldns_rdf_clone( tmp ));
}
/* digest hash type */
sha1hash = (uint8_t)h;
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
sizeof(uint8_t),
&sha1hash);
ldns_rr_push_rdf(ds, tmp);
/* digest */
/* owner name */
tmp = ldns_rdf_clone(ldns_rr_owner(key));
ldns_dname2canonical(tmp);
if (ldns_rdf2buffer_wire(data_buf, tmp) != LDNS_STATUS_OK) {
LDNS_FREE(digest);
ldns_buffer_free(data_buf);
ldns_rr_free(ds);
ldns_rdf_deep_free(tmp);
return NULL;
}
ldns_rdf_deep_free(tmp);
/* all the rdata's */
if (ldns_rr_rdata2buffer_wire(data_buf,
(ldns_rr*)key) != LDNS_STATUS_OK) {
LDNS_FREE(digest);
ldns_buffer_free(data_buf);
ldns_rr_free(ds);
return NULL;
}
switch(h) {
case LDNS_SHA1:
(void) ldns_sha1((unsigned char *) ldns_buffer_begin(data_buf),
(unsigned int) ldns_buffer_position(data_buf),
(unsigned char *) digest);
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
LDNS_SHA1_DIGEST_LENGTH,
digest);
ldns_rr_push_rdf(ds, tmp);
break;
case LDNS_SHA256:
(void) ldns_sha256((unsigned char *) ldns_buffer_begin(data_buf),
(unsigned int) ldns_buffer_position(data_buf),
(unsigned char *) digest);
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
LDNS_SHA256_DIGEST_LENGTH,
digest);
ldns_rr_push_rdf(ds, tmp);
break;
case LDNS_HASH_GOST:
#ifdef USE_GOST
if(!ldns_digest_evp((unsigned char *) ldns_buffer_begin(data_buf),
(unsigned int) ldns_buffer_position(data_buf),
(unsigned char *) digest, md)) {
LDNS_FREE(digest);
ldns_buffer_free(data_buf);
ldns_rr_free(ds);
return NULL;
}
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
(size_t)EVP_MD_size(md),
digest);
ldns_rr_push_rdf(ds, tmp);
#endif
break;
case LDNS_SHA384:
#ifdef USE_ECDSA
(void) SHA384((unsigned char *) ldns_buffer_begin(data_buf),
(unsigned int) ldns_buffer_position(data_buf),
(unsigned char *) digest);
tmp = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
SHA384_DIGEST_LENGTH,
digest);
ldns_rr_push_rdf(ds, tmp);
#endif
break;
}
LDNS_FREE(digest);
ldns_buffer_free(data_buf);
return ds;
}
/* From RFC3845:
*
* 2.1.2. The List of Type Bit Map(s) Field
*
* The RR type space is split into 256 window blocks, each representing
* the low-order 8 bits of the 16-bit RR type space. Each block that
* has at least one active RR type is encoded using a single octet
* window number (from 0 to 255), a single octet bitmap length (from 1
* to 32) indicating the number of octets used for the window block's
* bitmap, and up to 32 octets (256 bits) of bitmap.
*
* Window blocks are present in the NSEC RR RDATA in increasing
* numerical order.
*
* "|" denotes concatenation
*
* Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) +
*
* <cut>
*
* Blocks with no types present MUST NOT be included. Trailing zero
* octets in the bitmap MUST be omitted. The length of each block's
* bitmap is determined by the type code with the largest numerical
* value within that block, among the set of RR types present at the
* NSEC RR's owner name. Trailing zero octets not specified MUST be
* interpreted as zero octets.
*/
ldns_rdf *
ldns_dnssec_create_nsec_bitmap(ldns_rr_type rr_type_list[],
size_t size,
ldns_rr_type nsec_type)
{
uint8_t window; /* most significant octet of type */
uint8_t subtype; /* least significant octet of type */
int windows[256]; /* Max subtype per window */
uint8_t windowpresent[256]; /* bool if window appears in bitmap */
ldns_rr_type* d; /* used to traverse rr_type_list*/
size_t i; /* used to traverse windows array */
size_t sz; /* size needed for type bitmap rdf */
uint8_t* data = NULL; /* rdf data */
uint8_t* dptr; /* used to itraverse rdf data */
ldns_rdf* rdf; /* bitmap rdf to return */
if (nsec_type != LDNS_RR_TYPE_NSEC &&
nsec_type != LDNS_RR_TYPE_NSEC3) {
return NULL;
}
memset(windows, 0, sizeof(int)*256);
memset(windowpresent, 0, 256);
/* Which other windows need to be in the bitmap rdf?
*/
for (d = rr_type_list; d < rr_type_list + size; d++) {
window = *d >> 8;
subtype = *d & 0xff;
windowpresent[window] = 1;
if (windows[window] < (int)subtype) {
windows[window] = (int)subtype;
}
}
/* How much space do we need in the rdf for those windows?
*/
sz = 0;
for (i = 0; i < 256; i++) {
if (windowpresent[i]) {
sz += windows[i] / 8 + 3;
}
}
if (sz > 0) {
/* Format rdf data according RFC3845 Section 2.1.2 (see above)
*/
dptr = data = LDNS_CALLOC(uint8_t, sz);
if (!data) {
return NULL;
}
for (i = 0; i < 256; i++) {
if (windowpresent[i]) {
*dptr++ = (uint8_t)i;
*dptr++ = (uint8_t)(windows[i] / 8 + 1);
/* Now let windows[i] index the bitmap
* within data
*/
windows[i] = (int)(dptr - data);
dptr += dptr[-1];
}
}
}
/* Set the bits?
*/
for (d = rr_type_list; d < rr_type_list + size; d++) {
subtype = *d & 0xff;
data[windows[*d >> 8] + subtype/8] |= (0x80 >> (subtype % 8));
}
/* Allocate and return rdf structure for the data
*/
rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data);
if (!rdf) {
LDNS_FREE(data);
return NULL;
}
return rdf;
}
int
ldns_dnssec_rrsets_contains_type(const ldns_dnssec_rrsets *rrsets,
ldns_rr_type type)
{
const ldns_dnssec_rrsets *cur_rrset = rrsets;
while (cur_rrset) {
if (cur_rrset->type == type) {
return 1;
}
cur_rrset = cur_rrset->next;
}
return 0;
}
ldns_rr *
ldns_dnssec_create_nsec(const ldns_dnssec_name *from,
const ldns_dnssec_name *to,
ldns_rr_type nsec_type)
{
ldns_rr *nsec_rr;
ldns_rr_type types[65536];
size_t type_count = 0;
ldns_dnssec_rrsets *cur_rrsets;
int on_delegation_point;
if (!from || !to || (nsec_type != LDNS_RR_TYPE_NSEC)) {
return NULL;
}
nsec_rr = ldns_rr_new();
ldns_rr_set_type(nsec_rr, nsec_type);
ldns_rr_set_owner(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(from)));
ldns_rr_push_rdf(nsec_rr, ldns_rdf_clone(ldns_dnssec_name_name(to)));
on_delegation_point = ldns_dnssec_rrsets_contains_type(
from->rrsets, LDNS_RR_TYPE_NS)
&& !ldns_dnssec_rrsets_contains_type(
from->rrsets, LDNS_RR_TYPE_SOA);
cur_rrsets = from->rrsets;
while (cur_rrsets) {
/* Do not include non-authoritative rrsets on the delegation point
* in the type bitmap */
if ((on_delegation_point && (
cur_rrsets->type == LDNS_RR_TYPE_NS
|| cur_rrsets->type == LDNS_RR_TYPE_DS))
|| (!on_delegation_point &&
cur_rrsets->type != LDNS_RR_TYPE_RRSIG
&& cur_rrsets->type != LDNS_RR_TYPE_NSEC)) {
types[type_count] = cur_rrsets->type;
type_count++;
}
cur_rrsets = cur_rrsets->next;
}
types[type_count] = LDNS_RR_TYPE_RRSIG;
type_count++;
types[type_count] = LDNS_RR_TYPE_NSEC;
type_count++;
ldns_rr_push_rdf(nsec_rr, ldns_dnssec_create_nsec_bitmap(types,
type_count,
nsec_type));
return nsec_rr;
}
ldns_rr *
ldns_dnssec_create_nsec3(const ldns_dnssec_name *from,
const ldns_dnssec_name *to,
const ldns_rdf *zone_name,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
const uint8_t *salt)
{
ldns_rr *nsec_rr;
ldns_rr_type types[65536];
size_t type_count = 0;
ldns_dnssec_rrsets *cur_rrsets;
ldns_status status;
int on_delegation_point;
if (!from) {
return NULL;
}
nsec_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3);
ldns_rr_set_owner(nsec_rr,
ldns_nsec3_hash_name(ldns_dnssec_name_name(from),
algorithm,
iterations,
salt_length,
salt));
status = ldns_dname_cat(ldns_rr_owner(nsec_rr), zone_name);
if(status != LDNS_STATUS_OK) {
ldns_rr_free(nsec_rr);
return NULL;
}
ldns_nsec3_add_param_rdfs(nsec_rr,
algorithm,
flags,
iterations,
salt_length,
salt);
on_delegation_point = ldns_dnssec_rrsets_contains_type(
from->rrsets, LDNS_RR_TYPE_NS)
&& !ldns_dnssec_rrsets_contains_type(
from->rrsets, LDNS_RR_TYPE_SOA);
cur_rrsets = from->rrsets;
while (cur_rrsets) {
/* Do not include non-authoritative rrsets on the delegation point
* in the type bitmap. Potentionally not skipping insecure
* delegation should have been done earlier, in function
* ldns_dnssec_zone_create_nsec3s, or even earlier in:
* ldns_dnssec_zone_sign_nsec3_flg .
*/
if ((on_delegation_point && (
cur_rrsets->type == LDNS_RR_TYPE_NS
|| cur_rrsets->type == LDNS_RR_TYPE_DS))
|| (!on_delegation_point &&
cur_rrsets->type != LDNS_RR_TYPE_RRSIG)) {
types[type_count] = cur_rrsets->type;
type_count++;
}
cur_rrsets = cur_rrsets->next;
}
/* always add rrsig type if this is not an unsigned
* delegation
*/
if (type_count > 0 &&
!(type_count == 1 && types[0] == LDNS_RR_TYPE_NS)) {
types[type_count] = LDNS_RR_TYPE_RRSIG;
type_count++;
}
/* leave next rdata empty if they weren't precomputed yet */
if (to && to->hashed_name) {
(void) ldns_rr_set_rdf(nsec_rr,
ldns_rdf_clone(to->hashed_name),
4);
} else {
(void) ldns_rr_set_rdf(nsec_rr, NULL, 4);
}
ldns_rr_push_rdf(nsec_rr,
ldns_dnssec_create_nsec_bitmap(types,
type_count,
LDNS_RR_TYPE_NSEC3));
return nsec_rr;
}
ldns_rr *
ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs)
{
/* we do not do any check here - garbage in, garbage out */
/* the the start and end names - get the type from the
* before rrlist */
/* inefficient, just give it a name, a next name, and a list of rrs */
/* we make 1 big uberbitmap first, then windows */
/* todo: make something more efficient :) */
uint16_t i;
ldns_rr *i_rr;
uint16_t i_type;
ldns_rr *nsec = NULL;
ldns_rr_type i_type_list[65536];
size_t type_count = 0;
nsec = ldns_rr_new();
ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC);
ldns_rr_set_owner(nsec, ldns_rdf_clone(cur_owner));
ldns_rr_push_rdf(nsec, ldns_rdf_clone(next_owner));
for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
i_rr = ldns_rr_list_rr(rrs, i);
if (ldns_rdf_compare(cur_owner,
ldns_rr_owner(i_rr)) == 0) {
i_type = ldns_rr_get_type(i_rr);
if (i_type != LDNS_RR_TYPE_RRSIG && i_type != LDNS_RR_TYPE_NSEC) {
if (type_count == 0 || i_type_list[type_count-1] != i_type) {
i_type_list[type_count] = i_type;
type_count++;
}
}
}
}
i_type_list[type_count] = LDNS_RR_TYPE_RRSIG;
type_count++;
i_type_list[type_count] = LDNS_RR_TYPE_NSEC;
type_count++;
ldns_rr_push_rdf(nsec,
ldns_dnssec_create_nsec_bitmap(i_type_list,
type_count, LDNS_RR_TYPE_NSEC));
return nsec;
}
ldns_rdf *
ldns_nsec3_hash_name(const ldns_rdf *name,
uint8_t algorithm,
uint16_t iterations,
uint8_t salt_length,
const uint8_t *salt)
{
size_t hashed_owner_str_len;
ldns_rdf *cann;
ldns_rdf *hashed_owner;
unsigned char *hashed_owner_str;
char *hashed_owner_b32;
size_t hashed_owner_b32_len;
uint32_t cur_it;
/* define to contain the largest possible hash, which is
* sha1 at the moment */
unsigned char hash[LDNS_SHA1_DIGEST_LENGTH];
ldns_status status;
/* TODO: mnemonic list for hash algs SHA-1, default to 1 now (sha1) */
if (algorithm != LDNS_SHA1) {
return NULL;
}
/* prepare the owner name according to the draft section bla */
cann = ldns_rdf_clone(name);
if(!cann) {
#ifdef STDERR_MSGS
fprintf(stderr, "Memory error\n");
#endif
return NULL;
}
ldns_dname2canonical(cann);
hashed_owner_str_len = salt_length + ldns_rdf_size(cann);
hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len);
if(!hashed_owner_str) {
ldns_rdf_deep_free(cann);
return NULL;
}
memcpy(hashed_owner_str, ldns_rdf_data(cann), ldns_rdf_size(cann));
memcpy(hashed_owner_str + ldns_rdf_size(cann), salt, salt_length);
ldns_rdf_deep_free(cann);
for (cur_it = iterations + 1; cur_it > 0; cur_it--) {
(void) ldns_sha1((unsigned char *) hashed_owner_str,
(unsigned int) hashed_owner_str_len, hash);
LDNS_FREE(hashed_owner_str);
hashed_owner_str_len = salt_length + LDNS_SHA1_DIGEST_LENGTH;
hashed_owner_str = LDNS_XMALLOC(unsigned char, hashed_owner_str_len);
if (!hashed_owner_str) {
return NULL;
}
memcpy(hashed_owner_str, hash, LDNS_SHA1_DIGEST_LENGTH);
memcpy(hashed_owner_str + LDNS_SHA1_DIGEST_LENGTH, salt, salt_length);
hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH + salt_length;
}
LDNS_FREE(hashed_owner_str);
hashed_owner_str = hash;
hashed_owner_str_len = LDNS_SHA1_DIGEST_LENGTH;
hashed_owner_b32 = LDNS_XMALLOC(char,
ldns_b32_ntop_calculate_size(hashed_owner_str_len) + 1);
if(!hashed_owner_b32) {
return NULL;
}
hashed_owner_b32_len = (size_t) ldns_b32_ntop_extended_hex(
(uint8_t *) hashed_owner_str,
hashed_owner_str_len,
hashed_owner_b32,
ldns_b32_ntop_calculate_size(hashed_owner_str_len)+1);
if (hashed_owner_b32_len < 1) {
#ifdef STDERR_MSGS
fprintf(stderr, "Error in base32 extended hex encoding ");
fprintf(stderr, "of hashed owner name (name: ");
ldns_rdf_print(stderr, name);
fprintf(stderr, ", return code: %u)\n",
(unsigned int) hashed_owner_b32_len);
#endif
LDNS_FREE(hashed_owner_b32);
return NULL;
}
hashed_owner_b32[hashed_owner_b32_len] = '\0';
status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32);
if (status != LDNS_STATUS_OK) {
#ifdef STDERR_MSGS
fprintf(stderr, "Error creating rdf from %s\n", hashed_owner_b32);
#endif
LDNS_FREE(hashed_owner_b32);
return NULL;
}
LDNS_FREE(hashed_owner_b32);
return hashed_owner;
}
void
ldns_nsec3_add_param_rdfs(ldns_rr *rr,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
const uint8_t *salt)
{
ldns_rdf *salt_rdf = NULL;
uint8_t *salt_data = NULL;
ldns_rdf *old;
old = ldns_rr_set_rdf(rr,
ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
1, (void*)&algorithm),
0);
if (old) ldns_rdf_deep_free(old);
old = ldns_rr_set_rdf(rr,
ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8,
1, (void*)&flags),
1);
if (old) ldns_rdf_deep_free(old);
old = ldns_rr_set_rdf(rr,
ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
iterations),
2);
if (old) ldns_rdf_deep_free(old);
salt_data = LDNS_XMALLOC(uint8_t, salt_length + 1);
if(!salt_data) {
/* no way to return error */
return;
}
salt_data[0] = salt_length;
memcpy(salt_data + 1, salt, salt_length);
salt_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT,
salt_length + 1,
salt_data);
if(!salt_rdf) {
LDNS_FREE(salt_data);
/* no way to return error */
return;
}
old = ldns_rr_set_rdf(rr, salt_rdf, 3);
if (old) ldns_rdf_deep_free(old);
LDNS_FREE(salt_data);
}
static int
rr_list_delegation_only(const ldns_rdf *origin, const ldns_rr_list *rr_list)
{
size_t i;
ldns_rr *cur_rr;
if (!origin || !rr_list) return 0;
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
cur_rr = ldns_rr_list_rr(rr_list, i);
if (ldns_dname_compare(ldns_rr_owner(cur_rr), origin) == 0) {
return 0;
}
if (ldns_rr_get_type(cur_rr) != LDNS_RR_TYPE_NS) {
return 0;
}
}
return 1;
}
/* this will NOT return the NSEC3 completed, you will have to run the
finalize function on the rrlist later! */
ldns_rr *
ldns_create_nsec3(const ldns_rdf *cur_owner,
const ldns_rdf *cur_zone,
const ldns_rr_list *rrs,
uint8_t algorithm,
uint8_t flags,
uint16_t iterations,
uint8_t salt_length,
const uint8_t *salt,
bool emptynonterminal)
{
size_t i;
ldns_rr *i_rr;
uint16_t i_type;
ldns_rr *nsec = NULL;
ldns_rdf *hashed_owner = NULL;
ldns_status status;
ldns_rr_type i_type_list[1024];
size_t type_count = 0;
hashed_owner = ldns_nsec3_hash_name(cur_owner,
algorithm,
iterations,
salt_length,
salt);
status = ldns_dname_cat(hashed_owner, cur_zone);
if(status != LDNS_STATUS_OK) {
ldns_rdf_deep_free(hashed_owner);
return NULL;
}
nsec = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3);
if(!nsec) {
ldns_rdf_deep_free(hashed_owner);
return NULL;
}
ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC3);
ldns_rr_set_owner(nsec, hashed_owner);
ldns_nsec3_add_param_rdfs(nsec,
algorithm,
flags,
iterations,
salt_length,
salt);
(void) ldns_rr_set_rdf(nsec, NULL, 4);
for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
i_rr = ldns_rr_list_rr(rrs, i);
if (ldns_rdf_compare(cur_owner,
ldns_rr_owner(i_rr)) == 0) {
i_type = ldns_rr_get_type(i_rr);
if (type_count == 0 || i_type_list[type_count-1] != i_type) {
i_type_list[type_count] = i_type;
type_count++;
}
}
}
/* add RRSIG anyway, but only if this is not an ENT or
* an unsigned delegation */
if (!emptynonterminal && !rr_list_delegation_only(cur_zone, rrs)) {
i_type_list[type_count] = LDNS_RR_TYPE_RRSIG;
type_count++;
}
/* and SOA if owner == zone */
if (ldns_dname_compare(cur_zone, cur_owner) == 0) {
i_type_list[type_count] = LDNS_RR_TYPE_SOA;
type_count++;
}
ldns_rr_push_rdf(nsec,
ldns_dnssec_create_nsec_bitmap(i_type_list,
type_count, LDNS_RR_TYPE_NSEC3));
return nsec;
}
uint8_t
ldns_nsec3_algorithm(const ldns_rr *nsec3_rr)
{
if (nsec3_rr &&
(ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
&& (ldns_rr_rdf(nsec3_rr, 0) != NULL)
&& ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 0)) > 0) {
return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 0));
}
return 0;
}
uint8_t
ldns_nsec3_flags(const ldns_rr *nsec3_rr)
{
if (nsec3_rr &&
(ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
&& (ldns_rr_rdf(nsec3_rr, 1) != NULL)
&& ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 1)) > 0) {
return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 1));
}
return 0;
}
bool
ldns_nsec3_optout(const ldns_rr *nsec3_rr)
{
return (ldns_nsec3_flags(nsec3_rr) & LDNS_NSEC3_VARS_OPTOUT_MASK);
}
uint16_t
ldns_nsec3_iterations(const ldns_rr *nsec3_rr)
{
if (nsec3_rr &&
(ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
&& (ldns_rr_rdf(nsec3_rr, 2) != NULL)
&& ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 2)) > 0) {
return ldns_rdf2native_int16(ldns_rr_rdf(nsec3_rr, 2));
}
return 0;
}
ldns_rdf *
ldns_nsec3_salt(const ldns_rr *nsec3_rr)
{
if (nsec3_rr &&
(ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 ||
ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3PARAM)
) {
return ldns_rr_rdf(nsec3_rr, 3);
}
return NULL;
}
uint8_t
ldns_nsec3_salt_length(const ldns_rr *nsec3_rr)
{
ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
return (uint8_t) ldns_rdf_data(salt_rdf)[0];
}
return 0;
}
/* allocs data, free with LDNS_FREE() */
uint8_t *
ldns_nsec3_salt_data(const ldns_rr *nsec3_rr)
{
uint8_t salt_length;
uint8_t *salt;
ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
salt_length = ldns_rdf_data(salt_rdf)[0];
salt = LDNS_XMALLOC(uint8_t, salt_length);
if(!salt) return NULL;
memcpy(salt, &ldns_rdf_data(salt_rdf)[1], salt_length);
return salt;
}
return NULL;
}
ldns_rdf *
ldns_nsec3_next_owner(const ldns_rr *nsec3_rr)
{
if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
return NULL;
} else {
return ldns_rr_rdf(nsec3_rr, 4);
}
}
ldns_rdf *
ldns_nsec3_bitmap(const ldns_rr *nsec3_rr)
{
if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
return NULL;
} else {
return ldns_rr_rdf(nsec3_rr, 5);
}
}
ldns_rdf *
ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, const ldns_rdf *name)
{
uint8_t algorithm;
uint16_t iterations;
uint8_t salt_length;
uint8_t *salt = 0;
ldns_rdf *hashed_owner;
algorithm = ldns_nsec3_algorithm(nsec);
salt_length = ldns_nsec3_salt_length(nsec);
salt = ldns_nsec3_salt_data(nsec);
iterations = ldns_nsec3_iterations(nsec);
hashed_owner = ldns_nsec3_hash_name(name,
algorithm,
iterations,
salt_length,
salt);
LDNS_FREE(salt);
return hashed_owner;
}
bool
ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type)
{
uint8_t* dptr;
uint8_t* dend;
/* From RFC3845 Section 2.1.2:
*
* "The RR type space is split into 256 window blocks, each re-
* presenting the low-order 8 bits of the 16-bit RR type space."
*/
uint8_t window = type >> 8;
uint8_t subtype = type & 0xff;
if (! bitmap) {
return false;
}
assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP);
dptr = ldns_rdf_data(bitmap);
dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap);
/* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) +
* dptr[0] dptr[1] dptr[2:]
*/
while (dptr < dend && dptr[0] <= window) {
if (dptr[0] == window && subtype / 8 < dptr[1] &&
dptr + dptr[1] + 2 <= dend) {
return dptr[2 + subtype / 8] & (0x80 >> (subtype % 8));
}
dptr += dptr[1] + 2; /* next window */
}
return false;
}
ldns_status
ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type)
{
uint8_t* dptr;
uint8_t* dend;
/* From RFC3845 Section 2.1.2:
*
* "The RR type space is split into 256 window blocks, each re-
* presenting the low-order 8 bits of the 16-bit RR type space."
*/
uint8_t window = type >> 8;
uint8_t subtype = type & 0xff;
if (! bitmap) {
return false;
}
assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP);
dptr = ldns_rdf_data(bitmap);
dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap);
/* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) +
* dptr[0] dptr[1] dptr[2:]
*/
while (dptr < dend && dptr[0] <= window) {
if (dptr[0] == window && subtype / 8 < dptr[1] &&
dptr + dptr[1] + 2 <= dend) {
dptr[2 + subtype / 8] |= (0x80 >> (subtype % 8));
return LDNS_STATUS_OK;
}
dptr += dptr[1] + 2; /* next window */
}
return LDNS_STATUS_TYPE_NOT_IN_BITMAP;
}
ldns_status
ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type)
{
uint8_t* dptr;
uint8_t* dend;
/* From RFC3845 Section 2.1.2:
*
* "The RR type space is split into 256 window blocks, each re-
* presenting the low-order 8 bits of the 16-bit RR type space."
*/
uint8_t window = type >> 8;
uint8_t subtype = type & 0xff;
if (! bitmap) {
return false;
}
assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP);
dptr = ldns_rdf_data(bitmap);
dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap);
/* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) +
* dptr[0] dptr[1] dptr[2:]
*/
while (dptr < dend && dptr[0] <= window) {
if (dptr[0] == window && subtype / 8 < dptr[1] &&
dptr + dptr[1] + 2 <= dend) {
dptr[2 + subtype / 8] &= ~(0x80 >> (subtype % 8));
return LDNS_STATUS_OK;
}
dptr += dptr[1] + 2; /* next window */
}
return LDNS_STATUS_TYPE_NOT_IN_BITMAP;
}
bool
ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name)
{
ldns_rdf *nsec_owner = ldns_rr_owner(nsec);
ldns_rdf *hash_next;
char *next_hash_str;
ldns_rdf *nsec_next = NULL;
ldns_status status;
ldns_rdf *chopped_dname;
bool result;
if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) {
if (ldns_rr_rdf(nsec, 0) != NULL) {
nsec_next = ldns_rdf_clone(ldns_rr_rdf(nsec, 0));
} else {
return false;
}
} else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) {
hash_next = ldns_nsec3_next_owner(nsec);
next_hash_str = ldns_rdf2str(hash_next);
nsec_next = ldns_dname_new_frm_str(next_hash_str);
LDNS_FREE(next_hash_str);
chopped_dname = ldns_dname_left_chop(nsec_owner);
status = ldns_dname_cat(nsec_next, chopped_dname);
ldns_rdf_deep_free(chopped_dname);
if (status != LDNS_STATUS_OK) {
printf("error catting: %s\n", ldns_get_errorstr_by_id(status));
}
} else {
ldns_rdf_deep_free(nsec_next);
return false;
}
/* in the case of the last nsec */
if(ldns_dname_compare(nsec_owner, nsec_next) > 0) {
result = (ldns_dname_compare(nsec_owner, name) <= 0 ||
ldns_dname_compare(name, nsec_next) < 0);
} else if(ldns_dname_compare(nsec_owner, nsec_next) < 0) {
result = (ldns_dname_compare(nsec_owner, name) <= 0 &&
ldns_dname_compare(name, nsec_next) < 0);
} else {
result = true;
}
ldns_rdf_deep_free(nsec_next);
return result;
}
#ifdef HAVE_SSL
/* sig may be null - if so look in the packet */
ldns_status
ldns_pkt_verify_time(const ldns_pkt *p, ldns_rr_type t, const ldns_rdf *o,
const ldns_rr_list *k, const ldns_rr_list *s,
time_t check_time, ldns_rr_list *good_keys)
{
ldns_rr_list *rrset;
ldns_rr_list *sigs;
ldns_rr_list *sigs_covered;
ldns_rdf *rdf_t;
ldns_rr_type t_netorder;
if (!k) {
return LDNS_STATUS_ERR;
/* return LDNS_STATUS_CRYPTO_NO_DNSKEY; */
}
if (t == LDNS_RR_TYPE_RRSIG) {
/* we don't have RRSIG(RRSIG) (yet? ;-) ) */
return LDNS_STATUS_ERR;
}
if (s) {
/* if s is not NULL, the sigs are given to use */
sigs = (ldns_rr_list *)s;
} else {
/* otherwise get them from the packet */
sigs = ldns_pkt_rr_list_by_name_and_type(p, o,
LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_ANY_NOQUESTION);
if (!sigs) {
/* no sigs */
return LDNS_STATUS_ERR;
/* return LDNS_STATUS_CRYPTO_NO_RRSIG; */
}
}
/* rrsig are subtyped, so now we need to find the correct
* sigs for the type t
*/
t_netorder = htons(t); /* rdf are in network order! */
/* a type identifier is a 16-bit number, so the size is 2 bytes */
rdf_t = ldns_rdf_new(LDNS_RDF_TYPE_TYPE, 2, &t_netorder);
sigs_covered = ldns_rr_list_subtype_by_rdf(sigs, rdf_t, 0);
ldns_rdf_free(rdf_t);
if (! sigs_covered) {
if (! s) {
ldns_rr_list_deep_free(sigs);
}
return LDNS_STATUS_ERR;
}
ldns_rr_list_deep_free(sigs_covered);
rrset = ldns_pkt_rr_list_by_name_and_type(p, o, t,
LDNS_SECTION_ANY_NOQUESTION);
if (!rrset) {
if (! s) {
ldns_rr_list_deep_free(sigs);
}
return LDNS_STATUS_ERR;
}
return ldns_verify_time(rrset, sigs, k, check_time, good_keys);
}
ldns_status
ldns_pkt_verify(const ldns_pkt *p, ldns_rr_type t, const ldns_rdf *o,
const ldns_rr_list *k, const ldns_rr_list *s, ldns_rr_list *good_keys)
{
return ldns_pkt_verify_time(p, t, o, k, s, ldns_time(NULL), good_keys);
}
#endif /* HAVE_SSL */
ldns_status
ldns_dnssec_chain_nsec3_list(ldns_rr_list *nsec3_rrs)
{
size_t i;
char *next_nsec_owner_str;
ldns_rdf *next_nsec_owner_label;
ldns_rdf *next_nsec_rdf;
ldns_status status = LDNS_STATUS_OK;
for (i = 0; i < ldns_rr_list_rr_count(nsec3_rrs); i++) {
if (i == ldns_rr_list_rr_count(nsec3_rrs) - 1) {
next_nsec_owner_label =
ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs,
0)), 0);
next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label);
if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
== '.') {
next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
= '\0';
}
status = ldns_str2rdf_b32_ext(&next_nsec_rdf,
next_nsec_owner_str);
if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i),
next_nsec_rdf, 4)) {
/* todo: error */
}
ldns_rdf_deep_free(next_nsec_owner_label);
LDNS_FREE(next_nsec_owner_str);
} else {
next_nsec_owner_label =
ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs,
i + 1)),
0);
next_nsec_owner_str = ldns_rdf2str(next_nsec_owner_label);
if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
== '.') {
next_nsec_owner_str[strlen(next_nsec_owner_str) - 1]
= '\0';
}
status = ldns_str2rdf_b32_ext(&next_nsec_rdf,
next_nsec_owner_str);
ldns_rdf_deep_free(next_nsec_owner_label);
LDNS_FREE(next_nsec_owner_str);
if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i),
next_nsec_rdf, 4)) {
/* todo: error */
}
}
}
return status;
}
int
qsort_rr_compare_nsec3(const void *a, const void *b)
{
const ldns_rr *rr1 = * (const ldns_rr **) a;
const ldns_rr *rr2 = * (const ldns_rr **) b;
if (rr1 == NULL && rr2 == NULL) {
return 0;
}
if (rr1 == NULL) {
return -1;
}
if (rr2 == NULL) {
return 1;
}
return ldns_rdf_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2));
}
void
ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted)
{
qsort(unsorted->_rrs,
ldns_rr_list_rr_count(unsorted),
sizeof(ldns_rr *),
qsort_rr_compare_nsec3);
}
int
ldns_dnssec_default_add_to_signatures( ATTR_UNUSED(ldns_rr *sig)
, ATTR_UNUSED(void *n)
)
{
return LDNS_SIGNATURE_LEAVE_ADD_NEW;
}
int
ldns_dnssec_default_leave_signatures( ATTR_UNUSED(ldns_rr *sig)
, ATTR_UNUSED(void *n)
)
{
return LDNS_SIGNATURE_LEAVE_NO_ADD;
}
int
ldns_dnssec_default_delete_signatures( ATTR_UNUSED(ldns_rr *sig)
, ATTR_UNUSED(void *n)
)
{
return LDNS_SIGNATURE_REMOVE_NO_ADD;
}
int
ldns_dnssec_default_replace_signatures( ATTR_UNUSED(ldns_rr *sig)
, ATTR_UNUSED(void *n)
)
{
return LDNS_SIGNATURE_REMOVE_ADD_NEW;
}
#ifdef HAVE_SSL
ldns_rdf *
ldns_convert_dsa_rrsig_asn12rdf(const ldns_buffer *sig,
const long sig_len)
{
#ifdef USE_DSA
ldns_rdf *sigdata_rdf;
DSA_SIG *dsasig;
const BIGNUM *R, *S;
unsigned char *dsasig_data = (unsigned char*)ldns_buffer_begin(sig);
size_t byte_offset;
dsasig = d2i_DSA_SIG(NULL,
(const unsigned char **)&dsasig_data,
sig_len);
if (!dsasig) {
DSA_SIG_free(dsasig);
return NULL;
}
dsasig_data = LDNS_XMALLOC(unsigned char, 41);
if(!dsasig_data) {
DSA_SIG_free(dsasig);
return NULL;
}
dsasig_data[0] = 0;
# ifdef HAVE_DSA_SIG_GET0
DSA_SIG_get0(dsasig, &R, &S);
# else
R = dsasig->r;
S = dsasig->s;
# endif
byte_offset = (size_t) (20 - BN_num_bytes(R));
if (byte_offset > 20) {
DSA_SIG_free(dsasig);
LDNS_FREE(dsasig_data);
return NULL;
}
memset(&dsasig_data[1], 0, byte_offset);
BN_bn2bin(R, &dsasig_data[1 + byte_offset]);
byte_offset = (size_t) (20 - BN_num_bytes(S));
if (byte_offset > 20) {
DSA_SIG_free(dsasig);
LDNS_FREE(dsasig_data);
return NULL;
}
memset(&dsasig_data[21], 0, byte_offset);
BN_bn2bin(S, &dsasig_data[21 + byte_offset]);
sigdata_rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, 41, dsasig_data);
if(!sigdata_rdf) {
LDNS_FREE(dsasig_data);
}
DSA_SIG_free(dsasig);
return sigdata_rdf;
#else
(void)sig; (void)sig_len;
return NULL;
#endif
}
ldns_status
ldns_convert_dsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
const ldns_rdf *sig_rdf)
{
#ifdef USE_DSA
/* the EVP api wants the DER encoding of the signature... */
BIGNUM *R, *S;
DSA_SIG *dsasig;
unsigned char *raw_sig = NULL;
int raw_sig_len;
if(ldns_rdf_size(sig_rdf) < 1 + 2*SHA_DIGEST_LENGTH)
return LDNS_STATUS_SYNTAX_RDATA_ERR;
/* extract the R and S field from the sig buffer */
R = BN_new();
if(!R) return LDNS_STATUS_MEM_ERR;
(void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 1,
SHA_DIGEST_LENGTH, R);
S = BN_new();
if(!S) {
BN_free(R);
return LDNS_STATUS_MEM_ERR;
}
(void) BN_bin2bn((unsigned char *) ldns_rdf_data(sig_rdf) + 21,
SHA_DIGEST_LENGTH, S);
dsasig = DSA_SIG_new();
if (!dsasig) {
BN_free(R);
BN_free(S);
return LDNS_STATUS_MEM_ERR;
}
# ifdef HAVE_DSA_SIG_SET0
if (! DSA_SIG_set0(dsasig, R, S))
return LDNS_STATUS_SSL_ERR;
# else
dsasig->r = R;
dsasig->s = S;
# endif
raw_sig_len = i2d_DSA_SIG(dsasig, &raw_sig);
if (raw_sig_len < 0) {
DSA_SIG_free(dsasig);
free(raw_sig);
return LDNS_STATUS_SSL_ERR;
}
if (ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) {
ldns_buffer_write(target_buffer, raw_sig, (size_t)raw_sig_len);
}
DSA_SIG_free(dsasig);
free(raw_sig);
return ldns_buffer_status(target_buffer);
#else
(void)target_buffer; (void)sig_rdf;
return LDNS_STATUS_CRYPTO_ALGO_NOT_IMPL;
#endif
}
#ifdef USE_ECDSA
#ifndef S_SPLINT_S
ldns_rdf *
ldns_convert_ecdsa_rrsig_asn1len2rdf(const ldns_buffer *sig,
const long sig_len, int num_bytes)
{
ECDSA_SIG* ecdsa_sig;
const BIGNUM *r, *s;
unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
ldns_rdf* rdf;
ecdsa_sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&data, sig_len);
if(!ecdsa_sig) return NULL;
#ifdef HAVE_ECDSA_SIG_GET0
ECDSA_SIG_get0(ecdsa_sig, &r, &s);
#else
r = ecdsa_sig->r;
s = ecdsa_sig->s;
#endif
/* "r | s". */
if(BN_num_bytes(r) > num_bytes ||
BN_num_bytes(s) > num_bytes) {
ECDSA_SIG_free(ecdsa_sig);
return NULL; /* numbers too big for passed curve size */
}
data = LDNS_XMALLOC(unsigned char, num_bytes*2);
if(!data) {
ECDSA_SIG_free(ecdsa_sig);
return NULL;
}
/* write the bignums (in big-endian) a little offset if the BN code
* wants to write a shorter number of bytes, with zeroes prefixed */
memset(data, 0, num_bytes*2);
BN_bn2bin(r, data+num_bytes-BN_num_bytes(r));
BN_bn2bin(s, data+num_bytes*2-BN_num_bytes(s));
rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, (size_t)(num_bytes*2), data);
ECDSA_SIG_free(ecdsa_sig);
return rdf;
}
ldns_status
ldns_convert_ecdsa_rrsig_rdf2asn1(ldns_buffer *target_buffer,
const ldns_rdf *sig_rdf)
{
/* convert from two BIGNUMs in the rdata buffer, to ASN notation.
* ASN preable: 30440220 <R 32bytefor256> 0220 <S 32bytefor256>
* the '20' is the length of that field (=bnsize).
* the '44' is the total remaining length.
* if negative, start with leading zero.
* if starts with 00s, remove them from the number.
*/
uint8_t pre[] = {0x30, 0x44, 0x02, 0x20};
int pre_len = 4;
uint8_t mid[] = {0x02, 0x20};
int mid_len = 2;
int raw_sig_len, r_high, s_high, r_rem=0, s_rem=0;
long bnsize = (long)ldns_rdf_size(sig_rdf) / 2;
uint8_t* d = ldns_rdf_data(sig_rdf);
/* if too short, or not even length, do not bother */
if(bnsize < 16 || (size_t)bnsize*2 != ldns_rdf_size(sig_rdf))
return LDNS_STATUS_ERR;
/* strip leading zeroes from r (but not last one) */
while(r_rem < bnsize-1 && d[r_rem] == 0)
r_rem++;
/* strip leading zeroes from s (but not last one) */
while(s_rem < bnsize-1 && d[bnsize+s_rem] == 0)
s_rem++;
r_high = ((d[0+r_rem]&0x80)?1:0);
s_high = ((d[bnsize+s_rem]&0x80)?1:0);
raw_sig_len = pre_len + r_high + bnsize - r_rem + mid_len +
s_high + bnsize - s_rem;
if(ldns_buffer_reserve(target_buffer, (size_t) raw_sig_len)) {
ldns_buffer_write_u8(target_buffer, pre[0]);
ldns_buffer_write_u8(target_buffer, raw_sig_len-2);
ldns_buffer_write_u8(target_buffer, pre[2]);
ldns_buffer_write_u8(target_buffer, bnsize + r_high - r_rem);
if(r_high)
ldns_buffer_write_u8(target_buffer, 0);
ldns_buffer_write(target_buffer, d+r_rem, bnsize-r_rem);
ldns_buffer_write(target_buffer, mid, mid_len-1);
ldns_buffer_write_u8(target_buffer, bnsize + s_high - s_rem);
if(s_high)
ldns_buffer_write_u8(target_buffer, 0);
ldns_buffer_write(target_buffer, d+bnsize+s_rem, bnsize-s_rem);
}
return ldns_buffer_status(target_buffer);
}
#endif /* S_SPLINT_S */
#endif /* USE_ECDSA */
#if defined(USE_ED25519) || defined(USE_ED448)
/* debug printout routine */
static void print_hex(const char* str, uint8_t* d, int len)
{
const char hex[] = "0123456789abcdef";
int i;
printf("%s [len=%d]: ", str, len);
for(i=0; i<len; i++) {
int x = (d[i]&0xf0)>>4;
int y = (d[i]&0x0f);
printf("%c%c", hex[x], hex[y]);
}
printf("\n");
}
#endif
#ifdef USE_ED25519
ldns_rdf *
ldns_convert_ed25519_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len)
{
unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
ldns_rdf* rdf = NULL;
/* TODO when Openssl supports signing and you can test this */
print_hex("sig in ASN", data, sig_len);
return rdf;
}
ldns_status
ldns_convert_ed25519_rrsig_rdf2asn1(ldns_buffer *target_buffer,
const ldns_rdf *sig_rdf)
{
/* TODO when Openssl supports signing and you can test this. */
/* convert sig_buf into ASN1 into the target_buffer */
print_hex("sig raw", ldns_rdf_data(sig_rdf), ldns_rdf_size(sig_rdf));
return ldns_buffer_status(target_buffer);
}
#endif /* USE_ED25519 */
#ifdef USE_ED448
ldns_rdf *
ldns_convert_ed448_rrsig_asn12rdf(const ldns_buffer *sig, long sig_len)
{
unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
ldns_rdf* rdf = NULL;
/* TODO when Openssl supports signing and you can test this */
print_hex("sig in ASN", data, sig_len);
return rdf;
}
ldns_status
ldns_convert_ed448_rrsig_rdf2asn1(ldns_buffer *target_buffer,
const ldns_rdf *sig_rdf)
{
/* TODO when Openssl supports signing and you can test this. */
/* convert sig_buf into ASN1 into the target_buffer */
print_hex("sig raw", ldns_rdf_data(sig_rdf), ldns_rdf_size(sig_rdf));
return ldns_buffer_status(target_buffer);
}
#endif /* USE_ED448 */
#endif /* HAVE_SSL */