dnssec.c revision 1.21
1/* $OpenBSD: dnssec.c,v 1.21 2005/02/27 13:12:12 hshoexer 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/types.h> 28#include <netinet/in.h> 29#include <arpa/nameser.h> 30#include <arpa/inet.h> 31#include <stdlib.h> 32 33#include <openssl/rsa.h> 34 35#ifdef LWRES 36#include <lwres/netdb.h> 37#include <dns/keyvalues.h> 38#else 39#include <netdb.h> 40#endif 41 42#include "sysdep.h" 43 44#include "dnssec.h" 45#include "exchange.h" 46#include "ipsec_num.h" 47#include "libcrypto.h" 48#include "log.h" 49#include "message.h" 50#include "transport.h" 51#include "util.h" 52 53#ifndef DNS_UFQDN_SEPARATOR 54#define DNS_UFQDN_SEPARATOR "._ipsec." 55#endif 56 57/* adapted from <dns/rdatastruct.h> / RFC 2535 */ 58struct dns_rdata_key { 59 u_int16_t flags; 60 u_int8_t protocol; 61 u_int8_t algorithm; 62 u_int16_t datalen; 63 unsigned char *data; 64}; 65 66void * 67dns_get_key(int type, struct message *msg, int *keylen) 68{ 69 struct exchange *exchange = msg->exchange; 70 struct rrsetinfo *rr; 71 struct dns_rdata_key key_rr; 72 char name[MAXHOSTNAMELEN]; 73 in_addr_t ip4; 74 u_int8_t algorithm, *id, *umark; 75 size_t id_len; 76 int ret, i; 77 78 switch (type) { 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 bzero(name, sizeof name); 102 103 if (!id || id_len == 0) { 104 log_print("dns_get_key: ID is missing"); 105 return 0; 106 } 107 /* Exchanges (and SAs) don't carry the ID in ISAKMP form */ 108 id -= ISAKMP_GEN_SZ; 109 id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; 110 111 switch (GET_ISAKMP_ID_TYPE(id)) { 112 case IPSEC_ID_IPV4_ADDR: 113 /* We want to lookup a KEY RR in the reverse zone. */ 114 if (id_len < sizeof ip4) 115 return 0; 116 memcpy(&ip4, id + ISAKMP_ID_DATA_OFF, sizeof ip4); 117 snprintf(name, sizeof name, "%d.%d.%d.%d.in-addr.arpa.", ip4 118 >> 24, (ip4 >> 16) & 0xFF, (ip4 >> 8) & 0xFF, ip4 & 0xFF); 119 break; 120 121 case IPSEC_ID_IPV6_ADDR: 122 /* XXX Not yet. */ 123 return 0; 124 break; 125 126 case IPSEC_ID_FQDN: 127 if ((id_len + 1) >= sizeof name) 128 return 0; 129 /* ID is not NULL-terminated. Add trailing dot and NULL. */ 130 memcpy(name, id + ISAKMP_ID_DATA_OFF, id_len); 131 *(name + id_len) = '.'; 132 *(name + id_len + 1) = '\0'; 133 break; 134 135 case IPSEC_ID_USER_FQDN: 136 /* 137 * Some special handling here. We want to convert the ID 138 * 'user@host.domain' string into 'user._ipsec.host.domain.'. 139 */ 140 if ((id_len + sizeof(DNS_UFQDN_SEPARATOR)) >= sizeof name) 141 return 0; 142 /* Look for the '@' separator. */ 143 for (umark = id + ISAKMP_ID_DATA_OFF; (umark - id) < id_len; 144 umark++) 145 if (*umark == '@') 146 break; 147 if (*umark != '@') { 148 LOG_DBG((LOG_MISC, 50, "dns_get_key: bad UFQDN ID")); 149 return 0; 150 } 151 *umark++ = '\0'; 152 /* id is now terminated. 'umark', however, is not. */ 153 snprintf(name, sizeof name, "%s%s", id + ISAKMP_ID_DATA_OFF, 154 DNS_UFQDN_SEPARATOR); 155 memcpy(name + strlen(name), umark, id_len - strlen(id) - 1); 156 *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 2) = '.'; 157 *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 1) = '\0'; 158 break; 159 160 default: 161 return 0; 162 } 163 164 LOG_DBG((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s", name)); 165 ret = getrrsetbyname(name, C_IN, T_KEY, 0, &rr); 166 167 if (ret) { 168 LOG_DBG((LOG_MISC, 30, "dns_get_key: no DNS responses " 169 "(error %d)", ret)); 170 return 0; 171 } 172 LOG_DBG((LOG_MISC, 80, 173 "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d", 174 rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas, 175 rr->rri_nsigs)); 176 177 /* We don't accept unvalidated data. */ 178 if (!(rr->rri_flags & RRSET_VALIDATED)) { 179 LOG_DBG((LOG_MISC, 10, "dns_get_key: " 180 "got unvalidated response")); 181 freerrset(rr); 182 return 0; 183 } 184 /* Sanity. */ 185 if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY) { 186 LOG_DBG((LOG_MISC, 30, "dns_get_key: no KEY RRs received")); 187 freerrset(rr); 188 return 0; 189 } 190 bzero(&key_rr, sizeof key_rr); 191 192 /* 193 * Find a key with the wanted algorithm, if any. 194 * XXX If there are several keys present, we currently only find the 195 * first. 196 */ 197 for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i++) { 198 key_rr.flags = ntohs((u_int16_t) * rr->rri_rdatas[i].rdi_data); 199 key_rr.protocol = *(rr->rri_rdatas[i].rdi_data + 2); 200 key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3); 201 202 if (key_rr.protocol != DNS_KEYPROTO_IPSEC) { 203 LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored " 204 "non-IPsec key")); 205 continue; 206 } 207 if (key_rr.algorithm != algorithm) { 208 LOG_DBG((LOG_MISC, 50, "dns_get_key: ignored " 209 "key with other alg")); 210 continue; 211 } 212 key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4; 213 if (key_rr.datalen <= 0) { 214 LOG_DBG((LOG_MISC, 50, "dns_get_key: " 215 "ignored bad key")); 216 key_rr.datalen = 0; 217 continue; 218 } 219 /* This key seems to fit our requirements... */ 220 key_rr.data = (char *)malloc(key_rr.datalen); 221 if (!key_rr.data) { 222 log_error("dns_get_key: malloc (%d) failed", 223 key_rr.datalen); 224 freerrset(rr); 225 return 0; 226 } 227 memcpy(key_rr.data, rr->rri_rdatas[i].rdi_data + 4, 228 key_rr.datalen); 229 *keylen = key_rr.datalen; 230 } 231 232 freerrset(rr); 233 234 if (key_rr.datalen) 235 return key_rr.data; 236 return 0; 237} 238 239int 240dns_RSA_dns_to_x509(u_int8_t *key, int keylen, RSA **rsa_key) 241{ 242 RSA *rsa; 243 int key_offset; 244 u_int8_t e_len; 245 246 if (!key || keylen <= 0) { 247 log_print("dns_RSA_dns_to_x509: invalid public key"); 248 return -1; 249 } 250 rsa = RSA_new(); 251 if (rsa == NULL) { 252 log_error("dns_RSA_dns_to_x509: " 253 "failed to allocate new RSA struct"); 254 return -1; 255 } 256 e_len = *key; 257 key_offset = 1; 258 259 if (e_len == 0) { 260 if (keylen < 3) { 261 log_print("dns_RSA_dns_to_x509: invalid public key"); 262 RSA_free(rsa); 263 return -1; 264 } 265 e_len = *(key + key_offset++) << 8; 266 e_len += *(key + key_offset++); 267 } 268 if (e_len > (keylen - key_offset)) { 269 log_print("dns_RSA_dns_to_x509: invalid public key"); 270 RSA_free(rsa); 271 return -1; 272 } 273 rsa->e = BN_bin2bn(key + key_offset, e_len, NULL); 274 key_offset += e_len; 275 276 /* XXX if (keylen <= key_offset) -> "invalid public key" ? */ 277 278 rsa->n = BN_bin2bn(key + key_offset, keylen - key_offset, NULL); 279 280 *rsa_key = rsa; 281 282 LOG_DBG((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key", 283 BN_num_bits(rsa->n))); 284 return 0; 285} 286 287#if notyet 288int 289dns_RSA_x509_to_dns(RSA *rsa_key, u_int8_t *key, int *keylen) 290{ 291 return 0; 292} 293#endif 294