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