diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012/ike_phase_1.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/ike_phase_1.c | 1396 |
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; -} |