diff --git a/src/rr-dict.c b/src/rr-dict.c index d61bec3e..fc06f59f 100644 --- a/src/rr-dict.c +++ b/src/rr-dict.c @@ -37,6 +37,7 @@ #include "rr-dict.h" #include "types-internal.h" #include "context.h" +#include "dict.h" #define ALEN(a) (sizeof(a)/sizeof(a[0])) @@ -869,15 +870,157 @@ priv_getdns_create_reply_question_dict( return r; } +static getdns_return_t priv_getdns_construct_wire_rdata_from_rdata( + struct getdns_dict *rdata, uint32_t rr_type, + uint8_t **wire, size_t *wire_size) +{ + getdns_return_t r = GETDNS_RETURN_GOOD; + const ldns_rr_descriptor *rr_descript; + const struct rr_def *def; + size_t i, size; + struct getdns_bindata *bindata; + uint32_t value; + uint8_t *ptr; + + assert(rdata); + assert(wire); + assert(wire_size); + + def = rr_def_lookup(rr_type); + rr_descript = ldns_rr_descript(rr_type); + + /* First calculate needed size */ + size = 0; + for (i = 0; i < def->n_rdata_fields && r == GETDNS_RETURN_GOOD; i++) { + switch (def->rdata[i].type) { + case t_bindata: r = getdns_dict_get_bindata(rdata, + def->rdata[i].name, &bindata); + if (r) + break; + size += bindata->size; + break; + case t_int : switch (ldns_rr_descriptor_field_type( + rr_descript, i)) { + + case LDNS_RDF_TYPE_CLASS: + case LDNS_RDF_TYPE_ALG : + case LDNS_RDF_TYPE_INT8 : size += 1; + break; + case LDNS_RDF_TYPE_TYPE : + case LDNS_RDF_TYPE_CERT_ALG: + case LDNS_RDF_TYPE_INT16: size += 2; + break; + case LDNS_RDF_TYPE_TIME : + case LDNS_RDF_TYPE_PERIOD: + case LDNS_RDF_TYPE_INT32: size += 4; + break; + default: r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + break; + default : r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + } + *wire_size = size + 2; + *wire = ptr = GETDNS_XMALLOC(rdata->mf, uint8_t, size + 2); + if (! ptr) + return GETDNS_RETURN_MEMORY_ERROR; + + ptr[0] = (uint8_t) (size >> 8) & 0xff; + ptr[1] = (uint8_t) size & 0xff; + ptr += 2; + for (i = 0; i < def->n_rdata_fields && r == GETDNS_RETURN_GOOD; i++) { + switch (def->rdata[i].type) { + case t_bindata: r = getdns_dict_get_bindata(rdata, + def->rdata[i].name, &bindata); + if (r) + break; + (void) memcpy(ptr, bindata->data, + bindata->size); + ptr += bindata->size; + break; + case t_int : r = getdns_dict_get_int(rdata, + def->rdata[i].name, &value); + if (r) + break; + + switch (ldns_rr_descriptor_field_type( + rr_descript, i)) { + + case LDNS_RDF_TYPE_CLASS: + case LDNS_RDF_TYPE_ALG : + case LDNS_RDF_TYPE_INT8 : ptr[0] = (uint8_t) + value & 0xff; + ptr += 1; + break; + case LDNS_RDF_TYPE_TYPE : + case LDNS_RDF_TYPE_CERT_ALG: + case LDNS_RDF_TYPE_INT16: ptr[0] = (uint8_t) + (value>>8)&0xff; + ptr[1] = (uint8_t) + value & 0xff; + ptr += 2; + break; + case LDNS_RDF_TYPE_TIME : + case LDNS_RDF_TYPE_PERIOD: + case LDNS_RDF_TYPE_INT32: ptr[0] = (uint8_t) + (value>>24)&0xff; + ptr[1] = (uint8_t) + (value>>16)&0xff; + ptr[2] = (uint8_t) + (value>>8)&0xff; + ptr[3] = (uint8_t) + value & 0xff; + ptr += 4; + break; + default: r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + break; + default : r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + } + if (r) + GETDNS_FREE(rdata->mf, ptr); + return r; +} + +static getdns_return_t +priv_getdns_dict_get_raw_rdata(struct getdns_dict *rdata, + uint8_t **wire, size_t *wire_size) +{ + getdns_return_t r; + struct getdns_bindata *bindata; + + if ((r = getdns_dict_get_bindata(rdata, "rdata_raw", &bindata))) + return r; + + *wire_size = bindata->size + 2; + *wire = GETDNS_XMALLOC(rdata->mf, uint8_t, *wire_size); + if (! *wire) + return GETDNS_RETURN_MEMORY_ERROR; + + (*wire)[0] = (uint8_t) (bindata->size >> 8) & 0xff; + (*wire)[1] = (uint8_t) bindata->size & 0xff; + + (void) memcpy(*wire + 2, bindata->data, bindata->size); + return GETDNS_RETURN_GOOD; +} + getdns_return_t priv_getdns_create_rr_from_dict(struct getdns_dict *rr_dict, ldns_rr **rr) { getdns_return_t r = GETDNS_RETURN_GOOD; - struct getdns_bindata *name, *rdata_raw; + struct getdns_bindata *name; struct getdns_dict *rdata; uint32_t rr_type; ldns_rdf *owner; ldns_status s; + size_t pos; + uint8_t *wire; + size_t wire_size; assert(rr_dict); assert(rr); @@ -906,14 +1049,35 @@ priv_getdns_create_rr_from_dict(struct getdns_dict *rr_dict, ldns_rr **rr) if (r != GETDNS_RETURN_GOOD) break; - r = getdns_dict_get_bindata(rdata, "rdata_raw", &rdata_raw); + //r = getdns_dict_get_bindata(rdata, "rdata_raw", &rdata_raw); + r = priv_getdns_dict_get_raw_rdata(rdata, &wire, &wire_size); + if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME) { + r = priv_getdns_construct_wire_rdata_from_rdata( + rdata, rr_type, &wire, &wire_size); + } if (r != GETDNS_RETURN_GOOD) break; - - s = ldns_wire2rdf(*rr, rdata_raw->data, rdata_raw->size, 0); +#if 0 + fprintf(stderr, "wire_size: %d\n", (int)wire_size); + fprintf(stderr, "wire data: "); + for (size_t i = 0; i < wire_size; i++) { + if (i) { + if (i % 24 == 0) + fprintf(stderr, "\n "); + else if (i % 4 == 0) + fprintf(stderr, " "); + } + fprintf(stderr, "%.2x", wire[i]); + } + fprintf(stderr, "\n"); +#endif + pos = 0; + s = ldns_wire2rdf(*rr, wire, wire_size, &pos); + GETDNS_FREE(rr_dict->mf, wire); if (s == LDNS_STATUS_OK) return r; - + fprintf( stderr, "ldns error: %s (pos: %d)\n" + , ldns_get_errorstr_by_id(s), (int)pos); r = GETDNS_RETURN_GENERIC_ERROR; } while (0); ldns_rr_free(*rr); diff --git a/src/test/tests_dnssec.c b/src/test/tests_dnssec.c index f0fe9aae..38edf3c2 100644 --- a/src/test/tests_dnssec.c +++ b/src/test/tests_dnssec.c @@ -46,28 +46,131 @@ #include #include +getdns_return_t create_root_trustanchor_list(struct getdns_list **tas) +{ + static const struct getdns_bindata root_dname = { 1, (uint8_t *) "" }; + static const int root_key_tag = 19036; + static const int root_algorithm = 8; + static const int root_digest_type = 2; + static const struct getdns_bindata root_digest = { 32, (uint8_t *) + "\x49\xaa\xc1\x1d\x7b\x6f\x64\x46\x70\x2e\x54\xa1\x60\x73\x71\x60" + "\x7a\x1a\x41\x85\x52\x00\xfd\x2c\xe1\xcd\xde\x32\xf2\x4e\x8f\xb5" + }; + + getdns_return_t r = GETDNS_RETURN_GOOD; + struct getdns_dict *ta; + struct getdns_dict *rdata; + + if (! tas) + return GETDNS_RETURN_INVALID_PARAMETER; + + ta = getdns_dict_create(); + if (! ta) + return GETDNS_RETURN_MEMORY_ERROR; + do { + r = getdns_dict_set_bindata(ta, "name", + (struct getdns_bindata *)&root_dname); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_int(ta, "type", GETDNS_RRTYPE_DS); + if (r != GETDNS_RETURN_GOOD) + break; + + rdata = getdns_dict_create(); + if (! rdata) { + r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + do { + r = getdns_dict_set_int(rdata, + "key_tag", root_key_tag); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_int(rdata, + "algorithm", root_algorithm); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_int(rdata, + "digest_type", root_digest_type); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_bindata(rdata, + "digest", (struct getdns_bindata *)&root_digest); + if (r != GETDNS_RETURN_GOOD) + break; + + r = getdns_dict_set_dict(ta, "rdata", rdata); + } while(0); + + getdns_dict_destroy(rdata); + if (r != GETDNS_RETURN_GOOD) + break; + + *tas = getdns_list_create(); + if (! *tas) { + r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + r = getdns_list_set_dict(*tas, 0, ta); + if (r == GETDNS_RETURN_GOOD) + return r; + + getdns_list_destroy(*tas); + } while(0); + getdns_dict_destroy(ta); + return r; +} + /* Set up the callback function, which will also do the processing of the results */ void -this_callbackfn(struct getdns_context *this_context, - uint16_t this_callback_type, - struct getdns_dict *this_response, - void *this_userarg, getdns_transaction_t this_transaction_id) +this_callbackfn(struct getdns_context *context, uint16_t callback_type, + struct getdns_dict *response, void *userarg, + getdns_transaction_t transaction_id) { - if (this_callback_type == GETDNS_CALLBACK_COMPLETE) { /* This is a callback with data */ - char *res = getdns_pretty_print_dict(this_response); - fprintf(stdout, "%s\n", res); - free(res); + struct getdns_list *validation_chain; + struct getdns_list *trust_anchors; + getdns_return_t r; - } else if (this_callback_type == GETDNS_CALLBACK_CANCEL) - fprintf(stderr, - "The callback with ID %llu was cancelled. Exiting.", - (unsigned long long)this_transaction_id); - else - fprintf(stderr, - "The callback got a callback_type of %d. Exiting.", - this_callback_type); - getdns_dict_destroy(this_response); - (void) event_base_loopexit((struct event_base *)this_userarg, NULL); + do { + if (callback_type == GETDNS_CALLBACK_CANCEL) { + fprintf(stderr, + "The callback with ID %llu was cancelled.\n", + (long long unsigned int)transaction_id); + break; + } else if (callback_type != GETDNS_CALLBACK_COMPLETE) { + fprintf(stderr, + "The callback got a callback_type of %d.\n", + callback_type); + break; + } + r = getdns_dict_get_list(response, + "validation_chain", &validation_chain); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Could not get \"validation_chain\" from response:" + " %d\n", r); + break; + } + r = create_root_trustanchor_list(&trust_anchors); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Error in creating trust_anchor:" + " %d\n", r); + break; + } + r = getdns_validate_dnssec(NULL, + validation_chain, trust_anchors); + + printf("getdns_validate_dnssec returned: %d\n", r); + + getdns_list_destroy(trust_anchors); + } while (0); + getdns_dict_destroy(response); + (void) event_base_loopexit((struct event_base *)userarg, NULL); } int @@ -83,7 +186,6 @@ main(int argc, char** argv) return (GETDNS_RETURN_GENERIC_ERROR); } getdns_context_set_timeout(this_context, 5000); - struct getdns_dict * this_extensions = getdns_dict_create(); getdns_return_t this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_validation_chain", GETDNS_EXTENSION_TRUE); diff --git a/src/validate_dnssec.c b/src/validate_dnssec.c index 716aaab1..5358c506 100644 --- a/src/validate_dnssec.c +++ b/src/validate_dnssec.c @@ -35,23 +35,71 @@ */ #include +#include +#include "rr-dict.h" /* stuff to make it compile pedantically */ #define UNUSED_PARAM(x) ((void)(x)) +static getdns_return_t +priv_getdns_rr_list_from_list(struct getdns_list *list, ldns_rr_list **rr_list) +{ + getdns_return_t r; + size_t i, l; + struct getdns_dict *rr_dict; + ldns_rr *rr; + + if ((r = getdns_list_get_length(list, &l))) + return r; + + if (! (*rr_list = ldns_rr_list_new())) + return GETDNS_RETURN_MEMORY_ERROR; + + for (i = 0; i < l; i++) { + if ((r = getdns_list_get_dict(list, i, &rr_dict))) + break; + + if ((r = priv_getdns_create_rr_from_dict(rr_dict, &rr))) + break; + + if (! ldns_rr_list_push_rr(*rr_list, rr)) { + ldns_rr_free(rr); + r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + } + if (r) + ldns_rr_list_deep_free(*rr_list); + return r; +} + /* * getdns_validate_dnssec * */ getdns_return_t -getdns_validate_dnssec(struct getdns_bindata * record_to_validate, - struct getdns_list * bundle_of_support_records, - struct getdns_list * trust_anchor_rdatas) +getdns_validate_dnssec(struct getdns_bindata *to_validate, + struct getdns_list *support_records, + struct getdns_list *trust_anchors) { - UNUSED_PARAM(record_to_validate); - UNUSED_PARAM(bundle_of_support_records); - UNUSED_PARAM(trust_anchor_rdatas); - return GETDNS_RETURN_GOOD; + getdns_return_t r; + ldns_rr_list *tas; + ldns_rr_list *chain; + + if ((r = priv_getdns_rr_list_from_list(trust_anchors, &tas))) + return r; + + printf(";; trust anchors:\n"); + ldns_rr_list_print(stdout, tas); + + if ((r = priv_getdns_rr_list_from_list(support_records, &chain))) + return r; + + printf(";; support records:\n"); + ldns_rr_list_print(stdout, chain); + + + return r; } /* getdns_validate_dnssec */ /* validate_dnssec.c */