diff options
author | Othmar Gsenger <otti@anytun.org> | 2007-12-08 20:59:57 +0000 |
---|---|---|
committer | Othmar Gsenger <otti@anytun.org> | 2007-12-08 20:59:57 +0000 |
commit | f84dc62cc602eacb0daee3e9918a68b711ba94f0 (patch) | |
tree | 1acbdabf30b2ece1da880386da6a4b7c002669c3 /keyexchange/isakmpd-20041012/isakmp_cfg.c | |
parent | * added AuthTag class (diff) |
removed isakmpd
Diffstat (limited to 'keyexchange/isakmpd-20041012/isakmp_cfg.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/isakmp_cfg.c | 982 |
1 files changed, 0 insertions, 982 deletions
diff --git a/keyexchange/isakmpd-20041012/isakmp_cfg.c b/keyexchange/isakmpd-20041012/isakmp_cfg.c deleted file mode 100644 index 222d0c6..0000000 --- a/keyexchange/isakmpd-20041012/isakmp_cfg.c +++ /dev/null @@ -1,982 +0,0 @@ -/* $OpenBSD: isakmp_cfg.c,v 1.34 2004/08/08 19:11:06 deraadt Exp $ */ - -/* - * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. - * Copyright (c) 2002 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This code was written under funding by Gatespace - * (http://www.gatespace.com/). - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <string.h> -#include <bitstring.h> - -#include "sysdep.h" - -#include "attribute.h" -#include "conf.h" -#include "exchange.h" -#include "hash.h" -#include "ipsec.h" -#include "isakmp_fld.h" -#include "isakmp_num.h" -#include "log.h" -#include "message.h" -#include "prf.h" -#include "sa.h" -#include "transport.h" -#include "util.h" - -/* - * Validation script used to test messages for correct content of - * payloads depending on the exchange type. - */ -int16_t script_transaction[] = { - ISAKMP_PAYLOAD_ATTRIBUTE, /* Initiator -> responder. */ - EXCHANGE_SCRIPT_SWITCH, - ISAKMP_PAYLOAD_ATTRIBUTE, /* Responder -> initiator. */ - EXCHANGE_SCRIPT_END -}; - -static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); -static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t, - u_int32_t, char *, u_int8_t **, u_int16_t *); -static int cfg_initiator_send_ATTR(struct message *); -static int cfg_initiator_recv_ATTR(struct message *); -static int cfg_responder_recv_ATTR(struct message *); -static int cfg_responder_send_ATTR(struct message *); - -u_int8_t *cfg_add_hash(struct message *); -int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *, - u_int16_t); -int cfg_verify_hash(struct message *); - -/* Server: SET/ACK Client; REQ/REPLY */ -int (*isakmp_cfg_initiator[]) (struct message *) = { - cfg_initiator_send_ATTR, - cfg_initiator_recv_ATTR -}; - -/* Server: REQ/REPLY Client: SET/ACK */ -int (*isakmp_cfg_responder[]) (struct message *) = { - cfg_responder_recv_ATTR, - cfg_responder_send_ATTR -}; - -/* - * When we are "the server", this starts SET/ACK mode - * When we are "the client", this starts REQ/REPLY mode - */ -static int -cfg_initiator_send_ATTR(struct message *msg) -{ - struct sa *isakmp_sa = msg->isakmp_sa; - struct ipsec_exch *ie = msg->exchange->data; - u_int8_t *hashp = 0, *attrp, *attr; - size_t attrlen, off; - char *id_string, *cfg_mode, *field; - struct sockaddr *sa; -#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN /* XXX */ - bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX); - u_int16_t bit, length; - u_int32_t life; - - if (msg->exchange->phase == 2) { - hashp = cfg_add_hash(msg); - if (!hashp) - return -1; - } - /* We initiated this exchange, check isakmp_sa for other side. */ - if (isakmp_sa->initiator) - id_string = ipsec_id_string(isakmp_sa->id_r, - isakmp_sa->id_r_len); - else - id_string = ipsec_id_string(isakmp_sa->id_i, - isakmp_sa->id_i_len); - if (!id_string) { - log_print("cfg_initiator_send_ATTR: cannot parse ID"); - goto fail; - } - /* Check for attribute list to send to the other side */ - attrlen = 0; - bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1); - - cfg_mode = conf_get_str(id_string, "Mode"); - if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) { - /* SET/ACK mode */ - ie->cfg_type = ISAKMP_CFG_SET; - - LOG_DBG((LOG_NEGOTIATION, 10, - "cfg_initiator_send_ATTR: SET/ACK mode")); - -#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \ - { \ - if ((sa = conf_get_address (id_string, STR)) != NULL) \ - switch (sa->sa_family) { \ - case AF_INET: \ - bit_set (attrbits, ATTR4); \ - attrlen += ISAKMP_ATTR_SZ + LEN4; \ - break; \ - case AF_INET6: \ - bit_set (attrbits, ATTR6); \ - attrlen += ISAKMP_ATTR_SZ + LEN6; \ - break; \ - default: \ - break; \ - } \ - free (sa); \ - } while (0) - - /* - * XXX We don't simultaneously support IPv4 and IPv6 - * addresses. - */ - ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4, - ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16); - ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4, - ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16); - ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4, - ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16); - ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4, - ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16); - ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4, - ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16); -#ifdef notyet - ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8, - ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17); -#endif -#undef ATTRFIND - - if (conf_get_str(id_string, "Lifetime")) { - bit_set(attrbits, - ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); - attrlen += ISAKMP_ATTR_SZ + 4; - } - } else { - struct conf_list *alist; - struct conf_list_node *anode; - - ie->cfg_type = ISAKMP_CFG_REQUEST; - - LOG_DBG((LOG_NEGOTIATION, 10, - "cfg_initiator_send_ATTR: REQ/REPLY mode")); - - alist = conf_get_list(id_string, "Attributes"); - if (alist) { - for (anode = TAILQ_FIRST(&alist->fields); anode; - anode = TAILQ_NEXT(anode, link)) { - if (strcasecmp(anode->field, "Address") == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS); - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS); - attrlen += ISAKMP_ATTR_SZ * 2; - } else if (strcasecmp(anode->field, "Netmask") - == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK); - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK); - attrlen += ISAKMP_ATTR_SZ * 2; - } else if (strcasecmp(anode->field, - "Nameserver") == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS); - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS); - attrlen += ISAKMP_ATTR_SZ * 2; - } else if (strcasecmp(anode->field, - "WINS-server") == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS); - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS); - attrlen += ISAKMP_ATTR_SZ * 2; - } else if (strcasecmp(anode->field, - "DHCP-server") == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP); - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP); - attrlen += ISAKMP_ATTR_SZ * 2; - } else if (strcasecmp(anode->field, - "Lifetime") == 0) { - bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); - attrlen += ISAKMP_ATTR_SZ; - } else { - log_print("cfg_initiator_send_ATTR: " - "unknown attribute %.20s in " - "section [%s]", anode->field, - id_string); - } - } - - conf_free_list(alist); - } - } - - if (attrlen == 0) { - /* No data found. */ - log_print("cfg_initiator_send_ATTR: no IKECFG attributes " - "found for [%s]", id_string); - - /* - * We can continue, but this indicates a configuration error - * that the user probably will want to correct. - */ - free(id_string); - return 0; - } - attrlen += ISAKMP_ATTRIBUTE_SZ; - attrp = calloc(1, attrlen); - if (!attrp) { - log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed", - (unsigned long)attrlen); - goto fail; - } - if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, - 1)) { - free(attrp); - goto fail; - } - SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type); - getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id); - SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id); - - off = ISAKMP_ATTRIBUTE_SZ; - - /* - * Use the bitstring built previously to collect the right - * parameters for attrp. - */ - for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++) - if (bit_test(attrbits, bit)) { - attr = attrp + off; - SET_ISAKMP_ATTR_TYPE(attr, bit); - - if (ie->cfg_type == ISAKMP_CFG_REQUEST) { - off += ISAKMP_ATTR_SZ; - continue; - } - /* All the other are similar, this is the odd one. */ - if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) { - life = conf_get_num(id_string, "Lifetime", - 1200); - SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4); - encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life); - off += ISAKMP_ATTR_SZ + 4; - continue; - } - switch (bit) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - length = 4; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - length = 16; - break; - - default: - length = 0; /* Silence gcc. */ - } - - switch (bit) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - field = "Address"; - break; - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - field = "Netmask"; - break; - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - field = "Nameserver"; - break; - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - field = "DHCP-server"; - break; - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - field = "WINS-server"; - break; - default: - field = 0; /* Silence gcc. */ - } - - sa = conf_get_address(id_string, field); - - SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length); - memcpy(attr + ISAKMP_ATTR_VALUE_OFF, - sockaddr_addrdata(sa), length); - - free(sa); - - off += ISAKMP_ATTR_SZ + length; - } - if (msg->exchange->phase == 2) - if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) - goto fail; - - return 0; - -fail: - if (id_string) - free(id_string); - return -1; -} - -/* - * As "the server", this ends SET/ACK. - * As "the client", this ends REQ/REPLY. - */ -static int -cfg_initiator_recv_ATTR(struct message *msg) -{ - struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); - struct ipsec_exch *ie = msg->exchange->data; - struct sa *isakmp_sa = msg->isakmp_sa; - struct isakmp_cfg_attr *attr; - struct sockaddr *sa; - const char *uk_addr = "<unknown>"; - char *addr; - - if (msg->exchange->phase == 2) - if (cfg_verify_hash(msg)) - return -1; - - /* Sanity. */ - if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) { - log_print("cfg_initiator_recv_ATTR: " - "cfg packet ID does not match!"); - message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); - return -1; - } - switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) { - case ISAKMP_CFG_ACK: - if (ie->cfg_type != ISAKMP_CFG_SET) { - log_print("cfg_initiator_recv_ATTR: " - "bad packet type ACK"); - message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, - 0, 1, 0); - return -1; - } - break; - case ISAKMP_CFG_REPLY: - if (ie->cfg_type != ISAKMP_CFG_REQUEST) { - log_print("cfg_initiator_recv_ATTR: " - "bad packet type REPLY"); - message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, - 0, 1, 0); - return -1; - } - break; - - default: - log_print("cfg_initiator_recv_ATTR: unexpected configuration " - "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]); - message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); - return -1; - } - - attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, - GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, - cfg_decode_attribute, ie); - - switch (ie->cfg_type) { - case ISAKMP_CFG_ACK: { - /* SET/ACK -- Server side (ACK from client) */ - msg->transport->vtbl->get_src(isakmp_sa->transport, - &sa); - if (sockaddr2text(sa, &addr, 0) < 0) - addr = (char *) uk_addr; - - for (attr = LIST_FIRST(&ie->attrs); attr; - attr = LIST_NEXT(attr, link)) - LOG_DBG((LOG_NEGOTIATION, 50, - "cfg_initiator_recv_ATTR: " - "client %s ACKs attribute %s", addr, - constant_name(isakmp_cfg_attr_cst, - attr->type))); - - if (addr != uk_addr) - free(addr); - } - break; - - case ISAKMP_CFG_REPLY: { - /* - * REQ/REPLY: effect attributes we've gotten - * responses on. - */ - msg->transport->vtbl->get_src(isakmp_sa->transport, - &sa); - if (sockaddr2text(sa, &addr, 0) < 0) - addr = (char *) uk_addr; - - for (attr = LIST_FIRST(&ie->attrs); attr; - attr = LIST_NEXT(attr, link)) - LOG_DBG((LOG_NEGOTIATION, 50, - "cfg_initiator_recv_ATTR: " - "server %s replied with attribute %s", - addr, constant_name(isakmp_cfg_attr_cst, - attr->type))); - - if (addr != uk_addr) - free(addr); - } - break; - - default: - break; - } - - attrp->flags |= PL_MARK; - return 0; -} - -/* - * As "the server", this starts REQ/REPLY (initiated by the client). - * As "the client", this starts SET/ACK (initiated by the server). - */ -static int -cfg_responder_recv_ATTR(struct message *msg) -{ - struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); - struct ipsec_exch *ie = msg->exchange->data; - struct sa *isakmp_sa = msg->isakmp_sa; - struct isakmp_cfg_attr *attr; - struct sockaddr *sa; - char *addr; - - if (msg->exchange->phase == 2) - if (cfg_verify_hash(msg)) - return -1; - - ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p); - ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]; - - switch (ie->cfg_type) { - case ISAKMP_CFG_REQUEST: - case ISAKMP_CFG_SET: - break; - - default: - message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); - log_print("cfg_responder_recv_ATTR: " - "unexpected configuration message type %d", ie->cfg_type); - return -1; - } - - attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, - GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, - cfg_decode_attribute, ie); - - switch (ie->cfg_type) { - case ISAKMP_CFG_REQUEST: - /* We're done. */ - break; - - case ISAKMP_CFG_SET: { - /* SET/ACK -- Client side (SET from server) */ - const char *uk_addr = "<unknown>"; - - msg->transport->vtbl->get_dst(isakmp_sa->transport, - &sa); - if (sockaddr2text(sa, &addr, 0) < 0) - addr = (char *) uk_addr; - - for (attr = LIST_FIRST(&ie->attrs); attr; - attr = LIST_NEXT(attr, link)) - LOG_DBG((LOG_NEGOTIATION, 50, - "cfg_responder_recv_ATTR: " - "server %s asks us to SET attribute %s", - addr, constant_name(isakmp_cfg_attr_cst, - attr->type))); - - /* - * XXX Here's the place to add code to walk through - * XXX each attribute and send them along to dhclient - * XXX or whatever. Each attribute that we act upon - * XXX (such as setting a netmask), should be marked - * XXX like this for us to send the proper ACK - * XXX response: attr->attr_used++; - */ - - if (addr != uk_addr) - free(addr); - } - break; - - default: - break; - } - - attrp->flags |= PL_MARK; - return 0; -} - -/* - * As "the server", this ends REQ/REPLY mode. - * As "the client", this ends SET/ACK mode. - */ -static int -cfg_responder_send_ATTR(struct message *msg) -{ - struct ipsec_exch *ie = msg->exchange->data; - struct sa *isakmp_sa = msg->isakmp_sa; - u_int8_t *hashp = 0, *attrp; - u_int16_t attrlen; - char *id_string; - - if (msg->exchange->phase == 2) { - hashp = cfg_add_hash(msg); - if (!hashp) - return -1; - } - /* We are responder, check isakmp_sa for other side. */ - if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST)) - id_string = ipsec_id_string(isakmp_sa->id_i, - isakmp_sa->id_i_len); - else - id_string = ipsec_id_string(isakmp_sa->id_r, - isakmp_sa->id_r_len); - if (!id_string) { - log_print("cfg_responder_send_ATTR: cannot parse client's ID"); - return -1; - } - if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ? - ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp, - &attrlen)) { - free(id_string); - return -1; - } - free(id_string); - - if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, - 1)) { - free(attrp); - return -1; - } - if (msg->exchange->phase == 2) - if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) - return -1; - - return 0; -} - -u_int8_t * -cfg_add_hash(struct message *msg) -{ - struct ipsec_sa *isa = msg->isakmp_sa->data; - struct hash *hash = hash_get(isa->hash); - u_int8_t *hashp; - - hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize); - if (!hashp) { - log_error("cfg_add_hash: malloc (%lu) failed", - ISAKMP_HASH_SZ + (unsigned long)hash->hashsize); - return 0; - } - if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp, - ISAKMP_HASH_SZ + hash->hashsize, 1)) { - free(hashp); - return 0; - } - return hashp; -} - -int -cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data, - u_int16_t length) -{ - struct ipsec_sa *isa = msg->isakmp_sa->data; - struct prf *prf; - - prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, - isa->skeyid_len); - if (!prf) - return -1; - - prf->Init(prf->prfctx); - prf->Update(prf->prfctx, msg->exchange->message_id, - ISAKMP_HDR_MESSAGE_ID_LEN); - prf->Update(prf->prfctx, data, length); - prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx); - prf_free(prf); - return 0; -} - -int -cfg_verify_hash(struct message *msg) -{ - struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); - struct ipsec_sa *isa = msg->isakmp_sa->data; - struct prf *prf; - u_int8_t *hash, *comp_hash; - size_t hash_len; - - if (!hashp) { - log_print("cfg_verify_hash: phase 2 message missing HASH"); - message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, - 0, 1, 0); - return -1; - } - hash = hashp->p; - hash_len = GET_ISAKMP_GEN_LENGTH(hash); - comp_hash = malloc(hash_len - ISAKMP_GEN_SZ); - if (!comp_hash) { - log_error("cfg_verify_hash: malloc (%lu) failed", - (unsigned long)hash_len - ISAKMP_GEN_SZ); - return -1; - } - /* Verify hash. */ - prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, - isa->skeyid_len); - if (!prf) { - free(comp_hash); - return -1; - } - prf->Init(prf->prfctx); - prf->Update(prf->prfctx, msg->exchange->message_id, - ISAKMP_HDR_MESSAGE_ID_LEN); - prf->Update(prf->prfctx, hash + hash_len, - msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len); - prf->Final(comp_hash, prf->prfctx); - prf_free(prf); - - if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ) - != 0) { - message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, - 0, 1, 0); - free(comp_hash); - return -1; - } - free(comp_hash); - - /* Mark the HASH as handled. */ - hashp->flags |= PL_MARK; - - /* Mark message authenticated. */ - msg->flags |= MSG_AUTHENTICATED; - - return 0; -} - -/* - * Decode the attribute of type TYPE with a LEN length value pointed to by - * VALUE. VIE is a pointer to the IPsec exchange context holding the - * attributes indexed by type for easy retrieval. - */ -static int -cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, - void *vie) -{ - struct ipsec_exch *ie = vie; - struct isakmp_cfg_attr *attr; - - if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN - && type <= ISAKMP_CFG_ATTR_PRIVATE_MAX) - return 0; - if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) { - LOG_DBG((LOG_NEGOTIATION, 30, - "cfg_decode_attribute: invalid attr type %u", type)); - return -1; - } - attr = calloc(1, sizeof *attr); - if (!attr) { - log_error("cfg_decode_attribute: calloc (1, %lu) failed", - (unsigned long)sizeof *attr); - return -1; - } - attr->type = type; - attr->length = len; - if (len) { - attr->value = malloc(len); - if (!attr->value) { - log_error("cfg_decode_attribute: malloc (%d) failed", - len); - free(attr); - /* Should we also deallocate all other values? */ - return -1; - } - memcpy(attr->value, value, len); - } - LIST_INSERT_HEAD(&ie->attrs, attr, link); - return 0; -} - -/* - * Encode list of attributes from ie->attrs into a attribute payload. - */ -static int -cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type, - u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len) -{ - struct isakmp_cfg_attr *attr; - struct sockaddr *sa; - sa_family_t family; - u_int32_t value; - u_int16_t off; - char *field; - - /* Compute length */ - *len = ISAKMP_ATTRIBUTE_SZ; - for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { - /* With ACK we only include the attrs we've actually used. */ - if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) - continue; - - switch (attr->type) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: - attr->length = 4; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: - attr->length = 8; - break; - - case ISAKMP_CFG_ATTR_APPLICATION_VERSION: - /* XXX So far no version identifier of isakmpd here. */ - attr->length = 0; - break; - - case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: - attr->length = 2 * 15; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - attr->length = 16; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: - attr->length = 17; - break; - - default: - attr->ignore++; - /* XXX Log! */ - } - *len += ISAKMP_ATTR_SZ + attr->length; - } - - /* Allocate enough space for the payload */ - *attrp = calloc(1, *len); - if (!*attrp) { - log_error("cfg_encode_attributes: calloc (1, %lu) failed", - (unsigned long)*len); - return -1; - } - SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type); - SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id); - - off = ISAKMP_ATTRIBUTE_SZ; - for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { - /* With ACK we only include the attrs we've actually used. */ - if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) - continue; - - switch (attr->type) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - family = AF_INET; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - family = AF_INET6; - break; - - default: - family = 0; - break; - } - - switch (attr->type) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - field = "Address"; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: - field = "Network"; /* XXX or just "Address" */ - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - field = "Netmask"; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - field = "DHCP-server"; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - field = "Nameserver"; - break; - - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - field = "WINS-server"; - break; - - default: - field = 0; - } - - switch (attr->type) { - case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: - case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: - sa = conf_get_address(id_string, field); - if (!sa) { - LOG_DBG((LOG_NEGOTIATION, 10, - "cfg_responder_send_ATTR: " - "attribute not found: %s", field)); - attr->length = 0; - break; - } - if (sa->sa_family != family) { - log_print("cfg_responder_send_ATTR: " - "attribute %s - expected %s got %s data", - field, - (family == AF_INET ? "IPv4" : "IPv6"), - (sa->sa_family == - AF_INET ? "IPv4" : "IPv6")); - free(sa); - attr->length = 0; - break; - } - /* Temporary limit length for the _SUBNET types. */ - if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) - attr->length = 4; - else if (attr->type == - ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) - attr->length = 16; - - memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF, - sockaddr_addrdata(sa), attr->length); - free(sa); - - /* _SUBNET types need some extra work. */ - if (attr->type == - ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) { - sa = conf_get_address(id_string, "Netmask"); - if (!sa) { - LOG_DBG((LOG_NEGOTIATION, 10, - "cfg_responder_send_ATTR: " - "attribute not found: Netmask")); - attr->length = 0; - break; - } - if (sa->sa_family != AF_INET) { - log_print("cfg_responder_send_ATTR: " - "attribute Netmask - expected " - "IPv4 got IPv6 data"); - free(sa); - attr->length = 0; - break; - } - memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF + - attr->length, sockaddr_addrdata(sa), - attr->length); - attr->length = 8; - free(sa); - } else if (attr->type == - ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) { - int prefix = conf_get_num(id_string, "Prefix", - -1); - - if (prefix == -1) { - log_print("cfg_responder_send_ATTR: " - "attribute not found: Prefix"); - attr->length = 0; - break; - } else if (prefix < -1 || prefix > 128) { - log_print("cfg_responder_send_ATTR: " - "attribute Prefix - invalid " - "value %d", prefix); - attr->length = 0; - break; - } - *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) = - (u_int8_t)prefix; - attr->length = 17; - } - break; - - case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: - value = conf_get_num(id_string, "Lifetime", 1200); - encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value); - break; - - case ISAKMP_CFG_ATTR_APPLICATION_VERSION: - /* XXX So far no version identifier of isakmpd here. */ - break; - - case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: - break; - - default: - break; - } - - SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type); - SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length); - off += ISAKMP_ATTR_VALUE_OFF + attr->length; - } - - return 0; -} |