From 8517d0c00df8aa06705d80b5b2efae0a50e50e44 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Mon, 13 May 2013 15:36:06 +0200 Subject: [PATCH] Initial support for RFC6689, a.k.a. DANE. Note that it initially applies to 1.0.2, and not to HEAD. This is in order to allow development with existing libunbound installations that are dependent on OpenSSL 1.0.x. More details in RT. RT: 3003 --- ssl/dnssec.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 ssl/dnssec.c diff --git a/ssl/dnssec.c b/ssl/dnssec.c new file mode 100644 index 0000000000..f6c26448cd --- /dev/null +++ b/ssl/dnssec.c @@ -0,0 +1,172 @@ +#include + +#include +#include +#include +#include + +#ifndef OPENSSL_NO_LIBUNBOUND +#include + +static struct ub_ctx *ctx = NULL; +static DSO *unbound_dso = NULL; + +static union { + void *p; struct ub_ctx *(*f)(); } + p_ub_ctx_create = {NULL}; + +static union { + void *p; int (*f)(struct ub_ctx *,const char *); } + p_ub_ctx_resolvconf = {NULL}; + +static union { + void *p; int (*f)(struct ub_ctx *,const char *); } + p_ub_ctx_add_ta_file = {NULL}; + +static union { + void *p; void (*f)(struct ub_ctx *); } + p_ub_ctx_delete = {NULL}; + +static union { + void *p; int (*f)(struct ub_ctx *,const char *,int,int,struct ub_result**); } + p_ub_resolve = {NULL}; + +static union { + void *p; void (*f)(struct ub_result*); } + p_ub_resolve_free = {NULL}; + +#if defined(__GNUC__) && __GNUC__>=2 + static void unbound_init(void) __attribute__((constructor)); + static void unbound_fini(void) __attribute__((destructor)); +#endif + +static void unbound_init(void) +{ + DSO *dso; + + if ((dso = DSO_load(NULL, "unbound", NULL, 0)) == NULL) return; + + if ((p_ub_ctx_create.p = DSO_bind_func(dso,"ub_ctx_create")) == NULL || + (p_ub_ctx_resolvconf.p = DSO_bind_func(dso,"ub_ctx_resolvconf")) == NULL || + (p_ub_ctx_add_ta_file.p = DSO_bind_func(dso,"ub_ctx_add_ta_file")) == NULL || + (p_ub_ctx_delete.p = DSO_bind_func(dso,"ub_ctx_delete")) == NULL || + (p_ub_resolve.p = DSO_bind_func(dso,"ub_resolve")) == NULL || + (p_ub_resolve_free.p = DSO_bind_func(dso,"ub_resolve_free")) == NULL || + (ctx = p_ub_ctx_create.f()) == NULL) { + DSO_free(dso); + return; + } + + unbound_dso = dso; + + /* FIXME: parameterize these through CONF */ + p_ub_ctx_resolvconf.f(ctx,"/etc/resolv.conf"); + p_ub_ctx_add_ta_file.f(ctx,"/var/lib/unbound/root.key"); +} + +static void unbound_fini(void) +{ + if (ctx != NULL) p_ub_ctx_delete.f(ctx); + if (unbound_dso != NULL) DSO_free(unbound_dso); +} +#endif + +/* + * Output is array packed as [len][data][len][data][0] + */ +unsigned char *SSL_get_tlsa_record_byname (const char *name,int port,int type) +{ + unsigned char *ret=NULL; + char *query=NULL; + size_t qlen; + + if (ctx == NULL) return NULL; + + qlen = 7+5+strlen(name)+1; + if ((query = OPENSSL_malloc(qlen)) == NULL) + return NULL; + + BIO_snprintf(query,qlen,"_%u._%s.%s",port&0xffff,type==SOCK_STREAM?"tcp":"udp",name); + +#ifndef OPENSSL_NO_LIBUNBOUND + { + struct ub_result *tlsa=NULL; + + if (p_ub_resolve.f(ctx,query,52,1,&tlsa)==0 && + tlsa->havedata && tlsa->data[0]!=NULL) { + ret=(void*)-1; /* -1 means insecure */ + if (tlsa->secure) do { + unsigned char *data; + unsigned int dlen, i; + + for (dlen=0, i=0; tlsa->data[i]; i++) + dlen += sizeof(int)+(unsigned int)tlsa->len[i]; + dlen +=sizeof(int); + + if ((ret = OPENSSL_malloc(dlen)) == NULL) break; + + for (data=ret, i=0; tlsa->data[i]; i++) { + *(unsigned int *)data = dlen = (unsigned int)tlsa->len[i]; + data += sizeof(unsigned int); + memcpy(data,tlsa->data[i],dlen); + data += dlen; + } + *(unsigned int *)data = 0; /* trailing zero */ + } while (0); + p_ub_resolve_free.f(tlsa); + } + } +#elif defined(RRSET_VALIDATED) + do { + static union { + void *p; int (*f)(const char*,unsigned int,unsigned int,unsigned int,struct rrsetinfo **); } + p_getrrsetbyname = {NULL}; + static union { + void *p; void (*f)(struct rrsetinfo *); } + p_freerrset = {NULL}; + + struct rrsetinfo *rrset=NULL; + + if (p_getrrsetbyname.p==NULL) { + if ((p_getrrsetbyname.p = DSO_global_lookup("getrrsetbyname")) == NULL || + (p_freerrset.p = DSO_global_lookup("freerrset")) == NULL) + p_getrrsetbyname.p = (void*)-1; + } + + if (p_getrrsetbyname.p == (void *)-1) break; + + if (p_getrrsetbyname.f(query,1,52,RRSET_VALIDATED,&rrset) == 0 && rrset->rri_nrdatas) { + ret=(void*)-1; /* -1 means insecure */ + if ((rrset->rri_flags&RRSET_VALIDATED)) do { + unsigned char *data; + unsigned int dlen, i; + + for (dlen=0, i=0; irri_nrdatas; i++) + dlen += sizeof(int)+rrset->rri_rdatas[i].rdi_length; + dlen +=sizeof(int); + + if ((ret = OPENSSL_malloc(sizeof(int)+dlen)) == NULL) break; + + for (data=ret, i=0; irri_rdatas[i].rdi_length; i++) { + *(unsigned int *)data = dlen = rrset->rri_rdatas[i].rdi_length; + data += sizeof(unsigned int); + memcpy(data,rrset->rri_rdatas[i].rdi_data,dlen); + data += dlen; + } + *(unsigned int *)data = 0; /* trailing zero */ + } while (0); + p_freerrset.f(rrset); + } + } while (0); +#elif defined(_WIN32_NOT_YET) + { + PDNS_RECORD rrset; + + DnsQuery_A(query,52,DNS_QUERY_STANDARD,NULL,&rrset,NULL); + DnsRecordListFree(rrset,DnsFreeRecordList); + } +#endif + CRYPTO_free(query); + + return ret; +} -- 2.25.1