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