summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/ike_phase_1.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/ike_phase_1.c')
-rw-r--r--keyexchange/isakmpd-20041012/ike_phase_1.c1396
1 files changed, 0 insertions, 1396 deletions
diff --git a/keyexchange/isakmpd-20041012/ike_phase_1.c b/keyexchange/isakmpd-20041012/ike_phase_1.c
deleted file mode 100644
index 7f72a25..0000000
--- a/keyexchange/isakmpd-20041012/ike_phase_1.c
+++ /dev/null
@@ -1,1396 +0,0 @@
-/* $OpenBSD: ike_phase_1.c,v 1.56 2004/08/08 19:11:06 deraadt Exp $ */
-/* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */
-
-/*
- * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
- * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
- * Copyright (c) 2001, 2004 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 Ericsson Radio Systems.
- */
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "sysdep.h"
-
-#include "attribute.h"
-#include "conf.h"
-#include "constants.h"
-#include "crypto.h"
-#include "dh.h"
-#include "doi.h"
-#ifdef USE_DPD
-#include "dpd.h"
-#endif
-#include "exchange.h"
-#include "hash.h"
-#include "ike_auth.h"
-#include "ike_phase_1.h"
-#include "ipsec.h"
-#include "ipsec_doi.h"
-#include "isakmp.h"
-#include "log.h"
-#include "math_group.h"
-#include "message.h"
-#if defined (USE_NAT_TRAVERSAL)
-#include "nat_traversal.h"
-#endif
-#include "prf.h"
-#include "sa.h"
-#include "transport.h"
-#include "util.h"
-
-static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t,
- void *);
-static int ike_phase_1_validate_prop(struct exchange *, struct sa *,
- struct sa *);
-
-/* Offer a set of transforms to the responder in the MSG message. */
-int
-ike_phase_1_initiator_send_SA(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr;
- u_int8_t **transform = 0;
- size_t transforms_len = 0, proposal_len, sa_len;
- size_t *transform_len = 0;
- struct conf_list *conf, *life_conf;
- struct conf_list_node *xf, *life;
- int value, update_nextp;
- size_t i;
- struct payload *p;
- struct proto *proto;
- struct proto_attr *pa;
- int group_desc = -1, new_group_desc;
-
- /* Get the list of transforms. */
- conf = conf_get_list(exchange->policy, "Transforms");
- if (!conf)
- return -1;
-
- transform = calloc(conf->cnt, sizeof *transform);
- if (!transform) {
- log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) "
- "failed", (u_long)conf->cnt, (u_long) sizeof *transform);
- goto bail_out;
- }
- transform_len = calloc(conf->cnt, sizeof *transform_len);
- if (!transform_len) {
- log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) "
- "failed", (u_long)conf->cnt,
- (u_long) sizeof *transform_len);
- goto bail_out;
- }
- for (xf = TAILQ_FIRST(&conf->fields), i = 0; i < conf->cnt;
- i++, xf = TAILQ_NEXT(xf, link)) {
- /* XXX The sizing needs to be dynamic. */
- transform[i] = malloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF +
- 16 * ISAKMP_ATTR_VALUE_OFF);
- if (!transform[i]) {
- log_error("ike_phase_1_initiator_send_SA: malloc (%d) "
- "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF +
- 16 * ISAKMP_ATTR_VALUE_OFF);
- goto bail_out;
- }
- SET_ISAKMP_TRANSFORM_NO(transform[i], i);
- SET_ISAKMP_TRANSFORM_ID(transform[i], IPSEC_TRANSFORM_KEY_IKE);
- SET_ISAKMP_TRANSFORM_RESERVED(transform[i], 0);
-
- attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;
-
- if (attribute_set_constant(xf->field, "ENCRYPTION_ALGORITHM",
- ike_encrypt_cst, IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
- goto bail_out;
-
- if (attribute_set_constant(xf->field, "HASH_ALGORITHM",
- ike_hash_cst, IKE_ATTR_HASH_ALGORITHM, &attr))
- goto bail_out;
-
- if (attribute_set_constant(xf->field, "AUTHENTICATION_METHOD",
- ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD, &attr))
- goto bail_out;
-
- if (attribute_set_constant(xf->field, "GROUP_DESCRIPTION",
- ike_group_desc_cst, IKE_ATTR_GROUP_DESCRIPTION, &attr)) {
- /*
- * If no group description exists, try looking for
- * a user-defined one.
- */
- if (attribute_set_constant(xf->field, "GROUP_TYPE",
- ike_group_cst, IKE_ATTR_GROUP_TYPE, &attr))
- goto bail_out;
-
-#if 0
- if (attribute_set_bignum(xf->field, "GROUP_PRIME",
- IKE_ATTR_GROUP_PRIME, &attr))
- goto bail_out;
-
- if (attribute_set_bignum(xf->field,
- "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2,
- &attr))
- goto bail_out;
-
- if (attribute_set_bignum(xf->field,
- "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2,
- &attr))
- goto bail_out;
-
- if (attribute_set_bignum(xf->field, "GROUP_CURVE_A",
- IKE_ATTR_GROUP_CURVE_A, &attr))
- goto bail_out;
-
- if (attribute_set_bignum(xf->field, "GROUP_CURVE_B",
- IKE_ATTR_GROUP_CURVE_B, &attr))
- goto bail_out;
-#endif
- }
- /*
- * Life durations are special, we should be able to specify
- * several, one per type.
- */
- life_conf = conf_get_list(xf->field, "Life");
- if (life_conf) {
- for (life = TAILQ_FIRST(&life_conf->fields); life;
- life = TAILQ_NEXT(life, link)) {
- attribute_set_constant(life->field,
- "LIFE_TYPE", ike_duration_cst,
- IKE_ATTR_LIFE_TYPE, &attr);
-
- /*
- * XXX Deals with 16 and 32 bit lifetimes
- * only
- */
- value = conf_get_num(life->field,
- "LIFE_DURATION", 0);
- if (value) {
- if (value <= 0xffff)
- attr = attribute_set_basic(
- attr,
- IKE_ATTR_LIFE_DURATION,
- value);
- else {
- value = htonl(value);
- attr = attribute_set_var(attr,
- IKE_ATTR_LIFE_DURATION,
- (u_int8_t *)&value,
- sizeof value);
- }
- }
- }
- conf_free_list(life_conf);
- }
- attribute_set_constant(xf->field, "PRF", ike_prf_cst,
- IKE_ATTR_PRF, &attr);
-
- value = conf_get_num(xf->field, "KEY_LENGTH", 0);
- if (value)
- attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH,
- value);
-
- value = conf_get_num(xf->field, "FIELD_SIZE", 0);
- if (value)
- attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE,
- value);
-
- value = conf_get_num(xf->field, "GROUP_ORDER", 0);
- if (value)
- attr = attribute_set_basic(attr, IKE_ATTR_GROUP_ORDER,
- value);
-
- /* Record the real transform size. */
- transforms_len += transform_len[i] = attr - transform[i];
-
- /* XXX I don't like exchange-specific stuff in here. */
- if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) {
- /*
- * Make sure that if a group description is specified,
- * it is specified for all transforms equally.
- */
- attr = (u_int8_t *) conf_get_str(xf->field,
- "GROUP_DESCRIPTION");
- new_group_desc =
- attr ? constant_value(ike_group_desc_cst,
- (char *) attr) : 0;
- if (group_desc == -1)
- group_desc = new_group_desc;
- else if (group_desc != new_group_desc) {
- log_print("ike_phase_1_initiator_send_SA: "
- "differing group descriptions in a "
- "proposal");
- goto bail_out;
- }
- }
- /*
- * We need to check that we actually support our
- * configuration.
- */
- if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
- transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
- exchange->doi->is_attribute_incompatible, msg)) {
- log_print("ike_phase_1_initiator_send_SA: "
- "section [%s] has unsupported attribute(s)",
- xf->field);
- goto bail_out;
- }
- }
-
- /* XXX I don't like exchange-specific stuff in here. */
- if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
- ie->group = group_get(group_desc);
-
- proposal_len = ISAKMP_PROP_SPI_OFF;
- proposal = malloc(proposal_len);
- if (!proposal) {
- log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
- (unsigned long) proposal_len);
- goto bail_out;
- }
- SET_ISAKMP_PROP_NO(proposal, 1);
- SET_ISAKMP_PROP_PROTO(proposal, ISAKMP_PROTO_ISAKMP);
- SET_ISAKMP_PROP_SPI_SZ(proposal, 0);
- SET_ISAKMP_PROP_NTRANSFORMS(proposal, conf->cnt);
-
- /* XXX I would like to see this factored out. */
- proto = calloc(1, sizeof *proto);
- if (!proto) {
- log_error("ike_phase_1_initiator_send_SA: "
- "calloc (1, %lu) failed", (unsigned long) sizeof *proto);
- goto bail_out;
- }
- proto->no = 1;
- proto->proto = ISAKMP_PROTO_ISAKMP;
- proto->sa = TAILQ_FIRST(&exchange->sa_list);
- proto->xf_cnt = conf->cnt;
- TAILQ_INIT(&proto->xfs);
- for (i = 0; i < proto->xf_cnt; i++) {
- pa = (struct proto_attr *) calloc(1, sizeof *pa);
- if (!pa)
- goto bail_out;
- pa->len = transform_len[i];
- pa->attrs = (u_int8_t *) malloc(pa->len);
- if (!pa->attrs) {
- free(pa);
- goto bail_out;
- }
- memcpy(pa->attrs, transform[i], pa->len);
- TAILQ_INSERT_TAIL(&proto->xfs, pa, next);
- }
- TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto,
- link);
-
- sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
- sa_buf = malloc(sa_len);
- if (!sa_buf) {
- log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
- (unsigned long) sa_len);
- goto bail_out;
- }
- SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC);
- SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);
-
- /*
- * Add the payloads. As this is a SA, we need to recompute the
- * lengths of the payloads containing others.
- */
- if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
- goto bail_out;
- SET_ISAKMP_GEN_LENGTH(sa_buf,
- sa_len + proposal_len + transforms_len);
- sa_buf = 0;
-
- saved_nextp = msg->nextp;
- if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
- proposal_len, 0))
- goto bail_out;
- SET_ISAKMP_GEN_LENGTH(proposal, proposal_len + transforms_len);
- proposal = 0;
-
- update_nextp = 0;
- for (i = 0; i < conf->cnt; i++) {
- if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM,
- transform[i], transform_len[i], update_nextp))
- goto bail_out;
- update_nextp = 1;
- transform[i] = 0;
- }
- msg->nextp = saved_nextp;
-
- /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */
- ie->sa_i_b_len = sa_len + proposal_len + transforms_len -
- ISAKMP_GEN_SZ;
- ie->sa_i_b = malloc(ie->sa_i_b_len);
- if (!ie->sa_i_b) {
- log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
- (unsigned long) ie->sa_i_b_len);
- goto bail_out;
- }
- memcpy(ie->sa_i_b,
- payload_first(msg, ISAKMP_PAYLOAD_SA)->p + ISAKMP_GEN_SZ,
- sa_len - ISAKMP_GEN_SZ);
- memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
- payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL)->p, proposal_len);
- transforms_len = 0;
- for (i = 0, p = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM);
- i < conf->cnt; i++, p = TAILQ_NEXT(p, link)) {
- memcpy(ie->sa_i_b + sa_len + proposal_len + transforms_len -
- ISAKMP_GEN_SZ, p->p, transform_len[i]);
- transforms_len += transform_len[i];
- }
-
-#if defined (USE_NAT_TRAVERSAL)
- /* Advertise NAT-T capability. */
- if (nat_t_add_vendor_payloads(msg))
- goto bail_out;
-#endif
-
-#if defined (USE_DPD)
- /* Advertise DPD capability. */
- if (dpd_add_vendor_payload(msg))
- goto bail_out;
-#endif
-
- conf_free_list(conf);
- free(transform);
- free(transform_len);
- return 0;
-
-bail_out:
- if (sa_buf)
- free(sa_buf);
- if (proposal)
- free(proposal);
- if (transform) {
- for (i = 0; i < conf->cnt; i++)
- if (transform[i])
- free(transform[i]);
- free(transform);
- }
- if (transform_len)
- free(transform_len);
- conf_free_list(conf);
- return -1;
-}
-
-/* Figure out what transform the responder chose. */
-int
-ike_phase_1_initiator_recv_SA(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct sa *sa = TAILQ_FIRST(&exchange->sa_list);
- struct ipsec_exch *ie = exchange->data;
- struct ipsec_sa *isa = sa->data;
- struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA);
- struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL);
- struct payload *xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM);
-
- /*
- * IKE requires that only one SA with only one proposal exists and
- * since we are getting an answer on our transform offer, only one
- * transform.
- */
- if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link) ||
- TAILQ_NEXT(xf, link)) {
- log_print("ike_phase_1_initiator_recv_SA: "
- "multiple SA, proposal or transform payloads in phase 1");
- /* XXX Is there a better notification type? */
- message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
- return -1;
- }
- /* Check that the chosen transform matches an offer. */
- if (message_negotiate_sa(msg, ike_phase_1_validate_prop) ||
- !TAILQ_FIRST(&sa->protos))
- return -1;
-
- ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos), xf->p);
-
- /* XXX I don't like exchange-specific stuff in here. */
- if (exchange->type != ISAKMP_EXCH_AGGRESSIVE)
- ie->group = group_get(isa->group_desc);
-
- /* Mark the SA as handled. */
- sa_p->flags |= PL_MARK;
-
- return 0;
-}
-
-/* Send our public DH value and a nonce to the responder. */
-int
-ike_phase_1_initiator_send_KE_NONCE(struct message *msg)
-{
- struct ipsec_exch *ie = msg->exchange->data;
-
- ie->g_x_len = dh_getlen(ie->group);
-
- /* XXX I want a better way to specify the nonce's size. */
- return ike_phase_1_send_KE_NONCE(msg, 16);
-}
-
-/* Accept responder's public DH value and nonce. */
-int
-ike_phase_1_initiator_recv_KE_NONCE(struct message *msg)
-{
- if (ike_phase_1_recv_KE_NONCE(msg))
- return -1;
-
- return ike_phase_1_post_exchange_KE_NONCE(msg);
-}
-
-/*
- * Accept a set of transforms offered by the initiator and chose one we can
- * handle.
- */
-int
-ike_phase_1_responder_recv_SA(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct sa *sa = TAILQ_FIRST(&exchange->sa_list);
- struct ipsec_sa *isa = sa->data;
- struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA);
- struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL);
- struct ipsec_exch *ie = exchange->data;
-
- /* Mark the SA as handled. */
- sa_p->flags |= PL_MARK;
-
- /* IKE requires that only one SA with only one proposal exists. */
- if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link)) {
- log_print("ike_phase_1_responder_recv_SA: "
- "multiple SA or proposal payloads in phase 1");
- /* XXX Is there a better notification type? */
- message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
- return -1;
- }
- /* Chose a transform from the SA. */
- if (message_negotiate_sa(msg, ike_phase_1_validate_prop) ||
- !TAILQ_FIRST(&sa->protos))
- return -1;
-
- /* XXX Move into message_negotiate_sa? */
- ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos),
- TAILQ_FIRST(&sa->protos)->chosen->p);
-
- ie->group = group_get(isa->group_desc);
-
- /*
- * Check that the mandatory attributes: encryption, hash,
- * authentication method and Diffie-Hellman group description, has
- * been supplied.
- */
- if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group) {
- message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
- return -1;
- }
- /* Save the body for later hash computation. */
- ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH(sa_p->p) - ISAKMP_GEN_SZ;
- ie->sa_i_b = malloc(ie->sa_i_b_len);
- if (!ie->sa_i_b) {
- /* XXX How to notify peer? */
- log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed",
- (unsigned long) ie->sa_i_b_len);
- return -1;
- }
- memcpy(ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ, ie->sa_i_b_len);
- return 0;
-}
-
-/* Reply with the transform we chose. */
-int
-ike_phase_1_responder_send_SA(struct message *msg)
-{
- /* Add the SA payload with the transform that was chosen. */
- if (message_add_sa_payload(msg))
- return -1;
-
-#if defined (USE_NAT_TRAVERSAL)
- /* Advertise NAT-T capability. */
- if (nat_t_add_vendor_payloads(msg))
- return -1;
-#endif
-
-#if defined (USE_DPD)
- /* Advertise DPD capability. */
- if (dpd_add_vendor_payload(msg))
- return -1;
-#endif
- return 0;
-}
-
-/* Send our public DH value and a nonce to the peer. */
-int
-ike_phase_1_send_KE_NONCE(struct message *msg, size_t nonce_sz)
-{
- /* Public DH key. */
- if (ipsec_gen_g_x(msg)) {
- /* XXX How to log and notify peer? */
- return -1;
- }
- /* Generate a nonce, and add it to the message. */
- if (exchange_gen_nonce(msg, nonce_sz)) {
- /* XXX Log? */
- return -1;
- }
- /* Try to add certificates which are acceptable for the CERTREQs */
- if (exchange_add_certs(msg)) {
- /* XXX Log? */
- return -1;
- }
-#if defined (USE_NAT_TRAVERSAL)
- /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */
- if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER)
- if (nat_t_exchange_add_nat_d(msg)) {
- /* XXX Log? */
- return -1;
- }
-#endif
- return 0;
-}
-
-/* Receive our peer's public DH value and nonce. */
-int
-ike_phase_1_recv_KE_NONCE(struct message *msg)
-{
- /* Copy out the initiator's DH public value. */
- if (ipsec_save_g_x(msg)) {
- /* XXX How to log and notify peer? */
- return -1;
- }
- /* Copy out the initiator's nonce. */
- if (exchange_save_nonce(msg)) {
- /* XXX How to log and notify peer? */
- return -1;
- }
- /* Copy out the initiator's cert requests. */
- if (exchange_save_certreq(msg)) {
- /* XXX How to log and notify peer? */
- return -1;
- }
-#if defined (USE_NAT_TRAVERSAL)
- /* MainMode: Check for NAT-D payloads and contents. */
- if (msg->exchange->type == ISAKMP_EXCH_ID_PROT &&
- msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER)
- (void)nat_t_exchange_check_nat_d(msg);
-#endif
- return 0;
-}
-
-/*
- * Compute DH values and key material. This is done in a post-send function
- * as that means we can do parallel work in both the initiator and responder
- * thus speeding up exchanges.
- */
-int
-ike_phase_1_post_exchange_KE_NONCE(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- struct prf *prf;
- struct hash *hash = ie->hash;
- enum cryptoerr err;
-
- /* Compute Diffie-Hellman shared value. */
- ie->g_xy = malloc(ie->g_x_len);
- if (!ie->g_xy) {
- /* XXX How to notify peer? */
- log_error("ike_phase_1_post_exchange_KE_NONCE: "
- "malloc (%lu) failed", (unsigned long) ie->g_x_len);
- return -1;
- }
- if (dh_create_shared(ie->group, ie->g_xy,
- exchange->initiator ? ie->g_xr : ie->g_xi)) {
- log_print("ike_phase_1_post_exchange_KE_NONCE: "
- "dh_create_shared failed");
- return -1;
- }
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy,
- ie->g_x_len));
-
- /* Compute the SKEYID depending on the authentication method. */
- ie->skeyid = ie->ike_auth->gen_skeyid(exchange, &ie->skeyid_len);
- if (!ie->skeyid) {
- /* XXX Log and teardown? */
- return -1;
- }
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid,
- ie->skeyid_len));
-
- /* SKEYID_d. */
- ie->skeyid_d = malloc(ie->skeyid_len);
- if (!ie->skeyid_d) {
- /* XXX How to notify peer? */
- log_error("ike_phase_1_post_exchange_KE_NONCE: "
- "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
- return -1;
- }
- prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
- if (!prf) {
- /* XXX Log and teardown? */
- return -1;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
- prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
- prf->Update(prf->prfctx, (unsigned char *) "\0", 1);
- prf->Final(ie->skeyid_d, prf->prfctx);
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d,
- ie->skeyid_len));
-
- /* SKEYID_a. */
- ie->skeyid_a = malloc(ie->skeyid_len);
- if (!ie->skeyid_a) {
- log_error("ike_phase_1_post_exchange_KE_NONCE: "
- "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
- prf_free(prf);
- return -1;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, ie->skeyid_d, ie->skeyid_len);
- prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
- prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
- prf->Update(prf->prfctx, (unsigned char *) "\1", 1);
- prf->Final(ie->skeyid_a, prf->prfctx);
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a,
- ie->skeyid_len));
-
- /* SKEYID_e. */
- ie->skeyid_e = malloc(ie->skeyid_len);
- if (!ie->skeyid_e) {
- /* XXX How to notify peer? */
- log_error("ike_phase_1_post_exchange_KE_NONCE: "
- "malloc (%lu) failed", (unsigned long) ie->skeyid_len);
- prf_free(prf);
- return -1;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, ie->skeyid_a, ie->skeyid_len);
- prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
- prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
- prf->Update(prf->prfctx, (unsigned char *) "\2", 1);
- prf->Final(ie->skeyid_e, prf->prfctx);
- prf_free(prf);
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e,
- ie->skeyid_len));
-
- /* Key length determination. */
- if (!exchange->key_length)
- exchange->key_length = exchange->crypto->keymax;
-
- /* Derive a longer key from skeyid_e */
- if (ie->skeyid_len < exchange->key_length) {
- u_int16_t len, keylen;
- u_int8_t *key, *p;
-
- prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid_e,
- ie->skeyid_len);
- if (!prf) {
- /* XXX - notify peer */
- return -1;
- }
- /* Make keylen a multiple of prf->blocksize */
- keylen = exchange->key_length;
- if (keylen % prf->blocksize)
- keylen += prf->blocksize - (keylen % prf->blocksize);
-
- key = malloc(keylen);
- if (!key) {
- /* XXX - Notify peer. */
- log_error("ike_phase_1_post_exchange_KE_NONCE: "
- "malloc (%d) failed", keylen);
- return -1;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, (unsigned char *) "\0", 1);
- prf->Final(key, prf->prfctx);
-
- for (len = prf->blocksize, p = key; len < exchange->key_length;
- len += prf->blocksize, p += prf->blocksize) {
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, p, prf->blocksize);
- prf->Final(p + prf->blocksize, prf->prfctx);
- }
- prf_free(prf);
-
- /* Setup our keystate using the derived encryption key. */
- exchange->keystate = crypto_init(exchange->crypto, key,
- exchange->key_length, &err);
-
- free(key);
- } else
- /* Setup our keystate using the raw skeyid_e. */
- exchange->keystate = crypto_init(exchange->crypto,
- ie->skeyid_e, exchange->key_length, &err);
-
- /* Special handling for DES weak keys. */
- if (!exchange->keystate && err == EWEAKKEY &&
- (exchange->key_length << 1) <= ie->skeyid_len) {
- log_print("ike_phase_1_post_exchange_KE_NONCE: "
- "weak key, trying subseq. skeyid_e");
- exchange->keystate = crypto_init(exchange->crypto,
- ie->skeyid_e + exchange->key_length,
- exchange->key_length, &err);
- }
- if (!exchange->keystate) {
- log_print("ike_phase_1_post_exchange_KE_NONCE: "
- "exchange->crypto->init () failed: %d", err);
-
- /*
- * XXX We really need to know if problems are of transient
- * nature or fatal (like failed assertions etc.)
- */
- return -1;
- }
- /* Setup IV. XXX Only for CBC transforms, no? */
- hash->Init(hash->ctx);
- hash->Update(hash->ctx, ie->g_xi, ie->g_x_len);
- hash->Update(hash->ctx, ie->g_xr, ie->g_x_len);
- hash->Final(hash->digest, hash->ctx);
- crypto_init_iv(exchange->keystate, hash->digest,
- exchange->crypto->blocksize);
- return 0;
-}
-
-int
-ike_phase_1_responder_send_ID_AUTH(struct message *msg)
-{
- if (ike_phase_1_send_ID(msg))
- return -1;
-
- return ike_phase_1_send_AUTH(msg);
-}
-
-int
-ike_phase_1_send_ID(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- u_int8_t *buf;
- char header[80];
- ssize_t sz;
- struct sockaddr *src;
- int initiator = exchange->initiator;
- u_int8_t **id;
- size_t *id_len;
- char *my_id = 0, *data;
- u_int8_t id_type;
-
- /* Choose the right fields to fill-in. */
- id = initiator ? &exchange->id_i : &exchange->id_r;
- id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len;
-
- if (exchange->name)
- my_id = conf_get_str(exchange->name, "ID");
-
- if (!my_id)
- my_id = conf_get_str("General", "Default-phase-1-ID");
-
- msg->transport->vtbl->get_src(msg->transport, &src);
- sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src);
- if (sz == -1)
- return -1;
-
- sz += ISAKMP_ID_DATA_OFF;
- buf = malloc(sz);
- if (!buf) {
- log_error("ike_phase_1_send_ID: malloc (%lu) failed",
- (unsigned long) sz);
- return -1;
- }
- SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
- SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
- if (my_id) {
- SET_ISAKMP_ID_TYPE(buf, id_type);
- switch (id_type) {
- case IPSEC_ID_IPV4_ADDR:
- case IPSEC_ID_IPV6_ADDR:
- /* Already in network byteorder. */
- memcpy(buf + ISAKMP_ID_DATA_OFF,
- sockaddr_addrdata(src), sockaddr_addrlen(src));
- break;
-
- case IPSEC_ID_IPV4_ADDR_SUBNET:
- case IPSEC_ID_IPV6_ADDR_SUBNET:
- /* Network */
- data = conf_get_str(my_id, "Network");
- if (!data) {
- log_print("ike_phase_1_send_ID: section %s "
- "has no \"Network\" tag", my_id);
- return -1;
- }
- if (text2sockaddr(data, NULL, &src)) {
- log_error("ike_phase_1_send_ID: "
- "text2sockaddr() failed");
- return -1;
- }
- memcpy(buf + ISAKMP_ID_DATA_OFF,
- sockaddr_addrdata(src), sockaddr_addrlen(src));
- free(src);
- /* Netmask */
- data = conf_get_str(my_id, "Netmask");
- if (!data) {
- log_print("ike_phase_1_send_ID: section %s "
- "has no \"Netmask\" tag", my_id);
- return -1;
- }
- if (text2sockaddr(data, NULL, &src)) {
- log_error("ike_phase_1_send_ID: "
- "text2sockaddr() failed");
- return -1;
- }
- memcpy(buf + ISAKMP_ID_DATA_OFF +
- sockaddr_addrlen(src), sockaddr_addrdata(src),
- sockaddr_addrlen(src));
- free(src);
- break;
-
- case IPSEC_ID_FQDN:
- case IPSEC_ID_USER_FQDN:
- case IPSEC_ID_KEY_ID:
- data = conf_get_str(my_id, "Name");
- if (!data) {
- log_print("ike_phase_1_send_ID: section %s "
- "has no \"Name\" tag", my_id);
- return -1;
- }
- memcpy(buf + ISAKMP_ID_DATA_OFF, data,
- sz - ISAKMP_ID_DATA_OFF);
- break;
-
- default:
- log_print("ike_phase_1_send_ID: "
- "unsupported ID type %d", id_type);
- free(buf);
- return -1;
- }
- } else {
- switch (src->sa_family) {
- case AF_INET:
- SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR);
- break;
- case AF_INET6:
- SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR);
- break;
- }
- /* Already in network byteorder. */
- memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src),
- sockaddr_addrlen(src));
- }
-
- if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) {
- free(buf);
- return -1;
- }
- *id_len = sz - ISAKMP_GEN_SZ;
- *id = malloc(*id_len);
- if (!*id) {
- log_error("ike_phase_1_send_ID: malloc (%lu) failed",
- (unsigned long) *id_len);
- return -1;
- }
- memcpy(*id, buf + ISAKMP_GEN_SZ, *id_len);
- snprintf(header, sizeof header, "ike_phase_1_send_ID: %s",
- constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf)));
- LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,
- sz - ISAKMP_ID_DATA_OFF));
- return 0;
-}
-
-int
-ike_phase_1_send_AUTH(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
-
- if (ie->ike_auth->encode_hash(msg)) {
- /* XXX Log? */
- return -1;
- }
- /*
- * XXX Many people say the COMMIT flag is just junk, especially in
- * Phase 1.
- */
-#ifdef notyet
- if ((exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0)
- exchange->flags |= EXCHANGE_FLAG_I_COMMITTED;
-#endif
-
- return 0;
-}
-
-/* Receive ID and HASH and check that the exchange has been consistent. */
-int
-ike_phase_1_recv_ID_AUTH(struct message *msg)
-{
- if (ike_phase_1_recv_ID(msg))
- return -1;
-
- return ike_phase_1_recv_AUTH(msg);
-}
-
-/* Receive ID. */
-int
-ike_phase_1_recv_ID(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct payload *payload;
- char header[80], *rs = 0, *rid = 0, *p;
- int initiator = exchange->initiator;
- u_int8_t **id, id_type;
- size_t *id_len;
- ssize_t sz;
- struct sockaddr *sa;
-
- payload = payload_first(msg, ISAKMP_PAYLOAD_ID);
-
- if (exchange->name)
- rs = conf_get_str(exchange->name, "Remote-ID");
-
- if (rs) {
- sz = ipsec_id_size(rs, &id_type);
- if (sz == -1) {
- log_print("ike_phase_1_recv_ID: could not handle "
- "specified Remote-ID [%s]", rs);
- return -1;
- }
- rid = malloc(sz);
- if (!rid) {
- log_error("ike_phase_1_recv_ID: malloc (%lu) failed",
- (unsigned long) sz);
- return -1;
- }
- switch (id_type) {
- case IPSEC_ID_IPV4_ADDR:
- case IPSEC_ID_IPV6_ADDR:
- p = conf_get_str(rs, "Address");
- if (!p) {
- log_print("ike_phase_1_recv_ID: failed to get "
- "Address in Remote-ID section [%s]", rs);
- free(rid);
- return -1;
- }
- if (text2sockaddr(p, 0, &sa) == -1) {
- log_print("ike_phase_1_recv_ID: "
- "failed to parse address %s", p);
- free(rid);
- return -1;
- }
- if ((id_type == IPSEC_ID_IPV4_ADDR &&
- sa->sa_family != AF_INET) ||
- (id_type == IPSEC_ID_IPV6_ADDR &&
- sa->sa_family != AF_INET6)) {
- log_print("ike_phase_1_recv_ID: "
- "address %s not of expected family", p);
- free(rid);
- free(sa);
- return -1;
- }
- memcpy(rid, sockaddr_addrdata(sa),
- sockaddr_addrlen(sa));
- free(sa);
- break;
-
- case IPSEC_ID_FQDN:
- case IPSEC_ID_USER_FQDN:
- case IPSEC_ID_KEY_ID:
- p = conf_get_str(rs, "Name");
- if (!p) {
- log_print("ike_phase_1_recv_ID: failed to "
- "get Name in Remote-ID section [%s]", rs);
- free(rid);
- return -1;
- }
- memcpy(rid, p, sz);
- break;
-
- default:
- log_print("ike_phase_1_recv_ID: "
- "unsupported ID type %d", id_type);
- free(rid);
- return -1;
- }
-
- /* Compare expected/desired and received remote ID */
- if (bcmp(rid, payload->p + ISAKMP_ID_DATA_OFF, sz)) {
- log_print("ike_phase_1_recv_ID: "
- "received remote ID other than expected %s - %s", p, payload->p);
- free(rid);
- return -1;
- }
- free(rid);
- }
- /* Choose the right fields to fill in */
- id = initiator ? &exchange->id_r : &exchange->id_i;
- id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len;
-
- *id_len = GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ;
- *id = malloc(*id_len);
- if (!*id) {
- log_error("ike_phase_1_recv_ID: malloc (%lu) failed",
- (unsigned long) *id_len);
- return -1;
- }
- memcpy(*id, payload->p + ISAKMP_GEN_SZ, *id_len);
- snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s",
- constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p)));
- LOG_DBG_BUF((LOG_NEGOTIATION, 40, header,
- payload->p + ISAKMP_ID_DATA_OFF,
- *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF));
- payload->flags |= PL_MARK;
- return 0;
-}
-
-/* Receive HASH and check that the exchange has been consistent. */
-int
-ike_phase_1_recv_AUTH(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- struct prf *prf;
- struct hash *hash = ie->hash;
- char header[80];
- size_t hashsize = hash->hashsize;
- int initiator = exchange->initiator;
- u_int8_t **hash_p, *id;
- size_t id_len;
-
- /* Choose the right fields to fill in */
- hash_p = initiator ? &ie->hash_r : &ie->hash_i;
- id = initiator ? exchange->id_r : exchange->id_i;
- id_len = initiator ? exchange->id_r_len : exchange->id_i_len;
-
- /* The decoded hash will be in ie->hash_r or ie->hash_i */
- if (ie->ike_auth->decode_hash(msg)) {
- message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1,
- 0);
- return -1;
- }
- /* Allocate the prf and start calculating his HASH. */
- prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
- if (!prf) {
- /* XXX Log? */
- return -1;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
- prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
- prf->Update(prf->prfctx, exchange->cookies +
- (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
- ISAKMP_HDR_ICOOKIE_LEN);
- prf->Update(prf->prfctx, exchange->cookies +
- (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
- ISAKMP_HDR_ICOOKIE_LEN);
- prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
- prf->Update(prf->prfctx, id, id_len);
- prf->Final(hash->digest, prf->prfctx);
- prf_free(prf);
- snprintf(header, sizeof header, "ike_phase_1_recv_AUTH: "
- "computed HASH_%c", initiator ? 'R' : 'I');
- LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, hash->digest, hashsize));
-
- /* Check that the hash we got matches the one we computed. */
- if (memcmp(*hash_p, hash->digest, hashsize) != 0) {
- /* XXX Log? */
- return -1;
- }
-
- /* Mark message as authenticated. */
- msg->flags |= MSG_AUTHENTICATED;
-
- return 0;
-}
-
-struct attr_node {
- LIST_ENTRY(attr_node) link;
- u_int16_t type;
-};
-
-struct validation_state {
- struct conf_list_node *xf;
- LIST_HEAD(attr_head, attr_node) attrs;
- char *life;
-};
-
-/* Validate a proposal inside SA according to EXCHANGE's policy. */
-static int
-ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa,
- struct sa *isakmp_sa)
-{
- struct conf_list *conf, *tags;
- struct conf_list_node *xf, *tag;
- struct proto *proto;
- struct validation_state vs;
- struct attr_node *node, *next_node;
-
- /* Get the list of transforms. */
- conf = conf_get_list(exchange->policy, "Transforms");
- if (!conf)
- return 0;
-
- for (xf = TAILQ_FIRST(&conf->fields); xf; xf = TAILQ_NEXT(xf, link)) {
- for (proto = TAILQ_FIRST(&sa->protos); proto;
- proto = TAILQ_NEXT(proto, link)) {
- /* Mark all attributes in our policy as unseen. */
- LIST_INIT(&vs.attrs);
- vs.xf = xf;
- vs.life = 0;
- if (attribute_map(proto->chosen->p +
- ISAKMP_TRANSFORM_SA_ATTRS_OFF,
- GET_ISAKMP_GEN_LENGTH(proto->chosen->p) -
- ISAKMP_TRANSFORM_SA_ATTRS_OFF,
- attribute_unacceptable, &vs))
- goto try_next;
-
- /* Sweep over unseen tags in this section. */
- tags = conf_get_tag_list(xf->field);
- if (tags) {
- for (tag = TAILQ_FIRST(&tags->fields); tag;
- tag = TAILQ_NEXT(tag, link))
- /*
- * XXX Should we care about attributes
- * we have, they do not provide?
- */
- for (node = LIST_FIRST(&vs.attrs);
- node; node = next_node) {
- next_node =
- LIST_NEXT(node, link);
- if (node->type ==
- constant_value(ike_attr_cst,
- tag->field)) {
- LIST_REMOVE(node, link);
- free(node);
- }
- }
- conf_free_list(tags);
- }
- /* Are there leftover tags in this section? */
- node = LIST_FIRST(&vs.attrs);
- if (node)
- goto try_next;
- }
-
- /* All protocols were OK, we succeeded. */
- LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: "
- "success"));
- conf_free_list(conf);
- if (vs.life)
- free(vs.life);
- return 1;
-
-try_next:
- /* Are there leftover tags in this section? */
- node = LIST_FIRST(&vs.attrs);
- while (node) {
- LIST_REMOVE(node, link);
- free(node);
- node = LIST_FIRST(&vs.attrs);
- }
- if (vs.life)
- free(vs.life);
- }
-
- LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure"));
- conf_free_list(conf);
- return 0;
-}
-
-/*
- * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward.
- * The VVS argument holds a validation state kept across invocations.
- * If the attribute is unacceptable to use, return non-zero, otherwise zero.
- */
-static int
-attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len,
- void *vvs)
-{
- struct validation_state *vs = vvs;
- struct conf_list *life_conf;
- struct conf_list_node *xf = vs->xf, *life;
- char *tag = constant_lookup(ike_attr_cst, type);
- char *str;
- struct constant_map *map;
- struct attr_node *node;
- int rv;
-
- if (!tag) {
- LOG_DBG((LOG_NEGOTIATION, 60, "attribute_unacceptable: "
- "attribute type %d not known", type));
- return 1;
- }
- switch (type) {
- case IKE_ATTR_ENCRYPTION_ALGORITHM:
- case IKE_ATTR_HASH_ALGORITHM:
- case IKE_ATTR_AUTHENTICATION_METHOD:
- case IKE_ATTR_GROUP_DESCRIPTION:
- case IKE_ATTR_GROUP_TYPE:
- case IKE_ATTR_PRF:
- str = conf_get_str(xf->field, tag);
- if (!str) {
- /* This attribute does not exist in this policy. */
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: attr %s does not exist "
- "in %s", tag, xf->field));
- return 1;
- }
- map = constant_link_lookup(ike_attr_cst, type);
- if (!map)
- return 1;
-
- if ((constant_value(map, str) == decode_16(value)) ||
- (!strcmp(str, "ANY"))) {
- /* Mark this attribute as seen. */
- node = malloc(sizeof *node);
- if (!node) {
- log_error("attribute_unacceptable: "
- "malloc (%lu) failed",
- (unsigned long) sizeof *node);
- return 1;
- }
- node->type = type;
- LIST_INSERT_HEAD(&vs->attrs, node, link);
- return 0;
- }
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: %s: got %s, expected %s", tag,
- constant_name(map, decode_16(value)), str));
- return 1;
-
- case IKE_ATTR_GROUP_PRIME:
- case IKE_ATTR_GROUP_GENERATOR_1:
- case IKE_ATTR_GROUP_GENERATOR_2:
- case IKE_ATTR_GROUP_CURVE_A:
- case IKE_ATTR_GROUP_CURVE_B:
- /* XXX Bignums not handled yet. */
- return 1;
-
- case IKE_ATTR_LIFE_TYPE:
- case IKE_ATTR_LIFE_DURATION:
- life_conf = conf_get_list(xf->field, "Life");
- if (life_conf &&
- !strcmp(conf_get_str(xf->field, "Life"), "ANY"))
- return 0;
-
- rv = 1;
- if (!life_conf) {
- /* Life attributes given, but not in our policy. */
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: received unexpected life "
- "attribute"));
- return 1;
- }
- /*
- * Each lifetime type must match, otherwise we turn the
- * proposal down. In order to do this we need to find the
- * specific section of our policy's "Life" list and match
- * its duration.
- */
- switch (type) {
- case IKE_ATTR_LIFE_TYPE:
- for (life = TAILQ_FIRST(&life_conf->fields); life;
- life = TAILQ_NEXT(life, link)) {
- str = conf_get_str(life->field, "LIFE_TYPE");
- if (!str) {
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: "
- "section [%s] has no LIFE_TYPE",
- life->field));
- continue;
- }
-
- /*
- * If this is the type we are looking at,
- * to save a pointer this section in vs->life.
- */
- if (constant_value(ike_duration_cst, str) ==
- decode_16(value)) {
- vs->life = strdup(life->field);
- rv = 0;
- goto bail_out;
- }
- }
- LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable:"
- " unrecognized LIFE_TYPE %d", decode_16(value)));
- vs->life = 0;
- break;
-
- case IKE_ATTR_LIFE_DURATION:
- if (!vs->life) {
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: "
- "LIFE_DURATION without LIFE_TYPE"));
- rv = 1;
- goto bail_out;
- }
- str = conf_get_str(vs->life, "LIFE_DURATION");
- if (str) {
- if (!strcmp(str, "ANY"))
- rv = 0;
- else
- rv = !conf_match_num(vs->life,
- "LIFE_DURATION",
- len == 4 ? decode_32(value) :
- decode_16(value));
- } else {
- LOG_DBG((LOG_NEGOTIATION, 70,
- "attribute_unacceptable: section [%s] has "
- "no LIFE_DURATION", vs->life));
- rv = 1;
- }
-
- free(vs->life);
- vs->life = 0;
- break;
- }
-
-bail_out:
- conf_free_list(life_conf);
- return rv;
-
- case IKE_ATTR_KEY_LENGTH:
- case IKE_ATTR_FIELD_SIZE:
- case IKE_ATTR_GROUP_ORDER:
- if (conf_match_num(xf->field, tag, decode_16(value))) {
- /* Mark this attribute as seen. */
- node = malloc(sizeof *node);
- if (!node) {
- log_error("attribute_unacceptable: "
- "malloc (%lu) failed",
- (unsigned long) sizeof *node);
- return 1;
- }
- node->type = type;
- LIST_INSERT_HEAD(&vs->attrs, node, link);
- return 0;
- }
- return 1;
- }
- return 1;
-}