dnssec.c revision 1.9
1/*	$OpenBSD: dnssec.c,v 1.9 2001/08/17 10:35:51 ho 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
37#ifdef LWRES
38#include <lwres/netdb.h>
39#include <dns/keyvalues.h>
40#else
41#include <netdb.h>
42#endif
43
44#include "sysdep.h"
45
46#include "dnssec.h"
47#include "exchange.h"
48#include "ipsec_num.h"
49#include "libcrypto.h"
50#include "log.h"
51#include "message.h"
52#include "transport.h"
53#include "util.h"
54
55/* adapted from <dns/rdatastruct.h> / RFC 2535  */
56struct dns_rdata_key {
57  u_int16_t flags;
58  u_int8_t protocol;
59  u_int8_t algorithm;
60  u_int16_t datalen;
61  unsigned char *data;
62};
63
64void *
65dns_get_key (int type, struct message *msg, int *keylen)
66{
67  struct exchange *exchange = msg->exchange;
68  struct rrsetinfo *rr;
69  struct dns_rdata_key key_rr;
70  char name[MAXHOSTNAMELEN];
71  in_addr_t ip4;
72  u_int8_t algorithm;
73  u_int8_t *id;
74  size_t id_len;
75  int ret, i;
76
77  switch (type)
78    {
79    case IKE_AUTH_RSA_SIG:
80      algorithm = DNS_KEYALG_RSA;
81      break;
82
83    case IKE_AUTH_RSA_ENC:
84    case IKE_AUTH_RSA_ENC_REV:
85      /* XXX Not yet. */
86      /* algorithm = DNS_KEYALG_RSA; */
87      return 0;
88
89    case IKE_AUTH_DSS:
90      /* XXX Not yet. */
91      /* algorithm = DNS_KEYALG_DSS; */
92      return 0;
93
94    case IKE_AUTH_PRE_SHARED:
95    default:
96      return 0;
97    }
98
99  id = exchange->initiator ? exchange->id_r : exchange->id_i;
100  id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len;
101  memset (name, 0, MAXHOSTNAMELEN);
102
103  if (!id || id_len == 0)
104    {
105      log_print ("dns_get_key: ID is missing");
106      return 0;
107    }
108
109  /* Exchanges (and SAs) don't carry the ID in ISAKMP form */
110  id -= ISAKMP_ID_TYPE_OFF;
111  id_len += ISAKMP_ID_TYPE_OFF - ISAKMP_ID_DATA_OFF;
112
113  switch (GET_ISAKMP_ID_TYPE (id))
114    {
115    case IPSEC_ID_IPV4_ADDR:
116      /* We want to lookup a KEY RR in the reverse zone.  */
117      if (id_len < sizeof ip4)
118	return 0;
119      memcpy (&ip4, id + ISAKMP_ID_DATA_OFF, sizeof ip4);
120      sprintf (name, "%d.%d.%d.%d.in-addr.arpa.", ip4 >> 24,
121	       (ip4 >> 16) & 0xFF, (ip4 >> 8) & 0xFF, ip4 & 0xFF);
122      break;
123
124    case IPSEC_ID_FQDN:
125      if ((id_len + 1) >= MAXHOSTNAMELEN)
126	return 0;
127      /* ID is not NULL-terminated. Add trailing dot and terminate.  */
128      memcpy (name, id + ISAKMP_ID_DATA_OFF, id_len);
129      *(name + id_len) = '.';
130      *(name + id_len + 1) = '\0';
131      break;
132
133    case IPSEC_ID_USER_FQDN:
134      /* Some special handling here. */
135      break;
136
137    case IPSEC_ID_IPV6_ADDR:
138    default:
139      /* XXX not yet */
140      return 0;
141    }
142
143  LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s", name));
144  ret = getrrsetbyname (name, C_IN, T_KEY, 0, &rr);
145
146  if (ret)
147    {
148      LOG_DBG ((LOG_MISC, 30, "dns_get_key: no DNS responses (error %d)",
149		ret));
150      return 0;
151    }
152
153  LOG_DBG ((LOG_MISC, 80,
154	    "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d",
155	    rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas,
156	    rr->rri_nsigs));
157
158  /* We don't accept unvalidated data. */
159  if (!(rr->rri_flags & RRSET_VALIDATED))
160    {
161      LOG_DBG ((LOG_MISC, 10, "dns_get_key: got unvalidated response"));
162      freerrset (rr);
163      return 0;
164    }
165
166  /* Sanity. */
167  if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY)
168    {
169      LOG_DBG ((LOG_MISC, 30, "dns_get_key: no KEY RRs recieved"));
170      freerrset (rr);
171      return 0;
172    }
173
174  memset (&key_rr, 0, sizeof key_rr);
175
176  /*
177   * Find a key with the wanted algorithm, if any.
178   * XXX If there are several keys present, we currently only find the first.
179   */
180  for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i++)
181    {
182      key_rr.flags     = ntohs ((u_int16_t) *rr->rri_rdatas[i].rdi_data);
183      key_rr.protocol  = *(rr->rri_rdatas[i].rdi_data + 2);
184      key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3);
185
186      if (key_rr.protocol != DNS_KEYPROTO_IPSEC)
187	{
188	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored non-IPsec key"));
189	  continue;
190	}
191
192      if (key_rr.algorithm != algorithm)
193	{
194	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored key with other alg"));
195	  continue;
196	}
197
198      key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4;
199      if (key_rr.datalen <= 0)
200	{
201	  LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored bad key"));
202	  key_rr.datalen = 0;
203	  continue;
204	}
205
206      /* This key seems to fit our requirements... */
207      key_rr.data = (char *)malloc (key_rr.datalen);
208      if (!key_rr.data)
209	{
210	  log_error ("dns_get_key: malloc (%d) failed", key_rr.datalen);
211	  freerrset (rr);
212	  return 0;
213	}
214      memcpy (key_rr.data, rr->rri_rdatas[i].rdi_data + 4, key_rr.datalen);
215      *keylen = key_rr.datalen;
216    }
217
218  freerrset (rr);
219
220  if (key_rr.datalen)
221    return key_rr.data;
222  else
223    return 0;
224}
225
226int
227dns_RSA_dns_to_x509 (u_int8_t *key, int keylen, RSA **rsa_key)
228{
229  RSA *rsa;
230  int key_offset;
231  u_int8_t e_len;
232
233  if (!key || keylen <= 0)
234    {
235      log_print ("dns_RSA_dns_to_x509: invalid public key");
236      return -1;
237    }
238
239  rsa = LC (RSA_new, ());
240  if (rsa == NULL)
241    {
242      log_error ("dns_RSA_dns_to_x509: failed to allocate new RSA struct");
243      return -1;
244    }
245
246  e_len = *key;
247  key_offset = 1;
248
249  if (e_len == 0)
250    {
251      if (keylen < 3)
252	{
253	  log_print ("dns_RSA_dns_to_x509: invalid public key");
254	  LC (RSA_free, (rsa));
255	  return -1;
256	}
257      e_len  = *(key + key_offset++) << 8;
258      e_len += *(key + key_offset++);
259    }
260
261  if (e_len > (keylen - key_offset))
262    {
263      log_print ("dns_RSA_dns_to_x509: invalid public key");
264      LC (RSA_free, (rsa));
265      return -1;
266    }
267
268  rsa->e = LC (BN_bin2bn, (key + key_offset, e_len, NULL));
269  key_offset += e_len;
270
271  /* XXX if (keylen <= key_offset) -> "invalid public key" ? */
272
273  rsa->n = LC (BN_bin2bn, (key + key_offset, keylen - key_offset, NULL));
274
275  *rsa_key = rsa;
276
277  LOG_DBG ((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key",
278	    LC (BN_num_bits, (rsa->n))));
279
280  return 0;
281}
282
283#if notyet
284int
285dns_RSA_x509_to_dns (RSA *rsa_key, u_int8_t *key, int *keylen)
286{
287  return 0;
288}
289#endif
290