summaryrefslogtreecommitdiff
path: root/sbin/isakmpd/ike_main_mode.c
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-04-19 21:01:17 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-04-19 21:01:17 +0000
commit2969faaad8c3a983001f2c3bec92bf04ddbab767 (patch)
tree9e4f5ce68784404dec11cf62763112b117ac0613 /sbin/isakmpd/ike_main_mode.c
parent2fd6914eebe3bfbe4d3c0394bebbc16ff810971f (diff)
./ike_main_mode.c: Merge with EOM 1.76
Let's get aggressive\!
Diffstat (limited to 'sbin/isakmpd/ike_main_mode.c')
-rw-r--r--sbin/isakmpd/ike_main_mode.c1084
1 files changed, 18 insertions, 1066 deletions
diff --git a/sbin/isakmpd/ike_main_mode.c b/sbin/isakmpd/ike_main_mode.c
index 0b74fbb3cd4..f9ef570b5bc 100644
--- a/sbin/isakmpd/ike_main_mode.c
+++ b/sbin/isakmpd/ike_main_mode.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ike_main_mode.c,v 1.9 1999/04/05 21:01:02 niklas Exp $ */
-/* $EOM: ike_main_mode.c,v 1.75 1999/04/05 08:01:22 niklas Exp $ */
+/* $OpenBSD: ike_main_mode.c,v 1.10 1999/04/19 21:01:16 niklas Exp $ */
+/* $EOM: ike_main_mode.c,v 1.76 1999/04/16 21:24:43 niklas Exp $ */
/*
* Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
@@ -51,6 +51,7 @@
#include "hash.h"
#include "ike_auth.h"
#include "ike_main_mode.h"
+#include "ike_phase_1.h"
#include "ipsec.h"
#include "ipsec_doi.h"
#include "isakmp.h"
@@ -62,455 +63,44 @@
#include "transport.h"
#include "util.h"
-static int attribute_unacceptable (u_int16_t, u_int8_t *, u_int16_t, void *);
-static int ike_main_mode_validate_prop (struct exchange *, struct sa *);
-static int initiator_send_SA (struct message *);
-static int initiator_recv_SA (struct message *);
-static int initiator_send_KE_NONCE (struct message *);
-static int initiator_recv_KE_NONCE (struct message *);
static int initiator_send_ID_AUTH (struct message *);
-static int initiator_recv_ID_AUTH (struct message *);
-static int responder_recv_SA (struct message *);
-static int responder_send_SA (struct message *);
-static int responder_recv_KE_NONCE (struct message *);
static int responder_send_KE_NONCE (struct message *);
-static int responder_recv_ID_AUTH (struct message *);
-static int responder_send_ID_AUTH (struct message *);
-static int recv_KE_NONCE (struct message *);
-static int recv_ID_AUTH (struct message *);
-static int send_KE_NONCE (struct message *, size_t);
-static int send_ID_AUTH (struct message *);
-static int post_exchange_KE_NONCE (struct message *);
int (*ike_main_mode_initiator[]) (struct message *) = {
- initiator_send_SA,
- initiator_recv_SA,
- initiator_send_KE_NONCE,
- initiator_recv_KE_NONCE,
+ ike_phase_1_initiator_send_SA,
+ ike_phase_1_initiator_recv_SA,
+ ike_phase_1_initiator_send_KE_NONCE,
+ ike_phase_1_initiator_recv_KE_NONCE,
initiator_send_ID_AUTH,
- initiator_recv_ID_AUTH
+ ike_phase_1_recv_ID_AUTH
};
int (*ike_main_mode_responder[]) (struct message *) = {
- responder_recv_SA,
- responder_send_SA,
- responder_recv_KE_NONCE,
+ ike_phase_1_responder_recv_SA,
+ ike_phase_1_responder_send_SA,
+ ike_phase_1_recv_KE_NONCE,
responder_send_KE_NONCE,
- responder_recv_ID_AUTH,
- responder_send_ID_AUTH
+ ike_phase_1_recv_ID_AUTH,
+ ike_phase_1_responder_send_ID_AUTH
};
-/* Offer a set of transforms to the responder in the MSG message. */
-static int
-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, *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 i, value, update_nextp;
- struct payload *p;
- struct proto *proto;
-
- /* 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 ("initiator_send_SA: calloc (1, %d) failed",
- sizeof *transform);
- goto bail_out;
- }
-
- transform_len = calloc (conf->cnt, sizeof *transform_len);
- if (!transform_len)
- {
- log_error ("initiator_send_SA: calloc (1, %d) failed",
- 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 ("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 Does only handle 16-bit entities! */
- value = conf_get_num (life->field, "LIFE_DURATION", 0);
- if (value)
- attr
- = attribute_set_basic (attr, IKE_ATTR_LIFE_DURATION, 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];
- }
-
- proposal_len = ISAKMP_PROP_SPI_OFF;
- proposal = malloc (proposal_len);
- if (!proposal)
- {
- log_error ("initiator_send_SA: malloc (%d) failed", 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 ("initiator_send_SA: calloc (1, %d) failed", sizeof *proto);
- goto bail_out;
- }
-
- proto->no = 1;
- proto->proto = ISAKMP_PROTO_ISAKMP;
- proto->sa = TAILQ_FIRST (&exchange->sa_list);
- 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 ("initiator_send_SA: malloc (%d) failed", 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;
-
- 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;
- }
-
- /* 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)
- goto bail_out;
- memcpy (ie->sa_i_b,
- TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])->p + ISAKMP_GEN_SZ,
- sa_len - ISAKMP_GEN_SZ);
- memcpy (ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
- TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL])->p,
- proposal_len);
- transforms_len = 0;
- for (i = 0, p = TAILQ_FIRST (&msg->payload[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];
- }
-
- 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. */
-static int
-initiator_recv_SA (struct message *msg)
-{
- struct sa *sa;
- struct proto *proto;
- struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
- struct payload *prop = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL]);
- struct payload *xf = TAILQ_FIRST (&msg->payload[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 ("initiator_recv_SA: "
- "multiple SA, proposal or transform payloads in main mode");
- /* XXX Is there a better notification type? */
- message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
- return -1;
- }
-
- sa = TAILQ_FIRST (&msg->exchange->sa_list);
-
- /* Build the protection suite in our SA. */
- if (sa_add_transform (sa, xf, msg->exchange->initiator, &proto))
- {
- /* XXX Log? */
- return -1;
- }
-
- /* XXX Check that the chosen transform matches an offer. */
- ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos), xf->p);
-
- /* Mark the SA as handled. */
- sa_p->flags |= PL_MARK;
- return 0;
-}
-
-/* Send our public DH value and a nonce to the responder. */
-static int
-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 send_KE_NONCE (msg, 16);
-}
-
-/* Accept receptor's public DH value and nonce. */
-static int
-initiator_recv_KE_NONCE (struct message *msg)
-{
- if (recv_KE_NONCE (msg))
- return -1;
-
- return post_exchange_KE_NONCE (msg);
-}
-
static int
initiator_send_ID_AUTH (struct message *msg)
{
msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT;
- return send_ID_AUTH (msg);
-}
-
-static int
-initiator_recv_ID_AUTH (struct message *msg)
-{
- return recv_ID_AUTH (msg);
-}
-/*
- * Accept a set of transforms offered by the initiator and chose one we can
- * handle.
- */
-static int
-responder_recv_SA (struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct sa *sa = TAILQ_FIRST (&exchange->sa_list);
- struct payload *sa_p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA]);
- struct payload *prop = TAILQ_FIRST (&msg->payload[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 ("responder_recv_SA: "
- "multiple SA or proposal payloads in main mode");
- /* XXX Is there a better notification type? */
- message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 0);
- return -1;
- }
-
- /* Chose a transform from the SA. */
- if (message_negotiate_sa (msg, ike_main_mode_validate_prop)
- || !TAILQ_FIRST (&sa->protos))
+ if (ike_phase_1_send_ID (msg))
return -1;
- /* XXX Move into message_negotiate_sa? */
- ipsec_decode_transform (msg, sa, TAILQ_FIRST (&sa->protos),
- TAILQ_FIRST (&sa->protos)->chosen->p);
-
- /*
- * 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, 0, 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 log and notify peer? */
- 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. */
-static int
-responder_send_SA (struct message *msg)
-{
- /* Add the SA payload with the transform that was chosen. */
- return message_add_sa_payload (msg);
-}
-
-/* Accept initiator's public DH value and nonce. */
-static int
-responder_recv_KE_NONCE (struct message *msg)
-{
- return recv_KE_NONCE (msg);
+ return ike_phase_1_send_AUTH (msg);
}
/* Send our public DH value and a nonce to the initiator. */
-static int
+int
responder_send_KE_NONCE (struct message *msg)
{
/* XXX Should we really just use the initiator's nonce size? */
- if (send_KE_NONCE (msg, msg->exchange->nonce_i_len))
+ if (ike_phase_1_send_KE_NONCE (msg, msg->exchange->nonce_i_len))
return -1;
/*
@@ -519,645 +109,7 @@ responder_send_KE_NONCE (struct message *msg)
*/
message_register_post_send (msg,
(void (*) (struct message *))
- post_exchange_KE_NONCE);
-
- return 0;
-}
-
-/* Receive ID and HASH and check that the exchange has been consistent. */
-static int
-responder_recv_ID_AUTH (struct message *msg)
-{
- return recv_ID_AUTH (msg);
-}
-
-static int
-responder_send_ID_AUTH (struct message *msg)
-{
- return send_ID_AUTH (msg);
-}
-
-/* Send our public DH value and a nonce to the peer. */
-static int
-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;
- }
-
- return 0;
-}
-
-/* Receive our peer's public DH value and nonce. */
-static int
-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;
- }
-
- 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.
- */
-static int
-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 log and notify peer? */
- return -1;
- }
- dh_create_shared (ie->group, ie->g_xy,
- exchange->initiator ? ie->g_xr : ie->g_xi);
- log_debug_buf (LOG_MISC, 80, "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_debug_buf (LOG_MISC, 80, "post_exchange_KE_NONCE: SKEYID",
- ie->skeyid, ie->skeyid_len);
-
- /* SKEYID_d. */
- ie->skeyid_d = malloc (ie->skeyid_len);
- if (!ie->skeyid_d)
- {
- /* XXX Log and teardown? */
- 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, "\0", 1);
- prf->Final (ie->skeyid_d, prf->prfctx);
- log_debug_buf (LOG_MISC, 80, "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)
- {
- /* XXX Log & teardown? */
- 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, "\1", 1);
- prf->Final (ie->skeyid_a, prf->prfctx);
- log_debug_buf (LOG_MISC, 80, "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 Log and teardown? */
- 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, "\2", 1);
- prf->Final (ie->skeyid_e, prf->prfctx);
- prf_free (prf);
- log_debug_buf (LOG_MISC, 80, "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);
-
- if ((key = malloc (keylen)) == NULL)
- {
- /* XXX - notify peer */
- return -1;
- }
-
- prf->Init (prf->prfctx);
- prf->Update (prf->prfctx, "\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 ("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 ("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);
+ ike_phase_1_post_exchange_KE_NONCE);
return 0;
}
-
-static int
-send_ID_AUTH (struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- u_int8_t *buf;
- char header[80];
- size_t sz;
- struct sockaddr *src;
- int src_len;
- int initiator = exchange->initiator;
- u_int8_t **id;
- size_t *id_len;
-
- /* 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;
-
- /* XXX This begs to be more dynamic. */
- sz = ISAKMP_ID_DATA_OFF + 4;
- buf = malloc (sz);
- if (!buf)
- {
- log_error ("send_ID_AUTH: malloc (%d) failed", sz);
- return -1;
- }
-
- msg->transport->vtbl->get_src (msg->transport, &src, &src_len);
- /* XXX Assumes IPv4. */
- SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR);
- SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
- SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
- /* Already in network byteorder. */
- memcpy (buf + ISAKMP_ID_DATA_OFF,
- &((struct sockaddr_in *)src)->sin_addr.s_addr, sizeof (in_addr_t));
- 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 ("send_ID_AUTH: malloc (%d) failed", *id_len);
- return -1;
- }
- memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len);
- snprintf (header, 80, "send_ID_AUTH: %s",
- constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf)));
- log_debug_buf (LOG_MISC, 40, header, buf + ISAKMP_ID_DATA_OFF,
- sz - ISAKMP_ID_DATA_OFF);
-
- if (ie->ike_auth->encode_hash (msg) == -1)
- {
- /* 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. */
-static int
-recv_ID_AUTH (struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- struct payload *payload;
- 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;
-
- /* XXX Do I really have to save the ID in the SA? */
- payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]);
- *id_len = GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ;
- *id = malloc (*id_len);
- if (!*id)
- {
- /* XXX Log? */
- return -1;
- }
- memcpy (*id, payload->p + ISAKMP_GEN_SZ, *id_len);
- snprintf (header, 80, "recv_ID_AUTH: %s",
- constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (payload->p)));
- log_debug_buf (LOG_MISC, 40, header, payload->p + ISAKMP_ID_DATA_OFF,
- *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF);
- payload->flags |= PL_MARK;
-
- /* The decoded hash will be in ie->hash_r or ie->hash_i */
- if (ie->ike_auth->decode_hash (msg) == -1)
- {
- message_drop (msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 0, 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, 80, "recv_ID_AUTH: computed HASH_%c",
- initiator ? 'R' : 'I');
- log_debug_buf (LOG_MISC, 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;
- }
-
- 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_main_mode_validate_prop (struct exchange *exchange, struct sa *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) == -1)
- 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_debug (LOG_MISC, 20, "ike_main_mode_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_debug (LOG_MISC, 20, "ike_main_mode_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_print ("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. */
- return 1;
-
- map = constant_link_lookup (ike_attr_cst, type);
- if (!map)
- return 1;
-
- if (constant_value (map, str) == decode_16 (value))
- {
- /* Mark this attribute as seen. */
- node = malloc (sizeof *node);
- if (!node)
- {
- log_print ("attribute_unacceptable: malloc failed");
- return 1;
- }
- node->type = type;
- LIST_INSERT_HEAD (&vs->attrs, node, link);
- return 0;
- }
- 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:
- rv = 1;
- life_conf = conf_get_list (xf->field, "Life");
- if (!life_conf)
- /* Life attributes given, but not in our policy. */
- 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_print ("attribute_unacceptable: "
- "section [%s] has no LIFE_TYPE", life->field);
- continue;
- }
-
- /*
- * If this is the type we are looking at, save a pointer
- * to 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_print ("attribute_unacceptable: unrecognized LIFE_TYPE %d",
- decode_16 (value));
- vs->life = 0;
- break;
-
- case IKE_ATTR_LIFE_DURATION:
- if (!vs->life)
- {
- log_print ("attribute_unacceptable: "
- "LIFE_DURATION without LIFE_TYPE");
- rv = 1;
- goto bail_out;
- }
- rv = !conf_match_num (vs->life, "LIFE_DURATION", decode_16 (value));
- 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_print ("attribute_unacceptable: malloc failed");
- return 1;
- }
- node->type = type;
- LIST_INSERT_HEAD (&vs->attrs, node, link);
- return 0;
- }
- return 1;
- }
- return 1;
-}