summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/isakmp_cfg.c
diff options
context:
space:
mode:
authorOthmar Gsenger <otti@anytun.org>2007-12-08 20:59:57 +0000
committerOthmar Gsenger <otti@anytun.org>2007-12-08 20:59:57 +0000
commitf84dc62cc602eacb0daee3e9918a68b711ba94f0 (patch)
tree1acbdabf30b2ece1da880386da6a4b7c002669c3 /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.c982
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;
-}