dnssec.c revision 1.7
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  */
52struct 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
60void *
61dns_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
229int
230dns_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
287int
288dns_RSA_x509_to_dns (RSA *rsa_key, u_int8_t *key, int *keylen)
289{
290  return 0;
291}
292#endif
293