DTLS 1.2 cached record support.
[oweals/openssl.git] / ssl / dnssec.c
1 #include <openssl/opensslconf.h>
2
3 #include <string.h>
4 #include <netdb.h>
5 #include <sys/socket.h>
6 #include <openssl/bio.h>
7 #include <openssl/dso.h>
8
9 #include "ssl.h"
10
11 #ifndef OPENSSL_NO_LIBUNBOUND
12 #include <unbound.h>
13
14 static struct ub_ctx *ctx = NULL;
15 static DSO *unbound_dso = NULL;
16
17 static union {
18         void *p; struct ub_ctx *(*f)(); }
19         p_ub_ctx_create = {NULL};
20
21 static union {
22         void *p; int (*f)(struct ub_ctx *,const char *); }
23         p_ub_ctx_resolvconf = {NULL};
24
25 static union {
26         void *p; int (*f)(struct ub_ctx *,const char *); }
27         p_ub_ctx_add_ta_file = {NULL};
28
29 static union {
30         void *p; void (*f)(struct ub_ctx *); }
31         p_ub_ctx_delete = {NULL};
32
33 static union {
34         void *p; int (*f)(struct ub_ctx *,const char *,int,int,struct ub_result**); }
35         p_ub_resolve = {NULL};
36
37 static union {
38         void *p; void (*f)(struct ub_result*); }
39         p_ub_resolve_free = {NULL};
40
41 #if defined(__GNUC__) && __GNUC__>=2
42  static void unbound_init(void) __attribute__((constructor));
43  static void unbound_fini(void) __attribute__((destructor));
44 #endif 
45
46 static void unbound_init(void)
47 {
48         DSO *dso;
49
50         if ((dso = DSO_load(NULL, "unbound", NULL, 0)) == NULL) return;
51
52         if ((p_ub_ctx_create.p = DSO_bind_func(dso,"ub_ctx_create")) == NULL ||
53             (p_ub_ctx_resolvconf.p = DSO_bind_func(dso,"ub_ctx_resolvconf")) == NULL ||
54             (p_ub_ctx_add_ta_file.p = DSO_bind_func(dso,"ub_ctx_add_ta_file")) == NULL ||
55             (p_ub_ctx_delete.p = DSO_bind_func(dso,"ub_ctx_delete")) == NULL ||
56             (p_ub_resolve.p = DSO_bind_func(dso,"ub_resolve")) == NULL ||
57             (p_ub_resolve_free.p = DSO_bind_func(dso,"ub_resolve_free")) == NULL ||
58             (ctx = p_ub_ctx_create.f()) == NULL) {
59                 DSO_free(dso);
60                 return;
61         }
62
63         unbound_dso = dso;
64
65         /* FIXME: parameterize these through CONF */
66         p_ub_ctx_resolvconf.f(ctx,"/etc/resolv.conf");
67         p_ub_ctx_add_ta_file.f(ctx,"/var/lib/unbound/root.key");
68 }
69
70 static void unbound_fini(void)
71 {
72         if (ctx != NULL) p_ub_ctx_delete.f(ctx);
73         if (unbound_dso != NULL) DSO_free(unbound_dso);
74 }
75 #endif
76
77 /*
78  * Output is array packed as [len][data][len][data][0]
79  */
80 unsigned char *SSL_get_tlsa_record_byname (const char *name,int port,int type)
81 {
82         unsigned char *ret=NULL;
83         char *query=NULL;
84         size_t qlen;
85
86 #ifndef OPENSSL_NO_LIBUNBOUND
87         if (ctx == NULL) return NULL;
88 #elif defined(RRSET_VALIDATED)
89         static union {
90                 void *p; int (*f)(const char*,unsigned int,unsigned int,unsigned int,struct rrsetinfo **); }
91                 p_getrrsetbyname = {NULL};
92         static union {
93                 void *p; void (*f)(struct rrsetinfo *); }
94                 p_freerrset = {NULL};
95
96         if (p_getrrsetbyname.p==NULL) {
97                 if ((p_getrrsetbyname.p = DSO_global_lookup("getrrsetbyname")) == NULL ||
98                     (p_freerrset.p = DSO_global_lookup("freerrset")) == NULL)
99                         p_getrrsetbyname.p = (void*)-1;
100         }
101
102         if (p_getrrsetbyname.p == (void *)-1) return NULL;
103 #endif
104
105         qlen = 7+5+strlen(name)+1;
106         if ((query = OPENSSL_malloc(qlen)) == NULL)
107                 return NULL;
108
109         BIO_snprintf(query,qlen,"_%u._%s.%s",port&0xffff,type==SOCK_STREAM?"tcp":"udp",name);
110
111 #ifndef OPENSSL_NO_LIBUNBOUND
112         {
113         struct ub_result *tlsa=NULL;
114
115         if (p_ub_resolve.f(ctx,query,52,1,&tlsa)==0 &&
116             tlsa->havedata && tlsa->data[0]!=NULL) {
117                 ret=(void*)-1;  /* -1 means insecure */
118                 if (tlsa->secure) do {
119                         unsigned char *data;
120                         unsigned int dlen, i;
121
122                         for (dlen=0, i=0; tlsa->data[i]; i++)
123                                 dlen += sizeof(int)+(unsigned int)tlsa->len[i];
124                         dlen +=sizeof(int);
125
126                         if ((ret = OPENSSL_malloc(dlen)) == NULL) break;
127                         
128                         for (data=ret, i=0; tlsa->data[i]; i++) {
129                                 *(unsigned int *)data = dlen = (unsigned int)tlsa->len[i];
130                                 data += sizeof(unsigned int);
131                                 memcpy(data,tlsa->data[i],dlen);
132                                 data += dlen;
133                         }
134                         *(unsigned int *)data = 0;      /* trailing zero */
135                 } while (0);    
136                 p_ub_resolve_free.f(tlsa);
137         }
138         }
139 #elif defined(RRSET_VALIDATED)
140         {
141         struct rrsetinfo *rrset=NULL;
142
143         if (p_getrrsetbyname.f(query,1,52,RRSET_VALIDATED,&rrset) == 0 && rrset->rri_nrdatas) {
144                 ret=(void*)-1;  /* -1 means insecure */
145                 if ((rrset->rri_flags&RRSET_VALIDATED)) do {
146                         unsigned char *data;
147                         unsigned int dlen, i;
148
149                         for (dlen=0, i=0; i<rrset->rri_nrdatas; i++)
150                                 dlen += sizeof(int)+rrset->rri_rdatas[i].rdi_length;
151                         dlen +=sizeof(int);
152
153                         if ((ret = OPENSSL_malloc(sizeof(int)+dlen)) == NULL) break;
154
155                         for (data=ret, i=0; i<rrset->rri_rdatas[i].rdi_length; i++) {
156                                 *(unsigned int *)data = dlen = rrset->rri_rdatas[i].rdi_length;
157                                 data += sizeof(unsigned int);
158                                 memcpy(data,rrset->rri_rdatas[i].rdi_data,dlen);
159                                 data += dlen;
160                         }
161                         *(unsigned int *)data = 0;      /* trailing zero */
162                 } while (0);    
163                 p_freerrset.f(rrset);
164         }
165         }
166 #elif defined(_WIN32_NOT_YET)
167         {
168         PDNS_RECORD rrset;
169
170         DnsQuery_A(query,52,DNS_QUERY_STANDARD,NULL,&rrset,NULL);
171         DnsRecordListFree(rrset,DnsFreeRecordList);
172         }
173 #endif
174         CRYPTO_free(query);
175
176         return ret;
177 }