dnssec.c revision 1.2
1/*	$OpenBSD: dnssec.c,v 1.2 2001/01/27 12:03:32 niklas 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 <stdlib.h>
30#include <string.h>
31
32#include <netinet/in.h>
33#include <arpa/nameser.h>
34#include <arpa/inet.h>
35#include <dns/keyvalues.h>
36#include <lwres/lwres.h>
37#include <lwres/netdb.h>
38
39#include <openssl/rsa.h>
40
41#include "sysdep.h"
42
43#include "exchange.h"
44#include "log.h"
45#include "message.h"
46#include "transport.h"
47
48#include "ipsec_num.h"
49#include "dnssec.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
60/* XXX IPv4 specific */
61void *
62dns_get_key (int type, struct message *msg, int *keylen)
63{
64  struct rrsetinfo *rr;
65  struct hostent *hostent;
66  struct sockaddr_in *dst;
67  int ret, i;
68  struct dns_rdata_key key_rr;
69  u_int8_t algorithm;
70
71  switch (type)
72    {
73    case IKE_AUTH_RSA_SIG:
74      algorithm = DNS_KEYALG_RSA;
75      break;
76
77    case IKE_AUTH_RSA_ENC:
78    case IKE_AUTH_RSA_ENC_REV:
79      /* XXX Not yes. */
80      /* algorithm = DNS_KEYALG_RSA; */
81      return NULL;
82
83    case IKE_AUTH_DSS:
84      /* XXX Not yet. */
85      /* algorithm = DNS_KEYALG_DSS; */
86      return NULL;
87
88    case IKE_AUTH_PRE_SHARED:
89    default:
90      return NULL;
91    }
92
93  /* Get peer IP address */
94  msg->transport->vtbl->get_dst (msg->transport, (struct sockaddr **)&dst, &i);
95  /* Get peer name and aliases */
96  hostent = lwres_gethostbyaddr ((char *)&dst->sin_addr,
97				 sizeof (struct in_addr), PF_INET);
98
99  if (!hostent)
100    {
101      LOG_DBG ((LOG_MISC, 30,
102		"dns_get_key: lwres_gethostbyaddr (%s) failed: %s",
103		inet_ntoa (((struct sockaddr_in *)dst)->sin_addr),
104		lwres_hstrerror (lwres_h_errno)));
105      return NULL;
106    }
107
108  /* Try host official name */
109  LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s",
110	    hostent->h_name));
111  ret = lwres_getrrsetbyname (hostent->h_name, C_IN, T_KEY, 0, &rr);
112  if (ret)
113    {
114      /* Try host aliases */
115      i = 0;
116      while (hostent->h_aliases[i] && ret)
117	{
118	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for alias %s",
119		    hostent->h_aliases[i]));
120	  ret = lwres_getrrsetbyname (hostent->h_aliases[i], C_IN, T_KEY, 0,
121				      &rr);
122	  i ++;
123	}
124    }
125
126  if (ret)
127    {
128      LOG_DBG ((LOG_MISC, 30, "dns_get_key: no DNS responses (error %d)",
129		ret));
130      return NULL;
131    }
132
133  LOG_DBG ((LOG_MISC, 80,
134	    "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d",
135	    rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas,
136	    rr->rri_nsigs));
137
138  /* We don't accept unvalidated data. */
139  if (!(rr->rri_flags & RRSET_VALIDATED))
140    {
141      LOG_DBG ((LOG_MISC, 10, "dns_get_key: got unvalidated response"));
142      lwres_freerrset (rr);
143      return NULL;
144    }
145
146  /* Sanity. */
147  if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY)
148    {
149      LOG_DBG ((LOG_MISC, 30, "dns_get_key: no KEY RRs recieved"));
150      lwres_freerrset (rr);
151      return NULL;
152    }
153
154  memset (&key_rr, 0, sizeof (key_rr));
155
156  /*
157   * Find a key with the wanted algorithm, if any.
158   * XXX If there are several keys present, we currently only find the first.
159   */
160  for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i ++)
161    {
162      key_rr.flags     = ntohs ((u_int16_t) *rr->rri_rdatas[i].rdi_data);
163      key_rr.protocol  = *(rr->rri_rdatas[i].rdi_data + 2);
164      key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3);
165
166      if (key_rr.protocol != DNS_KEYPROTO_IPSEC)
167	{
168	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored non-IPSEC key"));
169	  continue;
170	}
171
172      if (key_rr.algorithm != algorithm)
173	{
174	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored key with other alg"));
175	  continue;
176	}
177
178      key_rr.datalen   = rr->rri_rdatas[i].rdi_length - 4;
179      if (key_rr.datalen <= 0)
180	{
181	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored bad key"));
182	  key_rr.datalen = 0;
183	  continue;
184	}
185
186      /* This key seems to fit our requirements... */
187      key_rr.data = (char *)malloc (key_rr.datalen);
188      if (!key_rr.data)
189	{
190	  log_error ("dns_get_key: malloc (%d) failed", key_rr.datalen);
191	  lwres_freerrset (rr);
192	  return NULL;
193	}
194      memcpy (key_rr.data, rr->rri_rdatas[i].rdi_data + 4, key_rr.datalen);
195      *keylen = key_rr.datalen;
196    }
197
198  lwres_freerrset (rr);
199
200  if (key_rr.datalen)
201    return key_rr.data;
202  else
203    return NULL;
204}
205
206int
207dns_RSA_dns_to_x509 (u_int8_t *key, int keylen, RSA **rsa_key)
208{
209  RSA *rsa;
210  int key_offset;
211  u_int8_t e_len;
212
213  if (!key || keylen <= 0)
214    {
215      log_print ("dns_RSA_dns_to_x509: invalid public key");
216      return -1;
217    }
218
219  rsa = RSA_new ();
220  if (!rsa)
221    {
222      log_error ("dns_RSA_dns_to_x509: failed to allocate new RSA struct");
223      return -1;
224    }
225
226  e_len = *key;
227  key_offset = 1;
228
229  if (e_len == 0)
230    {
231      if (keylen < 3)
232	{
233	  log_print ("dns_RSA_dns_to_x509: invalid public key");
234	  RSA_free (rsa);
235	  return -1;
236	}
237      e_len  = *(key + key_offset++) << 8;
238      e_len += *(key + key_offset++);
239    }
240
241  if (e_len > (keylen - key_offset))
242    {
243      log_print ("dns_RSA_dns_to_x509: invalid public key");
244      RSA_free (rsa);
245      return -1;
246    }
247
248  rsa->e = BN_bin2bn (key + key_offset, e_len, NULL);
249  key_offset += e_len;
250
251  /* XXX if (keylen <= key_offset) -> "invalid public key" ? */
252
253  rsa->n = BN_bin2bn (key + key_offset, keylen - key_offset, NULL);
254
255  *rsa_key = rsa;
256
257  LOG_DBG ((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key",
258	    BN_num_bits (rsa->n)));
259
260  return 0;
261}
262
263#if notyet
264int
265dns_RSA_x509_to_dns (RSA *rsa_key, u_int8_t *key, int *keylen)
266{
267  return 0;
268}
269#endif
270