summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2013-05-13 15:36:06 +0200
committerAndy Polyakov <appro@openssl.org>2013-05-13 15:36:06 +0200
commit8517d0c00df8aa06705d80b5b2efae0a50e50e44 (patch)
treec4b6dde202e011b89b2ce031d190a9e501cee281
parent8659dc73f4186d18feda71ec17e3fe705c604738 (diff)
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
-rw-r--r--ssl/dnssec.c172
1 files changed, 172 insertions, 0 deletions
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 <openssl/opensslconf.h>
+
+#include <string.h>
+#include <netdb.h>
+#include <openssl/bio.h>
+#include <openssl/dso.h>
+
+#ifndef OPENSSL_NO_LIBUNBOUND
+#include <unbound.h>
+
+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; i<rrset->rri_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; i<rrset->rri_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;
+}