Files
m241Neelima/components/ip_net2-6.9/ipike/src/ipike_exchange_main_mode.c
T
2026-07-30 11:19:44 +05:30

1888 lines
64 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_exchange_main_mode.c,v $ $Revision: 1.33.10.13 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_exchange_main_mode.c,v $
* $Author: hxu0 $ $Date: 2015-07-13 08:20:47 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_exchange_main_mode.h"
#include "ipike_exchange_informational.h"
#include "ipike_crypto.h"
#include "ipike_payload.h"
#include "ipike_attributes.h"
#include "ipike_payload_sa.h"
#include "ipike_payload_certificate.h"
#include "ipike_payload_key_exchange.h"
#include "ipike_payload_nonce.h"
#include "ipike_payload_identification.h"
#include "ipike_payload_notification.h"
#include "ipike_payload_hash.h"
#include "ipike_payload_sign.h"
#include "ipike_payload_transform.h"
#include "ipike_payload_vendor_id.h"
#include "ipike_payload_nat.h"
#include "ipike_util.h"
#include "ipike_sadb.h"
#include "ipike_ipsec.h"
#include "ipike_configuration.h"
#include "ipike_policy.h"
#include "ipike_http_fetcher.h"
#include <openssl/x509.h>
#include <ipcom_clib.h>
#include <ipcom_sock2.h>
#include <ipcom_syslog.h>
#include <ipcom_sock2.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_main_mode_update_state
*===========================================================================
* Description: Updates the exchange state after the data from
* message #1, 2, 3, 4, 5 or 6
* has been stored.
* Parameters: ie - holds all the states associated with the exchange.
* Returns: IPIKE_SUCCESS
* IPIKE_OUT_OF_MEMORY
* IPIKE_KE_DH_ERROR
*
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_1(Ipike_isakmp_exchange* ie);
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_2(Ipike_isakmp_exchange* ie);
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_3(Ipike_isakmp_exchange* ie);
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_4(Ipike_isakmp_exchange* ie);
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_5(Ipike_isakmp_exchange* ie);
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_6(Ipike_isakmp_exchange* ie);
/*
*===========================================================================
* ipike_main_mode_update_state
*===========================================================================
* Description: Calls functions that updates necessary state paramters during
* phase 1 main mode exchange.
* Parameters: ie - holds all the states associated with the exchange.
* Returns: IPIKE_SUCCESS
* IPIKE_OUT_OF_MEMORY
* IPIKE_KE_DH_ERROR
*
*/
IP_STATIC Ipike_error
ipike_main_mode_update_state(Ipike_isakmp_exchange* ie);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_main_mode_initialize_id
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_initialize_id(
Ipike_isakmp_exchange* ie,
Ipike_id* id)
{
Ipike_error err = IPIKE_SUCCESS;
const char* str = ie->ike_conf->local_id;
/* Try to use id from configuration, use IP-address if fails */
if (IP_NULL == str ||
IPIKE_SUCCESS != ipike_identification_generate(str, id))
{
err = ipike_ipsec_set_idix(&ie->ike_sa->local_addr, id);
}
return err;
}
/* This IKE daemon is responder */
/*
*===========================================================================
* ipike_main_mode_update_after_msg_1
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_1(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
err = ipike_policy_select_ike_sa_param(ie->ike_conf,
&ie->ike_sa->sa,
&ie->ike_sa->selected,
IP_FALSE);
if ( err != IPIKE_SUCCESS )
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, PROPOSAL_MISMATCH,
&ie->ike_sa->peer_addr, &ie->ike_sa->local_addr,
0, IP_NULL);
return err;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_update_after_msg_3
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_3(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ipike_sadb_entry *ike_sa = ie->ike_sa;
Ipike_transform_ike *transform = ipike_transform_ike_from_exch(ie);
if (transform==IP_NULL)
return IPIKE_FAILED;
if (IPIKE_SUCCESS != (err = ipike_payload_nonce_generate(&ike_sa->nr)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_generate_dh_key(transform->dh_prime,
transform->dh_generator, &ie->dh, &ike_sa->g_xr)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_dh_key(ie->dh,
&ike_sa->g_xi, &ike_sa->g_xy)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_skeyid(ie->ike_conf, ike_sa)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_phase1_secret_key(ie)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_initial_phase1_iv(ike_sa, &ie->iv)))
goto errout;
return IPIKE_SUCCESS;
errout:
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
return err;
}
/*
*===========================================================================
* ipike_main_mode_update_after_msg_5
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_5(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ipike_sadb_entry* ike_sa = ie->ike_sa;
Ip_u16 auth_meth;
Ip_u16 hash_alg;
Ipike_transform_ike *transform_ike;
/* Check if there is a more suitable IKE SA config */
ipike_main_mode_update_responder_config(ie);
if (IPIKE_SUCCESS != (err = ipike_main_mode_authentication_check(ie)))
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, AUTHENTICATION_ERROR,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
return err;
}
switch (ike_sa->sa.doi)
{
case IPIKE_DOI_IPSEC:
if (IPIKE_SUCCESS != (err = ipike_main_mode_initialize_id(ie, &ike_sa->idir)))
goto errout;
break;
default:
IPCOM_LOG1(ERR, "ipike_main_mode_update_after_msg_5() :: "\
"the DOI %d is not supported", ike_sa->sa.doi);
err = IPIKE_DOI_UNSUPPORTED;
goto errout;
}
transform_ike = ipike_transform_ike_from_exch(ie);
if (transform_ike==IP_NULL)
{
err = IPIKE_FAILED;
goto errout;
}
auth_meth = transform_ike->authentication_method;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
hash_alg = IPIKE_ATTR_HASH_SHA1;
else
hash_alg = transform_ike->hash_algorithm;
err = ipike_crypto_compute_hash_r(hash_alg, ike_sa, &ike_sa->hash_r);
if ( err != IPIKE_SUCCESS )
goto errout;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
err = ipike_crypto_compute_dsa_sign(ie->ike_conf->authentication.key_id,
ie->ike_conf->authentication.private_key,
&ike_sa->hash_r,
&ike_sa->sign_r);
else if (auth_meth == IPIKE_ATTR_AUTH_RSA_SIGNATURES)
err = ipike_crypto_compute_rsa_sign(ie->ike_conf->authentication.key_id,
ie->ike_conf->authentication.private_key,
&ike_sa->hash_r,
&ike_sa->sign_r);
/* Everything should be encrypted from now on */
ie->isakmp_flags = IPIKE_ISAKMP_ENCRYPTION;
errout:
if ( err != IPIKE_SUCCESS )
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
return err;
}
return IPIKE_SUCCESS;
}
/* This IKE daemon is initiator */
/*
*===========================================================================
* ipike_main_mode_update_before_msg_1
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_before_msg_1(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
err = ipike_sa_ike_initialize(ie->ike_conf, &ie->ike_sa->sa);
if ( err != IPIKE_SUCCESS )
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ie->ike_sa->local_addr, &ie->ike_sa->peer_addr,
0, IP_NULL);
return err;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_update_after_msg_2
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_2(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ipike_sadb_entry* ike_sa = ie->ike_sa;
Ipike_transform_ike* transform;
err = ipike_policy_select_ike_sa_param(ie->ike_conf,
&ike_sa->sa,
&ie->ike_sa->selected,
IP_TRUE);
if (IPIKE_SUCCESS != err)
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, PROPOSAL_MISMATCH,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
return err;
}
transform = ipike_transform_ike_from_exch(ie);
/* We should have a selected transform here otherwise would
* ipike_policy_select_ike_sa_param failed */
ip_assert(transform != IP_NULL);
err = ipike_crypto_generate_dh_key(transform->dh_prime,
transform->dh_generator,
&ie->dh, &ike_sa->g_xi);
if (IPIKE_SUCCESS != err)
goto errout;
err = ipike_payload_nonce_generate(&ike_sa->ni);
errout:
if (IPIKE_SUCCESS != err)
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
}
return err;
}
/*
*===========================================================================
* ipike_main_mode_update_after_msg_4
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_4(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ipike_sadb_entry* ike_sa = ie->ike_sa;
Ip_u16 auth_meth;
Ip_u16 hash_alg;
Ipike_transform_ike *transform_ike;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_dh_key(ie->dh,
&ike_sa->g_xr, &ike_sa->g_xy)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_skeyid(ie->ike_conf, ike_sa)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_phase1_secret_key(ie)))
goto errout;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_initial_phase1_iv(ike_sa, &ie->iv)))
goto errout;
switch (ike_sa->sa.doi)
{
case IPIKE_DOI_IPSEC:
if (IPIKE_SUCCESS != (err = ipike_main_mode_initialize_id(ie, &ike_sa->idii)))
goto errout;
break;
default:
IPCOM_LOG1(ERR, "ipike_main_mode_update_after_msg_4() ::"\
" the DOI %d is not supported",
ike_sa->sa.doi);
err = IPIKE_DOI_UNSUPPORTED;
goto errout;
}
transform_ike = ipike_transform_ike_from_exch(ie);
if (transform_ike==IP_NULL)
{
err= IPIKE_FAILED;
goto errout;
}
auth_meth = transform_ike->authentication_method;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
hash_alg = IPIKE_ATTR_HASH_SHA1;
else
hash_alg = transform_ike->hash_algorithm;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_hash_i(hash_alg, ike_sa, &ike_sa->hash_i)))
goto errout;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
err = ipike_crypto_compute_dsa_sign(ie->ike_conf->authentication.key_id,
ie->ike_conf->authentication.private_key,
&ike_sa->hash_i,
&ike_sa->sign_i);
else if (auth_meth == IPIKE_ATTR_AUTH_RSA_SIGNATURES)
err = ipike_crypto_compute_rsa_sign(ie->ike_conf->authentication.key_id,
ie->ike_conf->authentication.private_key,
&ike_sa->hash_i,
&ike_sa->sign_i);
/* Everything should be encrypted from now on */
ie->isakmp_flags = IPIKE_ISAKMP_ENCRYPTION;
errout:
if ( err != IPIKE_SUCCESS )
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ike_sa->peer_addr, &ike_sa->local_addr,
0, IP_NULL);
return err;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_update_after_msg_6
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_after_msg_6(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
err = ipike_main_mode_authentication_check(ie);
if ( err != IPIKE_SUCCESS )
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, AUTHENTICATION_ERROR,
&ie->ike_sa->peer_addr, &ie->ike_sa->local_addr,
0, IP_NULL);
return err;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_update_state
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_update_state(Ipike_isakmp_exchange* ie)
{
switch (ie->message_number)
{
/* We are responder */
case 1: return ipike_main_mode_update_after_msg_1(ie);
case 3: return ipike_main_mode_update_after_msg_3(ie);
case 5: return ipike_main_mode_update_after_msg_5(ie);
/* We are initiator */
case 0: return ipike_main_mode_update_before_msg_1(ie);
case 2: return ipike_main_mode_update_after_msg_2(ie);
case 4: return ipike_main_mode_update_after_msg_4(ie);
case 6: return ipike_main_mode_update_after_msg_6(ie);
}
IPCOM_LOG1(ERR,
"IKE main mode has 6 messages, this was %d",
ie->message_number);
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, ISAKMP_PACKET_ERROR,
&ie->ike_sa->peer_addr, &ie->ike_sa->local_addr,
0, IP_NULL);
return IPIKE_INVALID_MESSAGE_NUMBER;
}
/*
*===========================================================================
* ipike_main_mode_store_sai_b
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_store_sai_b(Ipike_value* sai_b, Ipike_sa_payload* payload)
{
sai_b->len = ip_ntohs(payload->header.length) - IPIKE_PAYLOAD_HEADER_LENGTH;
if (IP_NULL == (sai_b->value = ipcom_malloc(sai_b->len)))
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
ipcom_memcpy(sai_b->value, (Ip_u8 *) payload + IPIKE_PAYLOAD_HEADER_LENGTH,
sai_b->len);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_cert_create
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_cert_create(
Ipike_config_ike_sa* conf,
Ipike_cert_payload** payload)
{
Ipike_error err;
Ipike_cert cert;
cert.peer = ipike_crypto_read_cert(conf->authentication.certificate);
err = ipike_payload_certificate_create(cert.peer, IP_NULL, payload);
X509_free(cert.peer);
return err;
}
/*
*===========================================================================
* ipike_main_mode_verify_auth
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_verify_auth(Ipike_isakmp_exchange *ie)
{
Ipike_sadb_entry *ike_sa = ie->ike_sa;
Ipike_transform_ike *transform = IP_NULL;
Ipike_error err = IPIKE_AUTHENTICATION_FAILED;
Ip_u16 auth_meth = 0;
Ip_u16 hash_alg = 0;
ip_assert(ike_sa);
transform = ipike_transform_ike_from_exch(ie);
if (transform == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_main_mode_verify_auth :: null transform");
goto error;
}
auth_meth = transform->authentication_method;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
hash_alg = IPIKE_ATTR_HASH_SHA1;
else
hash_alg = ipike_transform_ike_from_exch(ie)->hash_algorithm;
/* Compute hash for RSA and DSS */
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES ||
auth_meth == IPIKE_ATTR_AUTH_RSA_SIGNATURES )
{
if (ike_sa->is_initiator)
err = ipike_crypto_compute_hash_r(hash_alg, ike_sa, &ike_sa->hash_r);
else
err = ipike_crypto_compute_hash_i(hash_alg, ike_sa, &ike_sa->hash_i);
if (err != IPIKE_SUCCESS)
goto error;
}
/* Verify signature */
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES)
{
err = ipike_crypto_verify_dsa_sign(ike_sa->cert.peer,
ike_sa->is_initiator ? &ike_sa->hash_r : &ike_sa->hash_i,
ike_sa->is_initiator ? &ike_sa->sign_r : &ike_sa->sign_i);
}
else if ( auth_meth == IPIKE_ATTR_AUTH_RSA_SIGNATURES )
{
err = ipike_crypto_verify_rsa_sign(ike_sa->cert.peer,
ike_sa->is_initiator ? &ike_sa->hash_r : &ike_sa->hash_i,
ike_sa->is_initiator ? &ike_sa->sign_r : &ike_sa->sign_i);
}
else
{
if (ike_sa->is_initiator)
err = ipike_crypto_verify_hash_r(ie->ike_sa);
else
err = ipike_crypto_verify_hash_i(ie->ike_sa);
}
error:
return err;
}
/*
*===========================================================================
* ipike_main_mode_http_get_crl_cb
*===========================================================================
*/
IP_STATIC void
ipike_main_mode_http_get_crl_cb(
Ipike_error status,
const char *data,
Ip_size_t data_len,
void *id)
{
Ipike_isakmp_exchange *ie = IP_NULL;
X509_CRL *crl = IP_NULL;
X509_CRL** crls = IP_NULL;
X509** trusted = IP_NULL;
X509** ca = IP_NULL;
Ipike_sadb_entry* ike_sa = IP_NULL;
Ipike_error err = IPIKE_AUTHENTICATION_FAILED;
ip_assert(id);
/* Get exchange state using the unique id */
ie = ipike_isakmp_get_exchange_from_unique_id(id, ipike_isakmp_get_unique_id_size());
if ( !ie )
{
/* No exchange found => abort */
IPCOM_LOG0(ERR, "ipike_main_mode_http_get_crl_cb()"\
" :: no IKE exchange state found");
/* Free allocated id */
ipcom_free( id );
/* No exchange found, stop proccessing */
return;
}
/* We should always have a valid ike_sa here */
ip_assert(ie->ike_sa);
ike_sa = ie->ike_sa;
/* Was the HTTP request successful */
if ( IPIKE_SUCCESS != status )
{
IPCOM_LOG1(ERR,
"ipike_main_mode_http_get_crl_cb() ::"\
" bad http response received (%d)", status);
goto done_continue;
}
/* Decode CRL */
crl = ipike_crypto_decode_crl((Ip_u8 *)data, data_len);
if ( !crl )
{
IPCOM_LOG0(ERR,
"ipike_main_mode_http_get_crl_cb() :: failed to decode crl");
goto done_continue;
}
/* Add CRL to CRL list */
if ( IPIKE_SUCCESS != ipike_array_add((void***) &crls, crl) )
goto done_continue;
/* Get intermediate CA certs from local storage */
ca = ipike_crypto_get_intermediate_ca_certs(
&ike_sa->cert,
ie->ike_conf->authentication.intermediate_ca_store);
/* Get trusted CA certs from local storage */
trusted = ipike_crypto_get_trusted_certs(
ie->ike_conf->authentication.trusted_ca_store);
/* Must at least have one trusted CA */
if ( !trusted )
{
IPCOM_LOG0(ERR,
"ipike_main_mode_http_get_crl_cb() ::"\
" failed to read trusted certificate");
goto done_continue;
}
#ifdef IPIKE_USE_OCSP
/* IKEv1 doesnt support OCSP define necessary for avoiding code duplication */
err = ipike_crypto_verify_certificate_ocsp(trusted, ca, ike_sa->cert.peer, crls, IP_NULL);
#else
err = ipike_crypto_verify_certificate(trusted, ca, ike_sa->cert.peer, crls);
#endif
done_continue:
/* Free allocated id */
ipcom_free( id );
ipike_array_free((void**) trusted, (void(*)(void*)) X509_free);
ipike_array_free((void**) ca, (void(*)(void*)) X509_free);
ipike_array_free((void**) crls, (void(*)(void*)) X509_CRL_free);
/* Update error state of IKE SA */
ie->ike_sa->error = err;
/* On failure */
if ( err != IPIKE_SUCCESS )
{
IPCOM_LOG0(ERR,
"ipike_main_mode_http_get_crl_cb() ::"\
" certificate verification failed");
(void)ipike_informational_report_error(ie->ike_sa, IP_NULL, err);
/* Set IKE SA to dying */
ipike_sadb_set_state(ie, ie->ike_sa, IPIKE_SA_DYING);
/* Destroy this exchange */
ipike_isakmp_free_exchange(ie, IP_TRUE);
}
else
{
/* Continue the exchange and send the response */
ipike_isakmp_process_message_continue(ie);
}
}
/*
*===========================================================================
* ipike_main_mode_http_get
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_main_mode_http_get(
Ipike_isakmp_exchange *ie,
const char *uri,
Ipike_http_fetcher_callback callback)
{
Ip_u8 *id;
Ip_u32 id_len;
if ( !uri )
return IPIKE_FAILED;
id_len = ipike_isakmp_get_unique_id_size();
id = ipcom_malloc( id_len );
if ( !id )
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
memset( id, 0, id_len);
/* Create an unique id for this exchange that is used for obtaining
correct exchange state in the callback */
if ( !ipike_isakmp_get_unique_id_for_exchange(ie, id, &id_len))
goto error_out;
/* Get data that is pointed out by the URI */
if ( IPIKE_SUCCESS != ipike_http_fetcher_get(uri, callback, id) )
{
IPCOM_LOG1(ERR, "ipike_main_mode_http_get :: failed to fetch \"%s\"", uri);
goto error_out;
}
/* Mark that this exchange is waiting for an external response */
ie->wait_response = IP_TRUE;
return IPIKE_SUCCESS;
error_out:
ipcom_free(id);
return IPIKE_FAILED;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_main_mode_cert_req_create
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_add_cert_request(
Ipike_config_ike_sa* conf,
Ipike_payload_header*** reply_payloads)
{
Ipike_cert_req_payload* payload = IP_NULL;
X509** trusted = IP_NULL;
X509** iter = IP_NULL;
Ipike_error err = IPIKE_SUCCESS;
/* Get trusted CA certs from local storage */
trusted = ipike_crypto_get_trusted_certs(conf->authentication.trusted_ca_store);
/* Create a certificate request payload for each trusted CA */
for (iter = trusted; iter && *iter; iter++)
{
payload = IP_NULL;
err = ipike_payload_certificate_req_create_v1(&payload, *iter);
if ( err != IPIKE_SUCCESS )
goto errout;
/* Add the payload if we have constructed on*/
if ( payload )
{
err = ipike_array_add((void***) reply_payloads, payload);
if (IPIKE_SUCCESS != err)
{
ipcom_free(payload);
goto errout;
}
}
}
errout:
ipike_array_free((void**) trusted, (void(*)(void*)) X509_free);
return err;
}
/*
*===========================================================================
* ipike_main_mode_update_responder_config
*===========================================================================
*/
IP_PUBLIC void
ipike_main_mode_update_responder_config(Ipike_isakmp_exchange *ie)
{
Ipike_sadb_entry* ike_sa;
Ipike_config_ike_sa *ike_conf;
Ipike_id* id;
ike_sa = ie->ike_sa;
id = &ike_sa->idii;
ike_conf = ipike_config_get_ike_sa_from_address_and_remote_id(ie,
&ie->msg.local_addr,
&ie->msg.peer_addr,
id->id_type,
&id->id_data,
ike_sa->cert.peer);
if ( IP_NULL != ike_conf && ike_conf != ie->ike_conf )
{
/* We found a differnet configuration that can be used */
ie->ike_conf = ike_conf;
/* Update IKE SA parameters */
if ( IP_NULL != ike_sa->id )
ipcom_free(ike_sa->id);
ike_sa->id = ipcom_strdup( ike_conf->ike_id );
IPCOM_LOG0(NOTICE, "ipike_main_mode_update_responder_config :: Updated IKE SA config selection based on 'remote_identifier'");
}
/* Fall through even if no matching configuration was found since and
* let the negotiation fail in the authentication check */
}
/*
*===========================================================================
* ipike_main_mode_authentication_check
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_main_mode_authentication_check(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ip_u16 auth_meth;
Ipike_transform_ike *transform;
Ipike_sadb_entry* ike_sa = ie->ike_sa;
X509** trusted = IP_NULL;
X509** ca = IP_NULL;
X509_CRL** crls = IP_NULL;
Ipike_id* id;
if (ike_sa->is_initiator)
id = &ike_sa->idir;
else
id = &ike_sa->idii;
/* Do we allow the remote peer access */
err = ipike_policy_accept_id(ie->ike_conf->remote_id,
id->id_type,
&id->id_data,
ike_sa->cert.peer);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG1(ERR, "ipike_main_mode_authentication_check() ::"\
" bad 'remote_identifier', err = %d", err);
goto error;
}
/* Authenticate */
err = ipike_main_mode_verify_auth(ie);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG1(ERR, "ipike_main_mode_authentication_check() ::"\
" failed to verify authentication data, err = %d",
err);
goto error;
}
transform = ipike_transform_ike_from_exch(ie);
if (transform == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_main_mode_authentication_check() ::"\
" null transform");
goto error;
}
auth_meth = transform->authentication_method;
if (auth_meth == IPIKE_ATTR_AUTH_DSS_SIGNATURES ||
auth_meth == IPIKE_ATTR_AUTH_RSA_SIGNATURES)
{
/* Check if a remote (HTTP) location of CRL is configured */
if ( ie->ike_conf->authentication.crl_store &&
ipcom_strncmp(ie->ike_conf->authentication.crl_store, "http://", 7) == 0 )
{
/* Fetching CRLs using CRL using http */
IPCOM_LOG1(DEBUG2, "ipike_main_mode_authentication_check() ::"\
" fetching crl via http \"%s\"",
ie->ike_conf->authentication.crl_store );
/* Verify certificate when we have received the CRL in the callback */
err = ipike_main_mode_http_get(ie,
ie->ike_conf->authentication.crl_store,
ipike_main_mode_http_get_crl_cb);
/* Failed to fetch CRL */
if ( IPIKE_SUCCESS != err )
{
err = IPIKE_AUTHENTICATION_FAILED;
IPCOM_LOG0(ERR, "ipike_main_mode_authentication_check() ::"\
" failed to fetch crl via http");
goto error;
}
/* Fetching CRLs via HTTP, break processing for now and continue
* when we have received the certificate */
return err;
}
else
{
ca = ipike_crypto_get_intermediate_ca_certs(
&ike_sa->cert,
ie->ike_conf->authentication.intermediate_ca_store);
trusted = ipike_crypto_get_trusted_certs(
ie->ike_conf->authentication.trusted_ca_store);
crls = ipike_crypto_read_crls(ie->ike_conf->authentication.crl_store);
if (trusted == IP_NULL)
{
IPCOM_LOG0(ERR,
"ipike_main_mode_authentication_check() ::"\
" failed to read trusted certificate");
err = IPIKE_INVALID_VALUE;
goto error;
}
#ifdef IPIKE_USE_OCSP
/* IKEv1 doesnt support OCSP define necessary for avoiding code
* duplication */
err = ipike_crypto_verify_certificate_ocsp(trusted, ca, ike_sa->cert.peer, crls, IP_NULL);
#else
err = ipike_crypto_verify_certificate(trusted, ca, ike_sa->cert.peer, crls);
#endif
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR,
"ipike_main_mode_update_after_msg_6: certificate verification failed");
goto error;
}
}
}
error:
ipike_array_free((void**) trusted, (void(*)(void*)) X509_free);
ipike_array_free((void**) ca, (void(*)(void*)) X509_free);
ipike_array_free((void**) crls, (void(*)(void*)) X509_CRL_free);
if (err)
{
/* Send a response and then destroy this exchange */
ie->send_and_destroy = IP_TRUE;
}
return err;
}
/*
*===========================================================================
* ipike_main_mode_on_new_exchange_initiator
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_on_new_exchange_initiator(
Ipike_isakmp_exchange* ie,
Ipike_sadb_entry* ike_sa,
const void* option1,
const void* trigger_flow)
{
Ipike_error err;
Ip_u8 initiator_cookie[IPIKE_ISAKMP_COOKIE_SIZE];
Ip_u8 responder_cookie[IPIKE_ISAKMP_COOKIE_SIZE];
union Ip_sockaddr_union peer_addr;
union Ip_sockaddr_union local_addr;
Ipike_config_flow *flow = IP_NULL;
/* IKE v1 */
ie->version = 1 << 4;
/* Store option1, only establish IKE SA if set */
ie->option1 = option1;
if (trigger_flow != IP_NULL)
{
/* Make a copy of the flow information, we will need to pass this
* further to the IPsec SA establishment */
flow = ipike_config_flow_duplicate(trigger_flow);
if (flow == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
/* Store the flow in the place holder for option2*/
ie->option2 = flow;
}
ipcom_microtime(&ie->start);
ipcom_memset(responder_cookie, 0, IPIKE_ISAKMP_COOKIE_SIZE);
err = ipike_crypto_generate_cookie(initiator_cookie);
if (IPIKE_SUCCESS != err)
return err;
/* Do we have an IKE SA, i.e. this is a reauthentication */
if (ike_sa != IP_NULL)
{
/* Use the same addresses and ports as the old IKE SA */
err = ipike_addr_copy(&local_addr, &ike_sa->local_addr);
if (IPIKE_SUCCESS != err)
return err;
err = ipike_addr_copy(&peer_addr, &ike_sa->peer_addr);
if (IPIKE_SUCCESS != err)
return err;
}
else
{
/* Use local address from configuration */
err = ipike_addr_copy(&local_addr, &ie->ike_conf->local_address);
if (IPIKE_SUCCESS != err)
return err;
/* Check if we have a valid host address in the configuration */
if ( ipike_config_netobj_is_host(&ie->ike_conf->remote_address) )
{
/* Use remote address from configuration */
err = ipike_addr_copy(&peer_addr,
&ie->ike_conf->remote_address.addr);
if (IPIKE_SUCCESS != err)
return err;
}
/* Was this negotiation triggered by a flow */
else if (flow != IP_NULL)
{
/* Use remote address from the trigger flow */
err = ipike_addr_copy(&peer_addr, &flow->dst[0]->addr);
if (IPIKE_SUCCESS != err)
return err;
}
else
{
/* No idea of the remote address */
return IPIKE_CONF_INVALID_VALUE;
}
/* Reset destination port to default IKE port (500) */
ipike_addr_set_port(&peer_addr, ipike.port);
}
if (ipike_addr_is_any(&local_addr))
{
/* Try to figure out our local address based on the peer address */
err = ipike_dispatcher_socket_local_addr_get(&local_addr,
&peer_addr);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(NOTICE,
"ipike_main_mode_on_new_exchange_initiator() ::"\
" failed to get local address");
/* Ignore error, the stack will find out the address
* eventually, however NAT-T will fail because of
* mismatching hashes */
}
}
err = ipike_sadb_add(initiator_cookie,
responder_cookie,
&local_addr,
&peer_addr,
&ie->ike_sa);
if (err != IPIKE_SUCCESS)
return err;
ie->is_phase1 = IP_TRUE;
ie->exchange_initiator = IP_TRUE;
ie->ike_sa->is_initiator = IP_TRUE;
ie->ike_sa->id = ipcom_strdup(ie->ike_conf->ike_id);
ie->ike_sa->version = ie->version;
ie->ike_sa->has_got_natt_capability = IP_FALSE;
return ipike_main_mode_update_state(ie);
}
/*
*===========================================================================
* ipike_main_mode_on_new_exchange_responder
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_on_new_exchange_responder(
Ipike_isakmp_exchange* ie,
Ipike_isakmp_header* first_isakmp,
union Ip_sockaddr_union* local_addr,
union Ip_sockaddr_union* peer_addr)
{
Ipike_error err;
Ip_u8 responder_cookie[IPIKE_ISAKMP_COOKIE_SIZE];
Ip_u8 retry;
ipcom_microtime(&ie->start);
/* IKE version 1 */
ie->version = 1 << 4;
if (first_isakmp->message_id != 0)
{
IPCOM_LOG0(ERR, "ipike_main_mode_on_new_exchange: message id must be zero in this exchange");
err = IPIKE_ISAKMP_INVALID_MESSAGE_ID;
}
else
{
retry = 0;
do {
if (retry++ > 100)
{
IPCOM_LOG0(ERR, "ipike_main_mode_on_new_exchange_responder: too many retries");
return IPIKE_FAILED;
}
/* Generate responder cookie until the initiator/responder
* cookie pair is unique */
if (IPIKE_SUCCESS != (err = ipike_crypto_generate_cookie(responder_cookie)))
return err;
} while (ipike_sadb_exist(first_isakmp->initiator_cookie, responder_cookie));
if (IPIKE_SUCCESS != (err = ipike_sadb_add(first_isakmp->initiator_cookie,
responder_cookie,
local_addr,
peer_addr,
&ie->ike_sa)))
{
IPCOM_LOG0(ERR, "ipike_main_mode_on_new_exchange_responder: failed to add sa");
}
else
{
ie->is_phase1 = IP_TRUE;
ie->ike_sa->is_initiator = IP_FALSE;
ie->ike_sa->id = ipcom_strdup(ie->ike_conf->ike_id);
ie->ike_sa->version = ie->version;
ie->ike_sa->has_got_natt_capability = IP_FALSE;
}
}
return err;
}
/*
*===========================================================================
* ipike_main_mode_on_delete_exchange
*===========================================================================
*/
IP_PUBLIC void
ipike_main_mode_on_delete_exchange(Ipike_isakmp_exchange* ie)
{
if (ie->ike_sa == IP_NULL)
return;
if (ie->message_number < ipike_isakmp_exchange_message_count(ie))
{
IPCOM_LOG0(WARNING,
"ipike_main_mode_on_delete_exchange: the exchange was not finished,"
" removing (incomplete) IKE SA");
(void) ipike_sadb_set_state(ie, ie->ike_sa, IPIKE_SA_DYING);
}
if (ie->option2)
ipike_config_flow_destroy((Ipike_config_flow *)ie->option2);
}
/*
*===========================================================================
* ipike_main_mode_get_payload_order
*===========================================================================
*/
IP_PUBLIC const Ip_u16 *
ipike_main_mode_get_payload_order(Ipike_isakmp_exchange* ie)
{
/* All authentication methods has #1 and #2 equal
and the authentication method can not be known
by the responder before processing #1 */
static Ip_u16 before_first_sa_processed[] = {
/* message # 1 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 2 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 3 */
IPIKE_PAYLOAD_NONE,
/* message # 4 */
IPIKE_PAYLOAD_NONE,
/* message # 5 */
IPIKE_PAYLOAD_NONE,
/* message # 6 */
IPIKE_PAYLOAD_NONE,
};
static Ip_u16 pre_shared_keys_payloads[] = {
/* message # 1 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 2 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 3 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 4 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 5 */
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NOTIFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 6 */
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NOTIFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
};
static Ip_u16 public_keys_sign_payloads[] = {
/* message # 1 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
/* message # 2 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
/* message # 3 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
/* message # 4 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
/* message # 5 */
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_CERTIFICATE | IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD,
IPIKE_PAYLOAD_SIGNATURE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NOTIFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
/* message # 6 */
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_CERTIFICATE | IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD,
IPIKE_PAYLOAD_SIGNATURE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NOTIFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_CERTIFICATE_REQUEST,
IPIKE_PAYLOAD_NONE,
};
static Ip_u16 public_keys_encrypt_payloads[] = {
/* message # 1 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 2 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 3 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 4 */
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 5 */
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 6 */
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
};
static Ip_u16 rev_public_keys_encrypt_payloads[] = {
/* message # 1 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 2 */
IPIKE_PAYLOAD_SECURITY_ASSOCIATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_ADD | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 3 */
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_CERTIFICATE,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 4 */
IPIKE_PAYLOAD_NONCE,
IPIKE_PAYLOAD_KEY_EXCHANGE,
IPIKE_PAYLOAD_IDENTFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NAT_DISCOVERY,
IPIKE_PAYLOAD_NONE,
/* message # 5 */
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
/* message # 6 */
IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_VENDOR_ID,
IPIKE_PAYLOAD_NONE,
};
static Ip_u16 *id_prot_payloads[] = {
before_first_sa_processed,
pre_shared_keys_payloads,
public_keys_sign_payloads,
public_keys_sign_payloads,
public_keys_encrypt_payloads,
rev_public_keys_encrypt_payloads
};
int i = 1;
int message_nr = ie->message_number;
Ip_u16 * ret;
Ip_u16 n = 0;
Ip_u16 auth_method = 0;
if (ipike_transform_ike_from_exch(ie) != IP_NULL)
auth_method = ipike_transform_ike_from_exch(ie)->authentication_method;
if (auth_method > IPIKE_ATTR_AUTH_COUNT)
return IP_NULL;
ret = id_prot_payloads[auth_method];
i = 1;
while (i != message_nr)
if (*ret++ == IPIKE_PAYLOAD_NONE)
i++;
/* Some optional must be added if we are using NAT traversal */
i = 0;
while (ret[i] != IPIKE_PAYLOAD_NONE)
{
n = (Ip_u16)(ret[i] & 0x3FFF);
if (n == IPIKE_PAYLOAD_NAT_DISCOVERY)
{
if (ipike.port_nat != 0 && ie->ike_sa->has_got_natt_capability)
ret[i] |= IPIKE_PAYLOAD_ADD;
else
ret[i] = (Ip_u16)(ret[i] & ~IPIKE_PAYLOAD_ADD);
}
/* Check policy for sending certificate and certificate request */
if ( auth_method != IPIKE_ATTR_AUTH_PRE_SHARED_KEY )
{
if ( n == IPIKE_PAYLOAD_CERTIFICATE )
{
if ( ipike_isakmp_should_send_certificate(ie) )
ret[i] |= IPIKE_PAYLOAD_ADD;
else
ret[i] = (Ip_u16)(ret[i] & ~IPIKE_PAYLOAD_ADD);
}
else if ( n == IPIKE_PAYLOAD_CERTIFICATE_REQUEST )
{
if ( ipike_isakmp_should_send_certificate_req(ie) )
ret[i] |= IPIKE_PAYLOAD_ADD;
else
ret[i] = (Ip_u16)(ret[i] & ~IPIKE_PAYLOAD_ADD);
}
}
i++;
}
return ret;
}
/*
*===========================================================================
* ipike_main_mode_process_payloads
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_process_payloads(
Ipike_isakmp_exchange *ie,
Ipike_isakmp_header *isakmp)
{
Ipike_payload_header *payload;
Ip_u8 this_payload;
Ipike_error err;
Ipike_payload_enum ctx;
/* Process payloads */
this_payload = isakmp->next_payload;
payload = ipike_first_payload(isakmp, &ctx);
err = IPIKE_SUCCESS;
while (payload != IP_NULL)
{
switch (this_payload)
{
case IPIKE_PAYLOAD_SECURITY_ASSOCIATION:
/* RFC2409 Section 5,
* The SA payload MUST precede all other payloads in a
* phase 1 exchange. */
if (IPIKE_PAYLOAD_SECURITY_ASSOCIATION != isakmp->next_payload)
return IPIKE_WRONG_PAYLOAD;
if (ie->ike_sa->is_initiator)
/* Free the SA that was sent to the responder */
ipike_sa_free(&ie->ike_sa->sa, IP_NULL);
else
{
/* Store the binary encoding of the SA from the initiator */
err = ipike_main_mode_store_sai_b(&ie->ike_sa->sai_b,
(Ipike_sa_payload*) payload);
if (IPIKE_SUCCESS != err)
break;
}
err = ipike_sa_extract(ie,
(Ipike_sa_payload*) payload,
&ie->ike_sa->sa);
break;
case IPIKE_PAYLOAD_KEY_EXCHANGE:
err = ipike_key_exchange_extract((Ipike_ke_payload*) payload,
ie->ike_sa->is_initiator ?
&ie->ike_sa->g_xr :
&ie->ike_sa->g_xi);
break;
case IPIKE_PAYLOAD_NONCE:
err = ipike_payload_nonce_extract((Ipike_nonce_payload*) payload,
ie->ike_sa->is_initiator ?
&ie->ike_sa->nr :
&ie->ike_sa->ni);
break;
case IPIKE_PAYLOAD_IDENTFICATION:
err = ipike_identification_ike_extract((Ipike_id_payload*) payload,
ie->ike_sa->sa.doi,
ie->ike_sa->is_initiator ?
&ie->ike_sa->idir :
&ie->ike_sa->idii);
break;
case IPIKE_PAYLOAD_HASH:
err = ipike_hash_extract((Ipike_hash_payload*) payload,
ie->ike_sa->is_initiator ?
&ie->ike_sa->hash_r :
&ie->ike_sa->hash_i);
break;
case IPIKE_PAYLOAD_NOTIFICATION:
err = ipike_notification_process_message(ie,
(Ipike_notification_payload*) payload);
break;
case IPIKE_PAYLOAD_CERTIFICATE:
err = ipike_payload_certificate_extract(
(Ipike_cert_payload*) payload,
&ie->ike_sa->cert);
break;
case IPIKE_PAYLOAD_CERTIFICATE_REQUEST:
ie->certificate_requested = IP_TRUE;
err = ipike_payload_certificate_req_extract_v1(
(Ipike_cert_req_payload*) payload,
&ie->ike_sa->cert);
break;
case IPIKE_PAYLOAD_SIGNATURE:
err = ipike_sign_extract((Ipike_sign_payload*) payload,
ie->ike_sa->is_initiator ?
&ie->ike_sa->sign_r :
&ie->ike_sa->sign_i);
break;
case IPIKE_PAYLOAD_VENDOR_ID:
err = ipike_payload_vendor_id_process(ie->ike_sa,
(Ipike_vendor_id_payload*) payload);
break;
case IPIKE_PAYLOAD_NAT_DISCOVERY:
err = ipike_nat_discovery_process(
ie->ike_sa,
(Ipike_nat_discovery_payload*) payload);
break;
default:
IPCOM_LOG2(ERR,
"ipike_main_mode_process_payloads() ::"\
" '%s' (%d) is an unsupported payload type",
ipike_payload_type_to_string(this_payload),
this_payload);
err = IPIKE_ISAKMP_UNSUPPORTED_PAYLOAD;
}
if (err != IPIKE_SUCCESS)
break;
this_payload = payload->next_payload;
payload = ipike_next_payload(&ctx);
}
ipike_free_payload_enumerator(&ctx);
if (err != IPIKE_SUCCESS)
{
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, ISAKMP_PACKET_ERROR,
&ie->ike_sa->peer_addr, &ie->ike_sa->local_addr,
0, IP_NULL);
return err;
}
return ipike_main_mode_update_state(ie);
}
/*
*===========================================================================
* ipike_main_mode_add_reply_payloads
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_add_reply_payloads(
Ipike_isakmp_exchange* ie,
Ipike_payload_header*** reply_payloads)
{
Ipike_error err = IPIKE_SUCCESS;
const Ip_u16* payload_ids = IP_NULL;
int i = 0;
Ipike_transform_ike *transform_ike;
if ( ie->ike_sa->error != IPIKE_SUCCESS )
return ie->ike_sa->error;
payload_ids = ipike_main_mode_get_payload_order(ie);
ip_assert(payload_ids != IP_NULL);
for (i = 0; payload_ids[i] != IPIKE_PAYLOAD_NONE; i++)
{
Ipike_payload_header* reply_payload = IP_NULL;
Ip_u8 payload_type;
if (IP_BIT_ISSET(payload_ids[i], IPIKE_PAYLOAD_OPT) &&
IP_BIT_ISSET(payload_ids[i], IPIKE_PAYLOAD_ADD) == IP_FALSE)
/* Only add the optional payload that had the IPIKE_PAYLOAD_ADD bit set */
continue;
payload_type = (Ip_u8) payload_ids[i];
switch (payload_type)
{
case IPIKE_PAYLOAD_SECURITY_ASSOCIATION:
err = ipike_sa_create(&ie->ike_sa->sa,
(Ipike_sa_payload**) &reply_payload);
if (err == IPIKE_SUCCESS && ie->ike_sa->is_initiator)
{
err = ipike_main_mode_store_sai_b(&ie->ike_sa->sai_b,
(Ipike_sa_payload*) reply_payload);
if (err != IPIKE_SUCCESS)
ipcom_free(reply_payload);
}
break;
case IPIKE_PAYLOAD_KEY_EXCHANGE:
err = ipike_key_exchange_create(ie->ike_sa->is_initiator ? &ie->ike_sa->g_xi : &ie->ike_sa->g_xr,
(Ipike_ke_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_IDENTFICATION:
err = ipike_identification_create(ie->ike_sa->is_initiator ? &ie->ike_sa->idii : &ie->ike_sa->idir,
(Ipike_id_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_HASH:
err = ipike_hash_create(ie->ike_sa->is_initiator ? &ie->ike_sa->hash_i : &ie->ike_sa->hash_r,
(Ipike_hash_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_NONCE:
err = ipike_payload_nonce_create(ie->ike_sa->is_initiator ? &ie->ike_sa->ni : &ie->ike_sa->nr,
(Ipike_nonce_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_CERTIFICATE:
err = ipike_main_mode_cert_create(ie->ike_conf,
(Ipike_cert_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_SIGNATURE:
err = ipike_sign_create(ie->ike_sa->is_initiator ? &ie->ike_sa->sign_i : &ie->ike_sa->sign_r,
(Ipike_sign_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_VENDOR_ID:
if ((IPIKE_SUCCESS == err) && (ipike.port_nat != 0))
{
err = ipike_payload_vendor_id_create(IPIKE_VENDOR_ID_NAT_T,
(Ipike_vendor_id_payload**) &reply_payload);
if (IPIKE_SUCCESS == err)
{
err = ipike_array_add((void***) reply_payloads, reply_payload);
if (IPIKE_SUCCESS != err)
ipcom_free(reply_payload);
}
}
if (IPIKE_SUCCESS == err)
{
err = ipike_payload_vendor_id_create(IPIKE_VENDOR_ID_DPD,
(Ipike_vendor_id_payload**) &reply_payload);
if (IPIKE_SUCCESS == err)
{
err = ipike_array_add((void***) reply_payloads, reply_payload);
if (IPIKE_SUCCESS != err)
ipcom_free(reply_payload);
}
}
reply_payload = IP_NULL;
break;
case IPIKE_PAYLOAD_NAT_DISCOVERY:
/* Always two payloads (local and peer) */
transform_ike = ipike_transform_ike_from_exch(ie);
if (transform_ike==IP_NULL)
{
err=IPIKE_FAILED;
goto error;
}
err = ipike_nat_discovery_create(&ie->ike_sa->peer_addr,
ie->ike_sa->initiator_cookie,
ie->ike_sa->responder_cookie,
transform_ike->hash_algorithm,
(Ipike_nat_discovery_payload**) &reply_payload);
if (IPIKE_SUCCESS == err)
err = ipike_array_add((void***) reply_payloads, reply_payload);
if (IPIKE_SUCCESS == err)
err = ipike_nat_discovery_create(&ie->ike_sa->local_addr,
ie->ike_sa->initiator_cookie,
ie->ike_sa->responder_cookie,
transform_ike->hash_algorithm,
(Ipike_nat_discovery_payload**) &reply_payload);
break;
case IPIKE_PAYLOAD_CERTIFICATE_REQUEST:
/* Request certificate if do not already have the peers certificate */
if ( !ie->ike_sa->cert.peer )
err = ipike_main_mode_add_cert_request(ie->ike_conf, reply_payloads);
break;
case IPIKE_PAYLOAD_NOTIFICATION:
case IPIKE_PAYLOAD_DELETE:
IPCOM_LOG1(ERR,
"Payload creation for '%s' is not implemented",
ipike_payload_type_to_string(payload_type));
err = IPIKE_NOT_IMPLEMENTED;
goto error;
default:
IPCOM_LOG1(ERR,
"Payload creation failed since %d is a unknown payload type",
payload_type);
err = IPIKE_ISAKMP_UNSUPPORTED_PAYLOAD;
goto error;
}
if (err != IPIKE_SUCCESS)
goto error;
if (reply_payload != IP_NULL)
{
if (IPIKE_SUCCESS != (err = ipike_array_add((void***) reply_payloads, reply_payload)))
{
ipcom_free(reply_payload);
goto error;
}
}
}
return IPIKE_SUCCESS;
error:
ipike_array_free((void**) *reply_payloads, ipcom_free); /*lint !e123 */
*reply_payloads = IP_NULL;
IPIKE_EVENT_LOG(IKE_PHASE_I_FAIL, IKE_INTERNAL_ERROR,
&ie->ike_sa->peer_addr, &ie->ike_sa->local_addr,
0, IP_NULL);
return err;
}
/*
*===========================================================================
* ipike_main_mode_cleartext_outgoing_message
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_cleartext_outgoing_message(
Ipike_isakmp_exchange* ie,
Ipike_isakmp_header** outgoing_isakmp)
{
(void) ie;
(void) outgoing_isakmp;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_main_mode_exchange_done
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_main_mode_exchange_done(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
ipike_sadb_free_intermediate(ie->ike_sa);
if (IPIKE_SUCCESS != (err = ipike_cpy_value(&ie->ike_sa->base_iv, &ie->iv)))
return err;
if (IPIKE_SUCCESS != (err = ipike_sadb_set_state(ie, ie->ike_sa, IPIKE_SA_ACTIVE)))
return err;
/* Set liveness */
ie->ike_sa->liveness.timeout = (Ip_u32) ie->ike_conf->liveness;
ipcom_microtime(&ie->stop);
IPCOM_LOG3(INFO, "Main mode exchange done in %d ms (peer: %s, Message ID: %d)",
(ie->stop.tv_sec - ie->start.tv_sec) * 1000 + (ie->stop.tv_usec - ie->start.tv_usec) / 1000,
ipike_addr_to_str(&ie->ike_sa->peer_addr),
ie->message_id);
(void)ipike_print_memory(IPCOM_LOG_DEBUG, "Final phase 1 (main mode) IV: ",
ie->iv.value, ie->iv.len);
if (ie->ike_conf->initial_contact && (ie->rekey_spi.len == 0))
ipike_informational_report_initial_contact(ie->ike_sa);
/* Initiate a quick mode exchange if we are the initiator and
* if option1 (only IKE) is not set */
if (ie->ike_sa->is_initiator && !ie->option1)
(void)ipike_isakmp_initiate_ipsec_exchanges(ie->ike_sa,
IP_NULL,
ie->option2);
return IPIKE_SUCCESS;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/