xref: /openbsd-src/sbin/isakmpd/dnssec.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: dnssec.c,v 1.7 2001/07/01 06:03:34 angelos Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 H�kan Olsson.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 #include <arpa/inet.h>
33 #include <stdlib.h>
34 
35 #include <openssl/rsa.h>
36 #include <dns/keyvalues.h>
37 #include <lwres/lwres.h>
38 #include <lwres/netdb.h>
39 
40 #include "sysdep.h"
41 
42 #include "dnssec.h"
43 #include "exchange.h"
44 #include "ipsec_num.h"
45 #include "libcrypto.h"
46 #include "log.h"
47 #include "message.h"
48 #include "transport.h"
49 #include "util.h"
50 
51 /* adapted from <dns/rdatastruct.h> / RFC 2535  */
52 struct dns_rdata_key {
53   u_int16_t flags;
54   u_int8_t protocol;
55   u_int8_t algorithm;
56   u_int16_t datalen;
57   unsigned char *data;
58 };
59 
60 void *
61 dns_get_key (int type, struct message *msg, int *keylen)
62 {
63   struct rrsetinfo *rr;
64   struct hostent *hostent;
65   struct sockaddr *dst;
66   int ret, i;
67   struct dns_rdata_key key_rr;
68   u_int8_t algorithm;
69 
70   switch (type)
71     {
72     case IKE_AUTH_RSA_SIG:
73       algorithm = DNS_KEYALG_RSA;
74       break;
75 
76     case IKE_AUTH_RSA_ENC:
77     case IKE_AUTH_RSA_ENC_REV:
78       /* XXX Not yet. */
79       /* algorithm = DNS_KEYALG_RSA; */
80       return 0;
81 
82     case IKE_AUTH_DSS:
83       /* XXX Not yet. */
84       /* algorithm = DNS_KEYALG_DSS; */
85       return 0;
86 
87     case IKE_AUTH_PRE_SHARED:
88     default:
89       return 0;
90     }
91 
92   /* Get peer IP address */
93   msg->transport->vtbl->get_dst (msg->transport, &dst);
94   /* Get peer name and aliases */
95   switch (dst->sa_family)
96     {
97     case AF_INET:
98       hostent =
99 	lwres_gethostbyaddr ((char *)&((struct sockaddr_in *)dst)->sin_addr,
100 			     sizeof (struct in_addr), PF_INET);
101       break;
102     case AF_INET6:
103       hostent =
104 	lwres_gethostbyaddr ((char *)&((struct sockaddr_in6 *)dst)->sin6_addr,
105 			     sizeof (struct in6_addr), PF_INET6);
106       break;
107     default:
108       log_print ("dns_get_key: unsupported protocol family %d",
109 		 dst->sa_family);
110       return 0;
111     }
112 
113   if (!hostent)
114     {
115 #ifdef USE_DEBUG
116       char *dst_str;
117 
118       if (sockaddr2text (dst, &dst_str, 0))
119 	dst_str = 0;
120 
121       LOG_DBG ((LOG_MISC, 30,
122 		"dns_get_key: lwres_gethostbyaddr (%s) failed: %s",
123 		dst_str ? dst_str : "<???>", lwres_hstrerror (lwres_h_errno)));
124 
125       if (dst_str)
126 	free (dst_str);
127 #endif
128       return 0;
129     }
130 
131   /* Try host official name */
132   LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s",
133 	    hostent->h_name));
134   ret = lwres_getrrsetbyname (hostent->h_name, C_IN, T_KEY, 0, &rr);
135   if (ret)
136     {
137       /* Try host aliases */
138       i = 0;
139       while (hostent->h_aliases[i] && ret)
140 	{
141 	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for alias %s",
142 		    hostent->h_aliases[i]));
143 	  ret = lwres_getrrsetbyname (hostent->h_aliases[i], C_IN, T_KEY, 0,
144 				      &rr);
145 	  i++;
146 	}
147     }
148 
149   if (ret)
150     {
151       LOG_DBG ((LOG_MISC, 30, "dns_get_key: no DNS responses (error %d)",
152 		ret));
153       return 0;
154     }
155 
156   LOG_DBG ((LOG_MISC, 80,
157 	    "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d",
158 	    rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas,
159 	    rr->rri_nsigs));
160 
161   /* We don't accept unvalidated data. */
162   if (!(rr->rri_flags & RRSET_VALIDATED))
163     {
164       LOG_DBG ((LOG_MISC, 10, "dns_get_key: got unvalidated response"));
165       lwres_freerrset (rr);
166       return 0;
167     }
168 
169   /* Sanity. */
170   if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY)
171     {
172       LOG_DBG ((LOG_MISC, 30, "dns_get_key: no KEY RRs recieved"));
173       lwres_freerrset (rr);
174       return 0;
175     }
176 
177   memset (&key_rr, 0, sizeof key_rr);
178 
179   /*
180    * Find a key with the wanted algorithm, if any.
181    * XXX If there are several keys present, we currently only find the first.
182    */
183   for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i++)
184     {
185       key_rr.flags     = ntohs ((u_int16_t) *rr->rri_rdatas[i].rdi_data);
186       key_rr.protocol  = *(rr->rri_rdatas[i].rdi_data + 2);
187       key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3);
188 
189       if (key_rr.protocol != DNS_KEYPROTO_IPSEC)
190 	{
191 	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored non-IPsec key"));
192 	  continue;
193 	}
194 
195       if (key_rr.algorithm != algorithm)
196 	{
197 	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored key with other alg"));
198 	  continue;
199 	}
200 
201       key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4;
202       if (key_rr.datalen <= 0)
203 	{
204 	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored bad key"));
205 	  key_rr.datalen = 0;
206 	  continue;
207 	}
208 
209       /* This key seems to fit our requirements... */
210       key_rr.data = (char *)malloc (key_rr.datalen);
211       if (!key_rr.data)
212 	{
213 	  log_error ("dns_get_key: malloc (%d) failed", key_rr.datalen);
214 	  lwres_freerrset (rr);
215 	  return 0;
216 	}
217       memcpy (key_rr.data, rr->rri_rdatas[i].rdi_data + 4, key_rr.datalen);
218       *keylen = key_rr.datalen;
219     }
220 
221   lwres_freerrset (rr);
222 
223   if (key_rr.datalen)
224     return key_rr.data;
225   else
226     return 0;
227 }
228 
229 int
230 dns_RSA_dns_to_x509 (u_int8_t *key, int keylen, RSA **rsa_key)
231 {
232   RSA *rsa;
233   int key_offset;
234   u_int8_t e_len;
235 
236   if (!key || keylen <= 0)
237     {
238       log_print ("dns_RSA_dns_to_x509: invalid public key");
239       return -1;
240     }
241 
242   rsa = LC (RSA_new, ());
243   if (rsa == NULL)
244     {
245       log_error ("dns_RSA_dns_to_x509: failed to allocate new RSA struct");
246       return -1;
247     }
248 
249   e_len = *key;
250   key_offset = 1;
251 
252   if (e_len == 0)
253     {
254       if (keylen < 3)
255 	{
256 	  log_print ("dns_RSA_dns_to_x509: invalid public key");
257 	  LC (RSA_free, (rsa));
258 	  return -1;
259 	}
260       e_len  = *(key + key_offset++) << 8;
261       e_len += *(key + key_offset++);
262     }
263 
264   if (e_len > (keylen - key_offset))
265     {
266       log_print ("dns_RSA_dns_to_x509: invalid public key");
267       LC (RSA_free, (rsa));
268       return -1;
269     }
270 
271   rsa->e = LC (BN_bin2bn, (key + key_offset, e_len, NULL));
272   key_offset += e_len;
273 
274   /* XXX if (keylen <= key_offset) -> "invalid public key" ? */
275 
276   rsa->n = LC (BN_bin2bn, (key + key_offset, keylen - key_offset, NULL));
277 
278   *rsa_key = rsa;
279 
280   LOG_DBG ((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key",
281 	    LC (BN_num_bits, (rsa->n))));
282 
283   return 0;
284 }
285 
286 #if notyet
287 int
288 dns_RSA_x509_to_dns (RSA *rsa_key, u_int8_t *key, int *keylen)
289 {
290   return 0;
291 }
292 #endif
293