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

591 lines
20 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_exchange_informational.c,v $ $Revision: 1.20.10.7 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_exchange_informational.c,v $
* $Author: svc-cmnet $ $Date: 2013-10-30 23:37:40 $
* $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_informational.h"
#include "ipike_crypto.h"
#include "ipike_payload_delete.h"
#include "ipike_payload_hash.h"
#include "ipike_payload_notification.h"
#include "ipike_util.h"
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
* Checks if the DPD counter is in the window _base + IPIKE_DPD_WINDOW_SIZE
*/
#define IPIKE_IS_IN_DPD_WINDOW(_base, _counter) \
(((((_base) + IPIKE_DPD_WINDOW_SIZE) >= (_counter)) && \
((_base) < (_counter) )) || \
((((_base) + IPIKE_DPD_WINDOW_SIZE) < (_base)) && \
(((_counter) < (IPIKE_DPD_WINDOW_SIZE - (0xffffffffu-(_base)))) || \
((_base) < (_counter)))))
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_informational_on_new_exchange
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_informational_on_new_exchange(Ipike_isakmp_exchange* ie)
{
Ipike_error err;
Ipike_transform_ike *transform_ike;
/* IKE v1 */
ie->version = 1 << 4;
ipcom_microtime(&ie->start);
if (ie->ike_sa->state == IPIKE_SA_ACTIVE)
{
/* Messages must be protected */
ie->isakmp_flags = IPIKE_ISAKMP_ENCRYPTION;
transform_ike = ipike_transform_ike_from_exch(ie);
if (transform_ike==IP_NULL)
return IPIKE_FAILED;
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_phase2_iv(
transform_ike->hash_algorithm,
&ie->ike_sa->base_iv, ip_htonl(ie->message_id), &ie->iv)))
return err;
}
return IPIKE_SUCCESS;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_informational_on_new_exchange
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_on_new_exchange_initiator(
Ipike_isakmp_exchange* ie,
Ipike_sadb_entry* ike_sa,
const void* payload,
const void* not_used)
{
IPCOM_UNUSED_ARG(not_used);
ie->ike_sa = ike_sa;
ipike_sadb_lock(ie->ike_sa);
ie->phase2.notify_or_delete = (Ipike_payload_header*) payload;
ie->is_phase1 = IP_FALSE;
ie->exchange_initiator = IP_TRUE;
return ipike_informational_on_new_exchange(ie);
}
/*
*===========================================================================
* ipike_informational_on_new_exchange
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_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)
{
(void) local_addr;
(void) peer_addr;
if (ipike_sadb_get( first_isakmp->initiator_cookie,
first_isakmp->responder_cookie,
IPIKE_SA_ACTIVE | IPIKE_SA_CONSTRUCTING,
&ie->ike_sa) != IPIKE_SUCCESS)
{
IPCOM_LOG0(WARNING, "ipike_informational_on_new_exchange: IKE SA not found");
IPCOM_LOG1(WARNING, "initiator_cookie: %s",
ipike_cookie_to_string(first_isakmp->initiator_cookie));
IPCOM_LOG1(WARNING, "responder_cookie: %s",
ipike_cookie_to_string(first_isakmp->responder_cookie));
IPIKE_EVENT_LOG(IKE_PACKET_DISCARD, INVALID_SPI_ERROR,
peer_addr, local_addr, 0, IP_NULL);
return IPIKE_SA_NOT_FOUND;
}
return ipike_informational_on_new_exchange(ie);
}
/*
*===========================================================================
* ipike_informational_on_delete_exchange
*===========================================================================
*/
IP_PUBLIC void
ipike_informational_on_delete_exchange(Ipike_isakmp_exchange* ie)
{
if (ie->phase2.notify_or_delete)
IPIKE_FREEP(ie->phase2.notify_or_delete);
}
/*
*===========================================================================
* ipike_informational_get_payload_order
*===========================================================================
*/
IP_PUBLIC const Ip_u16 *
ipike_informational_get_payload_order(Ipike_isakmp_exchange *ie)
{
/* The hash payload must be included if a IKE SA
is established with the recipient.
The ISAKMP message must contain one notification payload
or one delete payload */
static Ip_u16 informational_exchange[] = {
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_HASH,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_NOTIFICATION,
IPIKE_PAYLOAD_OPT | IPIKE_PAYLOAD_DELETE,
IPIKE_PAYLOAD_NONE,
};
(void) ie;
return informational_exchange;
}
/*
*===========================================================================
* ipike_informational_process_payloads
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_process_payloads(Ipike_isakmp_exchange *ie, Ipike_isakmp_header *isakmp)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_payload_header* payload;
Ip_u8 this_payload;
Ipike_payload_enum ctx;
/* Process payloads */
this_payload = isakmp->next_payload;
payload = ipike_first_payload(isakmp, &ctx);
while (payload != IP_NULL)
{
switch (this_payload)
{
case IPIKE_PAYLOAD_HASH:
if(!(err = ipike_hash_extract((Ipike_hash_payload*) payload, &ie->hash)))
err = ipike_crypto_verify_hash(ie, isakmp);
break;
case IPIKE_PAYLOAD_NOTIFICATION:
err = ipike_notification_process_message(ie, (Ipike_notification_payload*) payload);
break;
case IPIKE_PAYLOAD_DELETE:
err = ipike_payload_delete_process_message(ie->ike_sa, (Ipike_delete_payload*) payload);
break;
default:
IPCOM_LOG2(ERR,
"ipike_informational_process_payloads: '%s' (%d) is an unsupported payload type",
ipike_payload_type_to_string(this_payload), this_payload);
err = IPIKE_ISAKMP_UNSUPPORTED_PAYLOAD;
break;
}
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_PACKET_DISCARD, ISAKMP_PACKET_ERROR,
&ie->msg.peer_addr, &ie->msg.local_addr,
0, IP_NULL);
return err;
}
/* We do not need this exchange anymore */
return IPIKE_EXCH_FINNISHED;
}
/*
*===========================================================================
* ipike_informational_add_reply_payloads
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_add_reply_payloads(
Ipike_isakmp_exchange* ie,
Ipike_payload_header*** reply_payload)
{
Ipike_error err;
Ipike_transform_ike* transform;
if (ie->ike_sa->state != IPIKE_SA_CONSTRUCTING)
{
/* We have a IKE SA, so the payloads should be encrypted and
a hash payload is needed.
The hash value will be calculated later, just add it so
enough memory will be allocated */
Ip_u8 hash_buffer[HMAC_MAX_MD_CBLOCK];
Ipike_value dummy_hash;
Ipike_hash_payload* hash_payload = IP_NULL;
transform = ipike_transform_ike_from_exch(ie);
if (transform==IP_NULL)
return IPIKE_FAILED;
dummy_hash.value = hash_buffer;
dummy_hash.len = ipike_attribute_get_digest_size(transform->hash_algorithm);
if (IPIKE_SUCCESS != (err = ipike_hash_create(&dummy_hash, &hash_payload)))
goto error;
if (IPIKE_SUCCESS != (err = ipike_array_add((void***) reply_payload, hash_payload)))
{
ipcom_free(hash_payload);
goto error;
}
}
if (IPIKE_SUCCESS != (err = ipike_array_add((void***) reply_payload, ie->phase2.notify_or_delete)))
goto error;
/* To avoid multiple releases of the memory for the delete/notify payload */
ie->phase2.notify_or_delete = IP_NULL;
error:
return err;
}
/*
*===========================================================================
* ipike_informational_cleartext_outgoing_message
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_cleartext_outgoing_message(
Ipike_isakmp_exchange* ie,
Ipike_isakmp_header** outgoing_isakmp)
{
Ipike_error err;
Ipike_isakmp_header *reply = *outgoing_isakmp;
if (ie->ike_sa->state != IPIKE_SA_CONSTRUCTING)
{
Ipike_value hash = { IP_NULL, 0};
Ipike_payload_header* hash_payload;
if (reply->next_payload != IPIKE_PAYLOAD_HASH)
{
IPCOM_LOG1(ERR,
"ipike_informational_cleartext_outgoing_message: malformed quick mode message, "
"the first payload must be a hash payload (not %s)",
ipike_payload_type_to_string(reply->next_payload));
return IPIKE_ISAKMP_INVALID_PAYLOAD;
}
if (IPIKE_SUCCESS != (err = ipike_crypto_compute_hash_1(ie->ike_sa, reply, &hash)))
return err;
hash_payload = (Ipike_payload_header *) ((Ip_u8*) reply + sizeof(Ipike_isakmp_header));
ip_assert(ip_ntohs(hash_payload->length) == IPIKE_HASH_HEADER_LENGTH + hash.len);
ipcom_memcpy((Ip_u8*) hash_payload + IPIKE_HASH_HEADER_LENGTH, hash.value, hash.len);
ipcom_free(hash.value);
}
else
{
if (reply->next_payload != IPIKE_PAYLOAD_NOTIFICATION &&
reply->next_payload != IPIKE_PAYLOAD_DELETE)
{
IPCOM_LOG1(ERR,
"ipike_informational_cleartext_outgoing_message: malformed quick mode message, "
"the second payload must be a notification or delete payload (not %s)",
ipike_payload_type_to_string(reply->next_payload));
return IPIKE_ISAKMP_INVALID_PAYLOAD;
}
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_informational_exchange_done
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_exchange_done(Ipike_isakmp_exchange* ie)
{
ipcom_microtime(&ie->stop);
IPCOM_LOG0(INFO, "informational exchange done");
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_informational_report_error
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_informational_report_error(
Ipike_sadb_entry* ike_sa,
Ipike_ipsec_sa_param* ipsec_sa,
Ipike_error error_code)
{
Ipike_error err;
Ip_u16 msg_type;
Ipike_value spi = { IP_NULL, 0 };
Ip_u8 isakmp_spi[IPIKE_ISAKMP_COOKIE_SIZE * 2];
Ip_u8 proto_id = IPIKE_PROTO_ISAKMP;
Ipike_notification_payload* notification;
if (IPIKE_SUCCESS != (err = ipike_notification_error_code_to_message_type(error_code, &msg_type)))
return err;
if (ike_sa->state == IPIKE_SA_CONSTRUCTING)
{
spi.value = isakmp_spi;
spi.len = sizeof(isakmp_spi);
ipcom_memcpy(isakmp_spi, ike_sa->initiator_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
ipcom_memcpy(isakmp_spi + IPIKE_ISAKMP_COOKIE_SIZE, ike_sa->responder_cookie,
IPIKE_ISAKMP_COOKIE_SIZE);
}
else if (ipsec_sa)
{
/* we are in phase 2 (quick mode) IPSec DOI */
Ipike_sa* inbound;
/* Even if ESP+AH accepted only report first transform SPI in
error message. ignore the second ! */
inbound = &ipsec_sa->inbound_sa;
if (inbound->proposals && inbound->selected_proposal >= 0)
{
proto_id = inbound->proposals[inbound->selected_proposal]->proto_id;
spi = inbound->proposals[inbound->selected_proposal]->spi;
}
}
notification = ipike_notification_new(IPIKE_DOI_IPSEC,
proto_id,
msg_type,
spi.value,
(Ip_u8) spi.len,
IP_NULL,
0);
if (IP_NULL == notification)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
return ipike_isakmp_initiate_informational_exchange(ike_sa, &notification->header);
}
/*
*===========================================================================
* ipike_informational_liveness
*===========================================================================
*/
IP_PUBLIC Ip_bool
ipike_informational_liveness(Ipike_sadb_entry* ike_sa, Ip_u32 counter)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_notification_payload* notification = IP_NULL;
Ip_u16 type = 0;
Ip_u8 spi_data[IPIKE_ISAKMP_COOKIE_SIZE * 2];
if (ike_sa->liveness.enabled)
{
if (counter == 0)
{
if (ike_sa->liveness.local_counter == 0)
{
(void)RAND_bytes((Ip_u8*)&ike_sa->liveness.local_counter, sizeof(ike_sa->liveness.local_counter));
ike_sa->liveness.local_counter &= 0x00ffffff;
}
/* Increase seqeuence number for each DPD R-U-THERE message */
ike_sa->liveness.local_counter++;
type = IPIKE_NOTI_R_U_THERE;
counter = ike_sa->liveness.local_counter;
}
else
{
/* Counter always incremented with one */
if (ike_sa->liveness.peer_counter == 0 ||
IPIKE_IS_IN_DPD_WINDOW(ike_sa->liveness.peer_counter, counter))
{
type = IPIKE_NOTI_R_U_THERE_ACK;
ike_sa->liveness.peer_counter = counter;
}
else
{
IPCOM_LOG1(WARNING, "ipike_informational_liveness() :: Received"\
" DPD sequence number '%d' is not acceptable",
counter);
}
}
/* Initiate exchange if not rejected */
if (type != 0)
{
counter = ip_htonl(counter);
ipcom_memcpy(spi_data, ike_sa->initiator_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
ipcom_memcpy(spi_data + IPIKE_ISAKMP_COOKIE_SIZE, ike_sa->responder_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
notification = ipike_notification_new(IPIKE_DOI_IPSEC,
IPIKE_PROTO_ISAKMP,
type,
spi_data,
sizeof(spi_data),
(Ip_u8*)&counter,
sizeof(counter));
if (IP_NULL == notification)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
err = ipike_isakmp_initiate_informational_exchange(ike_sa,
&notification->header);
}
}
}
return (err == IPIKE_SUCCESS);
}
/*
*===========================================================================
* ipike_informational_report_sa_delete
*===========================================================================
*/
IP_PUBLIC void
ipike_informational_report_sa_delete(
Ipike_sadb_entry* ike_sa,
Ip_u8 proto_id,
Ipike_value* spi)
{
Ipike_delete_payload *del;
del = ipike_payload_delete_new(IPIKE_DOI_IPSEC, proto_id, (Ip_u8) spi->len, spi->value);
if (IP_NULL == del)
{
IP_PANIC();
return;
}
(void) ipike_isakmp_initiate_informational_exchange(ike_sa, &del->header);
}
/*
*===========================================================================
* ipike_informational_report_initial_contact
*===========================================================================
*/
IP_PUBLIC void
ipike_informational_report_initial_contact(Ipike_sadb_entry* ike_sa)
{
Ipike_notification_payload* notify;
Ip_u8 spi_data[IPIKE_ISAKMP_COOKIE_SIZE * 2];
ipcom_memcpy(spi_data, ike_sa->initiator_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
ipcom_memcpy(spi_data + IPIKE_ISAKMP_COOKIE_SIZE, ike_sa->responder_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
notify = ipike_notification_new(IPIKE_DOI_IPSEC,
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INITIAL_CONTACT,
spi_data,
sizeof(spi_data),
IP_NULL,
0);
if (IP_NULL == notify)
{
IP_PANIC();
return;
}
(void) ipike_isakmp_initiate_informational_exchange(ike_sa, &notify->header);
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/