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

2406 lines
74 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipike2_payload_sa.c,v $ $Revision: 1.39.10.6 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike2_payload_sa.c,v $
* $Author: wdeng $ $Date: 2021-11-05 09:51:39 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* IKE v2 Security Association Payload */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPIKE_USE_VERSION2
#include "ipike_h.h"
#include "ipike_sadb.h"
#include "ipike_util.h"
#include "ipike_configuration.h"
#include "ipike_attributes.h"
#include "ipike_ipsec_attributes.h"
#include "ipike2_payload_sa.h"
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_payload_sa_header_size
*===========================================================================
* Description: Returns the size of the SA payload header.
* Parameters: sa - a pointer to a SA payload.
* Returns: The size (in bytes) of the SA payload header.
*
*/
IP_STATIC Ip_u16
ipike_payload_sa_header_size(void);
/*
*===========================================================================
* ipike_sa_proposal_proto_id_to_string
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC const char *
ipike_sa_proposal_proto_id_to_string(Ip_u8 proto);
/*
*===========================================================================
* ipike_sa_transform_type_to_string
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC const char *
ipike_sa_transform_type_to_string(Ip_u8 type);
/*
*===========================================================================
* ipike_sa_transform_id_to_string
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC const char *
ipike_sa_transform_id_to_string(Ip_u8 type, Ip_u16 id);
/*
*===========================================================================
* ipike_payload_sa_proposal_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike2_proposal_info*
ipike_payload_sa_proposal_data(Ipike2_sa_payload* sa);
/*
*===========================================================================
* ipike_payload_sa_proposal_length
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u16
ipike_payload_sa_proposal_length(Ipike2_sa_payload* sa);
/*
*===========================================================================
* ipike_payload_sa_transform_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike2_transform_info*
ipike_payload_sa_transform_data(Ipike2_proposal_info* p);
/*
*===========================================================================
* ipike_payload_sa_transform_length
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u16
ipike_payload_sa_transform_length(Ipike2_proposal_info* p);
/*
*===========================================================================
* ipike_payload_sa_attributes_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_attribute*
ipike_payload_sa_attributes_data(Ipike2_transform_info* t);
/*
*===========================================================================
* ipike_payload_sa_attributes_length
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u16
ipike_payload_sa_attributes_length(Ipike2_transform_info* t);
/*
*===========================================================================
* ipike_payload_sa_proposal_spi_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u8*
ipike_payload_sa_proposal_spi_data(Ipike2_proposal_info* p);
/*
*===========================================================================
* ipike_payload_sa_size
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u16
ipike_payload_sa_size(Ipike2_sa* sa);
/*
*===========================================================================
* ipike_payload_sa_next_proposal
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike2_proposal_info*
ipike_payload_sa_next_proposal(Ipike2_proposal_info* p);
/*
*===========================================================================
* ipike_payload_sa_next_transform
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike2_transform_info*
ipike_payload_sa_next_transform(Ipike2_transform_info* t);
/*
*===========================================================================
* ipike_payload_sa_next_attribute
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_attribute*
ipike_payload_sa_next_attribute(Ipike_attribute* a, Ip_size_t length);
/*
*===========================================================================
* ipike_payload_sa_proposal_chain_length
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_s32
ipike_payload_sa_proposal_chain_length(Ipike2_proposal_info* p, Ip_u32 size);
/*
*===========================================================================
* ipike_payload_sa_transform_chain_length
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_s32
ipike_payload_sa_transform_chain_length(Ipike2_transform_info* t, Ip_u32 size);
/*
*===========================================================================
* ipike_payload_sa_transform_check
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_payload_sa_transform_check(Ipike2_transform_info* t);
/*
*===========================================================================
* ipike_payload_sa_proposal_check
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_payload_sa_proposal_check(Ipike2_proposal_info* p);
/*
*===========================================================================
* ipike_transform_add_attribute
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_transform_add_attribute(
Ipike2_transform* transform,
Ip_u16 type,
const char* value);
/*
*===========================================================================
* ipike_transform_create
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_transform_create(
Ip_u8 type,
Ip_u16 id,
Ip_bool more,
Ipike2_transform** t);
/*
*===========================================================================
* ipike_free_transform
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipike_free_transform(Ipike2_transform* t);
/*
*===========================================================================
* ipike_proposal_add_transform
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_proposal_add_transform(
Ipike2_proposal* proposal,
Ip_u8 type,
Ip_u16 id);
/*
*===========================================================================
* ipike_proposal_get_algorithms
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC const char*
ipike_proposal_get_algorithms(
Ipike_config_proposal* proposal_conf,
Ip_u8 type);
/*
*===========================================================================
* ipike_sa_is_transform_allowed
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipike_sa_is_transform_allowed(Ip_u8 protocol, Ip_u8 type, Ip_u16 id);
/*
*===========================================================================
* ipike_proposal_add_transforms
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_proposal_add_transforms(
Ipike_config_proposal* proposal_conf,
Ip_u8 protocol,
Ip_u8 type,
Ipike2_proposal* proposal);
/*
*===========================================================================
* ipike_create_proposal
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_create_proposal(
Ipike_config_proposal* proposal_conf,
Ip_u8 proposal_number,
Ip_u8 protocol,
Ipike2_proposal** proposal);
/*
*===========================================================================
* ipike_create_proposals
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_create_proposals(
Ip_bool is_ike,
Ipike_config_proposal** proposals_conf,
Ipike2_proposal*** proposals);
/*
*===========================================================================
* ipike_free_proposal
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipike_free_proposal(Ipike2_proposal* p);
/*
*===========================================================================
* ipike_copy_attribute_value
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_size_t
ipike_copy_attribute_value(
Ipike_attribute * a,
Ip_u8 * data,
Ip_size_t size);
/*
*===========================================================================
* ipike_copy_transform_value
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_size_t
ipike_copy_transform_value(
Ipike2_transform * t,
Ip_u8 * data,
Ip_size_t size);
/*
*===========================================================================
* ipike_copy_transform_content
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_size_t
ipike_copy_transform_content(
Ip_bool more,
Ip_u8 type,
Ip_u16 id,
Ipike_attribute* attr,
Ip_u8* data,
Ip_size_t size);
/*
*===========================================================================
* ipike_copy_proposal_value
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_size_t
ipike_copy_proposal_value(
Ipike2_proposal* p,
Ip_u8 * data,
Ip_size_t size);
/*
*===========================================================================
* ipike_copy_proposal_value
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_size_t
ipike_copy_selected_proposal(
Ipike2_sa * sa,
Ip_u8 * data,
Ip_size_t size);
/*
*===========================================================================
* ipike_payload_sa_transform_extract
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_payload_sa_transform_extract(
Ipike2_transform_info* info,
Ipike2_transform* transform);
/*
*===========================================================================
* ipike_payload_sa_proposal_extract
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_payload_sa_proposal_extract(
Ipike2_proposal_info* info,
Ipike2_proposal* proposal);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_payload_sa_header_size
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_payload_sa_header_size(void)
{
return (Ip_u16)(sizeof(Ipike_payload_header));
}
/*
*===========================================================================
* ipike_sa_proposal_proto_id_to_string
*===========================================================================
*/
IP_STATIC const char *
ipike_sa_proposal_proto_id_to_string(Ip_u8 proto)
{
const char* s;
if ((ipike_map_string(ipike.proposal_proto_map, proto, &s)))
return "invalid security protocol id";
return s;
}
/*
*===========================================================================
* ipike_sa_transform_type_to_string
*===========================================================================
*/
IP_STATIC const char *
ipike_sa_transform_type_to_string(Ip_u8 type)
{
const char* s;
if ((ipike_map_string(ipike.transform_type_map, type, &s)))
return "invalid transform type";
return s;
}
/*
*===========================================================================
* ipike_sa_transform_id_to_string
*===========================================================================
*/
IP_STATIC const char *
ipike_sa_transform_id_to_string(Ip_u8 type, Ip_u16 id)
{
const char *s;
static char buf[32];
ipcom_sprintf(buf, "unknown transform id %d", (int)id);
switch (type)
{
case IPIKE_TRANSFORM_TYPE_ENCR:
if ((ipike_map_string(ipike.transform_encr_id_map, id, &s)))
return buf;
break;
case IPIKE_TRANSFORM_TYPE_PRF:
if ((ipike_map_string(ipike.transform_prf_id_map, id, &s)))
return buf;
break;
case IPIKE_TRANSFORM_TYPE_INTEG:
if ((ipike_map_string(ipike.transform_integ_id_map, id, &s)))
return buf;
break;
case IPIKE_TRANSFORM_TYPE_DH:
if ((ipike_map_string(ipike.transform_dh_id_map, id, &s)))
return buf;
break;
case IPIKE_TRANSFORM_TYPE_ESN:
if (id == 0)
return "off";
else
return "on";
default:
ipcom_sprintf(buf, "unknown transform type %u", type);
return buf;
}
return s;
}
/*
*===========================================================================
* ipike_payload_sa_proposal_data
*===========================================================================
*/
IP_STATIC Ipike2_proposal_info*
ipike_payload_sa_proposal_data(Ipike2_sa_payload* sa)
{
if (ip_htons(sa->header.length) <= ipike_payload_sa_header_size())
return IP_NULL;
return (Ipike2_proposal_info*)((Ip_u8*)sa + ipike_payload_sa_header_size());
}
/*
*===========================================================================
* ipike_payload_sa_proposal_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_payload_sa_proposal_length(Ipike2_sa_payload* sa)
{
if (ip_htons(sa->header.length) <= ipike_payload_sa_header_size())
return 0;
return (Ip_u16)(ip_htons(sa->header.length) - ipike_payload_sa_header_size());
}
/*
*===========================================================================
* ipike_payload_sa_transform_data
*===========================================================================
*/
IP_STATIC Ipike2_transform_info*
ipike_payload_sa_transform_data(Ipike2_proposal_info* p)
{
if (ip_htons(p->length) < (sizeof(*p) + p->spi_size))
return IP_NULL;
return (Ipike2_transform_info*)((Ip_u8*)p + sizeof(*p) + p->spi_size);
}
/*
*===========================================================================
* ipike_payload_sa_transform_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_payload_sa_transform_length(Ipike2_proposal_info* p)
{
if (ip_htons(p->length) < (sizeof(*p) + p->spi_size))
return 0;
return (Ip_u16)(ip_htons(p->length) - sizeof(*p) - p->spi_size);
}
/*
*===========================================================================
* ipike_payload_sa_attributes_data
*===========================================================================
*/
IP_STATIC Ipike_attribute *
ipike_payload_sa_attributes_data(Ipike2_transform_info* t)
{
if (ip_htons(t->length) <= sizeof(*t))
return IP_NULL;
return (Ipike_attribute*)((Ip_u8*)t + sizeof(*t));
}
/*
*===========================================================================
* ipike_payload_sa_attributes_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_payload_sa_attributes_length(Ipike2_transform_info* t)
{
if (ip_htons(t->length) <= sizeof(*t))
return 0;
return (Ip_u16)(ip_htons(t->length) - sizeof(*t));
}
/*
*===========================================================================
* ipike_payload_sa_proposal_spi_data
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_payload_sa_proposal_spi_data(Ipike2_proposal_info* p)
{
return ((Ip_u8*)p + sizeof(*p));
}
/*
*===========================================================================
* ipike_payload_sa_size
*===========================================================================
* Description: Return propsal size(s) for this SA in host endian
* Parameters:
* Returns:
*/
IP_STATIC Ip_u16
ipike_payload_sa_size(Ipike2_sa *sa)
{
int size;
if (sa->proposals == IP_NULL)
/* No proposals */
return 0;
size = (int) ipike_payload_sa_header_size();
if (sa->selected_proposal == -1)
{
/* -1 -> Total size of all proposals */
int i;
for (i = 0; i < sa->proposal_count; i++)
size += ip_ntohs(sa->proposals[i]->info.length);
}
else
{
/* Size of selected proposal only */
if (sa->selected_proposal < sa->proposal_count)
size += ip_ntohs(sa->proposals[sa->selected_proposal]->info.length);
}
return (Ip_u16) size;
}
/*
*===========================================================================
* ipike_payload_sa_next_proposal
*===========================================================================
*/
IP_STATIC Ipike2_proposal_info *
ipike_payload_sa_next_proposal(Ipike2_proposal_info *p)
{
if (p->more == 0)
return IP_NULL;
p = (Ipike2_proposal_info *)((Ip_u8 *)p + ip_htons(p->length));
return p;
}
/*
*===========================================================================
* ipike_payload_sa_next_transform
*===========================================================================
*/
IP_STATIC Ipike2_transform_info*
ipike_payload_sa_next_transform(Ipike2_transform_info* t)
{
if (t->more == 0)
return IP_NULL;
t = (Ipike2_transform_info*)((Ip_u8*)t + ip_htons(t->length));
return t;
}
/*
*===========================================================================
* ipike_payload_sa_next_attribute
*===========================================================================
*/
IP_STATIC Ipike_attribute*
ipike_payload_sa_next_attribute(Ipike_attribute* a, Ip_size_t length)
{
Ip_size_t n;
n = ipike_attribute_size(a);
if (length < n)
n = 0;
if (n == 0)
a = IP_NULL;
else
a = (Ipike_attribute*)((Ip_u8*)a + n);
return a;
}
/*
*===========================================================================
* ipike_payload_sa_proposal_chain_length
*===========================================================================
*/
IP_STATIC Ip_s32
ipike_payload_sa_proposal_chain_length(Ipike2_proposal_info* p, Ip_u32 size)
{
/* The proposals have same "header" format as payloads, so we can use
the next payload function */
return ipike_payload_chain_size((Ipike_payload_header*)p, size);
}
/*
*===========================================================================
* ipike_payload_sa_transform_chain_length
*===========================================================================
*/
IP_STATIC Ip_s32
ipike_payload_sa_transform_chain_length(Ipike2_transform_info* t, Ip_u32 size)
{
/* The transforms have same "header" format as payloads, so we can use
the next payload function */
return ipike_payload_chain_size((Ipike_payload_header*)t, size);
}
/*
*===========================================================================
* ipike_payload_sa_transform_check
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_sa_transform_check(Ipike2_transform_info* transform)
{
Ipike_attribute* attr;
Ip_size_t attr_len;
Ip_ssize_t attr_len_left;
Ip_size_t attr_total_size = 0; /* calculated total attribute size */
if (0 != IP_GET_NTOHS(&transform->reserved) ||
0 != IP_GET_NTOHS(&transform->reserved2))
{
IPCOM_LOG0(ERR, "the reserved field of the transform field is not zero");
return IPIKE_ISAKMP_INVALID_PAYLOAD;
}
if (transform->more != IPIKE_PAYLOAD_NONE &&
transform->more != IPIKE_PAYLOAD_TRANSFORM)
{
IPCOM_LOG3(ERR,
"invalid 'next payload' (%d) in field in the transform payload, only %d and %d are allowed",
(int) transform->more, IPIKE_PAYLOAD_NONE, IPIKE_PAYLOAD_TRANSFORM);
return IPIKE_WRONG_PAYLOAD;
}
attr = (Ipike_attribute*)((Ip_u8*)transform + sizeof(Ipike2_transform_info));
attr_len = attr_len_left = IP_GET_NTOHS(&transform->length) - sizeof(Ipike2_transform_info);
if (attr_len_left == 0)
{
/* No attributes in this transform */
return IPIKE_SUCCESS;
}
if (attr_len_left < 0 || attr_len_left < (Ip_ssize_t)sizeof(Ipike_attribute))
return IPIKE_ISAKMP_INVALID_PAYLOAD;
while (attr)
{
attr_total_size += ipike_attribute_size(attr);
attr = ipike_next_attribute(attr, &attr_len_left);
}
if (attr_total_size > attr_len)
{
IPCOM_LOG2(ERR,
"the transform payload is too small to hold all attributes (%d > %d)",
attr_total_size,
attr_len);
return IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_sa_proposal_check
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_sa_proposal_check(Ipike2_proposal_info* p)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike2_transform_info* transform;
Ip_u32 total_length;
Ip_s32 chain_length;
Ip_u8 detected_transforms = 0;
/* Must have at least one transform */
if (p->transform_count == 0)
{
IPCOM_LOG0(ERR,
"ipike_check_proposal_payload: the propsal does not have any transforms");
err = IPIKE_ISAKMP_INVALID_PAYLOAD;
return err;
}
else
{
transform = ipike_payload_sa_transform_data(p);
if (transform==IP_NULL)
{
IPCOM_LOG0(ERR,
"The transforms extends beyond the end of the proposal");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
return err;
}
total_length = ipike_payload_sa_transform_length(p);
chain_length = ipike_payload_sa_transform_chain_length(transform, total_length);
if (chain_length < 0)
{
IPCOM_LOG0(ERR,
"The transforms extends beyond the end of the proposal");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
else if (chain_length != (Ip_s32) total_length)
{
IPCOM_LOG0(ERR,
"The transforms is not as long as indicated by the proposal");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
else
{
for (;IP_NULL != transform;
transform = ipike_payload_sa_next_transform(transform))
{
if (IPIKE_SUCCESS != (err = ipike_payload_sa_transform_check(transform)))
break;
detected_transforms++;
}
if ((IPIKE_SUCCESS != err) ||
(detected_transforms != p->transform_count))
{
IPCOM_LOG2(ERR,
"The propsal indicates %d transforms, %d was found",
(int)p->transform_count, (int)detected_transforms);
err = IPIKE_ISAKMP_INVALID_PAYLOAD;
}
}
}
return err;
}
/*
*===========================================================================
* ipike_transform_add_attribute
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_transform_add_attribute(
Ipike2_transform* transform,
Ip_u16 type,
const char* value)
{
Ipike_error err;
Ipike_attribute* attr;
Ip_u16 n;
switch (type)
{
case IPIKE_ATTR_CLS_KEY_LENGTH:
err = ipike_attribute_key_length_from_enc_alg_string_v2(value, &n);
if (IPIKE_SUCCESS != err)
return err;
if (n == 0) /* default length, no need to specify length */
return IPIKE_SUCCESS;
attr = ipcom_malloc(sizeof(*attr));
if (IP_NULL == attr)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
attr->type = ip_htons(IPIKE_ATTR_BASIC | type);
attr->value = ip_htons(n*8);
if (IPIKE_SUCCESS != (err = ipike_array_add((void***)&transform->attributes, attr)))
{
ipcom_free(attr);
return err;
}
transform->info.length = ip_ntohs(transform->info.length);
transform->info.length = (Ip_u16)(transform->info.length + sizeof(Ipike_attribute));
transform->info.length = ip_htons(transform->info.length);
break;
default:
IP_PANIC(); /* Should never happen */
return IPIKE_FAILED;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_transform_create
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_transform_create(
Ip_u8 type,
Ip_u16 id,
Ip_bool more,
Ipike2_transform** t)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike2_transform* transform;
if (IP_NULL == (transform = ipcom_calloc(1, sizeof(Ipike2_transform))))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
transform->info.type = type;
transform->info.id = ip_htons(id);
transform->info.more = (Ip_u8)(more ? 0x03 : 0x00);
transform->info.length = ip_htons(sizeof(Ipike2_transform_info));
*t = transform;
}
return err;
}
/*
*===========================================================================
* ipike_free_transform
*===========================================================================
*/
IP_STATIC void
ipike_free_transform(Ipike2_transform* t)
{
ipike_array_free((void**) t->attributes, ipcom_free);
ipcom_memset(t, 0, sizeof(Ipike2_transform));
ipcom_free(t);
}
/*
*===========================================================================
* ipike_proposal_add_transform
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_proposal_add_transform(
Ipike2_proposal* proposal,
Ip_u8 type,
Ip_u16 id)
{
Ipike_error err;
Ipike2_transform* transform;
if (IPIKE_SUCCESS != (err = ipike_transform_create(type, id, IP_TRUE, &transform)))
{
IPCOM_LOG0(ERR, "ipike_proposal_add_transform: Failed to add transform");
}
else if (IPIKE_SUCCESS != (err = ipike_array_add((void***) &proposal->transforms, transform)))
{
IPCOM_LOG0(ERR, "ipike_proposal_add_transform: Failed to add transform");
ipcom_free(transform);
}
else
{
/* Update length of proposal (length host order) */
proposal->info.length = (Ip_u16)(proposal->info.length +
ip_ntohs(transform->info.length));
proposal->info.transform_count++;
}
return err;
}
/*
*===========================================================================
* ipike_proposal_get_algorithms
*===========================================================================
*/
IP_STATIC const char*
ipike_proposal_get_algorithms(
Ipike_config_proposal* proposal_conf,
Ip_u8 type)
{
switch (type)
{
case IPIKE_TRANSFORM_TYPE_DH:
return proposal_conf->dh_group;
case IPIKE_TRANSFORM_TYPE_ENCR:
return proposal_conf->encryption_alg;
case IPIKE_TRANSFORM_TYPE_PRF:
return proposal_conf->hash_alg;
case IPIKE_TRANSFORM_TYPE_INTEG:
return proposal_conf->integrity_alg;
default:
IP_PANIC();
break;
}
return IP_NULL;
}
/*
*===========================================================================
* ipike_sa_is_transform_allowed
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_sa_is_transform_allowed(
Ip_u8 protocol,
Ip_u8 type,
Ip_u16 id)
{
if ((protocol == IPIKE_PROTO_IPSEC_ESP || protocol == IPIKE_PROTO_IPSEC_AH) &&
type == IPIKE_TRANSFORM_TYPE_PRF)
return IP_FALSE;
if (protocol == IPIKE_PROTO_ISAKMP && type == IPIKE_TRANSFORM_TYPE_ENCR &&
(id == IPIKE_ENCR_NULL || id == IPIKE_ENCR_AES_CTR))
{
IPCOM_LOG1(DEBUG, "ipike_sa_is_transform_allowed() :: "\
"algorithm '%s' not allowed for ISKAMP",
ipike_attribute_encryption_alg_to_string_v2(id));
return IP_FALSE;
}
return IP_TRUE;
}
/*
*===========================================================================
* ipike_proposal_add_transforms
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_proposal_add_transforms(
Ipike_config_proposal *proposal_conf,
Ip_u8 protocol,
Ip_u8 type,
Ipike2_proposal *proposal)
{
Ipike_error err = IPIKE_SUCCESS;
const char* str;
char** vec;
Ip_u32 i;
Ip_u16 id;
Ipike2_transform *transform;
str = ipike_proposal_get_algorithms(proposal_conf, type);
if (str == IP_NULL)
return IPIKE_SUCCESS; /* none available */
vec = ipike_strvec(str, ", ");
if (vec == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
for (i = 0; vec[i] != IP_NULL && err == IPIKE_SUCCESS; i++)
{
id = ipike_sa_transform_id_from_string(type, vec[i]);
if ((id != 0) && ipike_sa_is_transform_allowed(protocol, type, id))
{
if (IPIKE_SUCCESS != (err = ipike_transform_create(type, id, IP_TRUE, &transform)))
{
IPCOM_LOG0(ERR, "ipike_proposal_add_transforms: Failed to create transform");
}
/* Add optional key length */
else if (type == IPIKE_TRANSFORM_TYPE_ENCR
&& (IPIKE_SUCCESS != (err = ipike_transform_add_attribute(transform, IPIKE_ATTR_CLS_KEY_LENGTH, vec[i]))))
{
IPCOM_LOG0(ERR, "ipike_proposal_add_transforms: Failed to add key length");
ipcom_free(transform);
}
else if (IPIKE_SUCCESS != (err = ipike_array_add((void***) &proposal->transforms, transform)))
{
IPCOM_LOG0(ERR, "ipike_proposal_add_transforms: Failed to add transform");
ipcom_free(transform);
}
else
{
proposal->info.transform_count++;
proposal->info.length = (Ip_u16)(proposal->info.length +
ip_htons(transform->info.length));
}
}
}
ipike_array_free((void**)vec, ipcom_free);
return err;
}
/*
*===========================================================================
* ipike_create_proposal
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_create_proposal(
Ipike_config_proposal* proposal_conf,
Ip_u8 proposal_number,
Ip_u8 protocol,
Ipike2_proposal **proposal)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike2_proposal *p;
p = ipcom_calloc(1, sizeof(Ipike2_proposal));
if (p == IP_NULL)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
p->info.proto_id = protocol;
err = ipike_proposal_add_transforms(proposal_conf, protocol, IPIKE_TRANSFORM_TYPE_DH, p);
if (err != IPIKE_SUCCESS)
goto errout;
if (protocol == IPIKE_PROTO_ISAKMP)
{
err = ipike_proposal_add_transforms(proposal_conf, protocol, IPIKE_TRANSFORM_TYPE_PRF, p);
if (err != IPIKE_SUCCESS)
goto errout;
}
if (protocol != IPIKE_PROTO_IPSEC_AH)
{
err = ipike_proposal_add_transforms(proposal_conf, protocol, IPIKE_TRANSFORM_TYPE_ENCR, p);
if (err != IPIKE_SUCCESS)
goto errout;
}
err = ipike_proposal_add_transforms(proposal_conf, protocol, IPIKE_TRANSFORM_TYPE_INTEG, p);
if (err != IPIKE_SUCCESS)
goto errout;
/* Add ESN for AH/ESP (default false=0) */
if ((p->info.proto_id == IPIKE_PROTO_IPSEC_ESP || p->info.proto_id == IPIKE_PROTO_IPSEC_AH)
&& !ipike_proposal_has_transform_type(p, IPIKE_TRANSFORM_TYPE_ESN))
{
/* If use_esn isn't specified or set to 'any' */
if ( proposal_conf->use_esn == IP_NULL ||
ipcom_strstr(proposal_conf->use_esn, "any") != IP_NULL)
{
/* Default is ESN both on (let responder choose) */
err = ipike_proposal_add_transform(p, IPIKE_TRANSFORM_TYPE_ESN, 1);
if (err != IPIKE_SUCCESS)
goto errout;
err = ipike_proposal_add_transform(p, IPIKE_TRANSFORM_TYPE_ESN, 0);
if (err != IPIKE_SUCCESS)
goto errout;
}
else
{
if (ipcom_strstr(proposal_conf->use_esn, "on") != IP_NULL)
{
err = ipike_proposal_add_transform(p, IPIKE_TRANSFORM_TYPE_ESN, 1);
if (err != IPIKE_SUCCESS)
goto errout;
}
if (ipcom_strstr(proposal_conf->use_esn, "off") != IP_NULL)
{
err = ipike_proposal_add_transform(p, IPIKE_TRANSFORM_TYPE_ESN, 0);
if (err != IPIKE_SUCCESS)
goto errout;
}
}
IPCOM_LOG1(DEBUG2,"use_esn from config: %s \n",
proposal_conf->use_esn ? proposal_conf->use_esn : "any");
}
if (p->info.transform_count == 0)
{
IPCOM_LOG0(ERR, "ipike_create_proposal: at least 1 transform must be specified");
err = IPIKE_SA_NO_VALID_TRANSFORM_CONFIGURED;
goto errout;
}
/* Mark last transform as ending */
p->transforms[p->info.transform_count-1]->info.more = 0;
p->info.length = (Ip_u16)(p->info.length + sizeof(p->info));
p->info.number = proposal_number;
*proposal = p;
/* Store length in correct byte-order */
p->info.length = ip_htons(p->info.length);
/* Success */
return IPIKE_SUCCESS;
/* Failure */
errout:
ip_assert(err != IPIKE_SUCCESS);
ipcom_free(p);
return err;
}
/*
*===========================================================================
* ipike_create_proposals
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_create_proposals(
Ip_bool is_ike,
Ipike_config_proposal** proposals_conf,
Ipike2_proposal*** proposals)
{
Ipike_error err = IPIKE_FAILED;
Ipike2_proposal* p;
Ip_u8 i;
Ip_u8 num;
if (proposals_conf != IP_NULL)
{
for (i = 0; i < 100 && IP_NULL != proposals_conf[i]; i++)
{
if ((proposals_conf[i]->number % 0xff) != 0)
num = (Ip_u8)(proposals_conf[i]->number);
else
num = (Ip_u8)(i + 1);
if (is_ike)
err = ipike_create_proposal(proposals_conf[i], num, IPIKE_PROTO_ISAKMP, &p);
else if (IP_NULL == proposals_conf[i]->encryption_alg)
err = ipike_create_proposal(proposals_conf[i], num, IPIKE_PROTO_IPSEC_AH, &p);
else
err = ipike_create_proposal(proposals_conf[i], num, IPIKE_PROTO_IPSEC_ESP, &p);
if (err != IPIKE_SUCCESS)
break;
if (IPIKE_SUCCESS != (err = ipike_array_add((void***) proposals, p)))
{
ipcom_free(p);
break;
}
if (proposals_conf[i+1] == IP_NULL)
p->info.more = 0; /* Last propsal */
else
p->info.more = 2; /* Always 2 for proposals */
}
}
if (err != IPIKE_SUCCESS)
{
ipike_array_free((void**)*proposals, ipcom_free);
*proposals = IP_NULL;
}
return err;
}
/*
*===========================================================================
* ipike_free_proposal
*===========================================================================
*/
IP_STATIC void
ipike_free_proposal(Ipike2_proposal* p)
{
ipike_array_free((void**) p->transforms, (void(*)(void*)) ipike_free_transform);
ipcom_memset(p, 0, sizeof(Ipike2_proposal));
ipcom_free(p);
}
/*
*===========================================================================
* ipike_copy_attribute_value
*===========================================================================
*/
IP_STATIC Ip_size_t
ipike_copy_attribute_value(
Ipike_attribute * a,
Ip_u8 * data,
Ip_size_t size)
{
Ip_size_t length;
if (IPIKE_ATTR_AF(ip_htons(a->type)))
length = sizeof(*a);
else
length = sizeof(*a) + ip_htons(a->value);
if (size >= length)
ipcom_memcpy((void*)data, (void*)a, length);
else
length = 0;
return length;
}
/*
*===========================================================================
* ipike_copy_transform_value
*===========================================================================
*/
IP_STATIC Ip_size_t
ipike_copy_transform_value(
Ipike2_transform * t,
Ip_u8 * data,
Ip_size_t size)
{
Ip_size_t length = 0;
Ip_size_t length2 = 0;
Ip_u8 i;
/* Should always be enough area, so just ignore value if buffer too small */
if (size >= ip_htons(t->info.length))
{
length2 = sizeof(t->info);
ipcom_memcpy((void*)data, (void*)&t->info, length2);
/* Move buffer forward */
data += length2;
length += length2;
size -= length2;
/* Copy all eventual attributes */
if (t->attributes != IP_NULL)
{
for (i=0; t->attributes[i] != IP_NULL; i++)
{
length2 = ipike_copy_attribute_value(t->attributes[i], data, size);
/* Move buffer forward */
data += length2;
length += length2;
size -= length2;
}
}
ip_assert(length == ip_htons(t->info.length));
}
return length;
}
/*
*===========================================================================
* ipike_copy_transform_content
*===========================================================================
*/
IP_STATIC Ip_size_t
ipike_copy_transform_content(
Ip_bool more,
Ip_u8 type,
Ip_u16 id,
Ipike_attribute* attr,
Ip_u8* data,
Ip_size_t size)
{
Ip_size_t length;
Ipike2_transform transform;
ipcom_memset(&transform, 0, sizeof(transform));
transform.info.more = (Ip_u8)(more ? 0x03 : 0x00);
transform.info.length = sizeof(transform.info);
if (IP_NULL != attr)
transform.info.length = (Ip_u16)(transform.info.length +
ipike_attribute_size(attr));
transform.info.length = ip_htons(transform.info.length);
transform.info.type = type;
transform.info.id = ip_htons(id);
transform.attributes = IP_NULL;
if (IP_NULL != attr)
if (IPIKE_SUCCESS != ipike_array_add((void***)&transform.attributes, attr))
return 0;
length = ipike_copy_transform_value(&transform, data, size);
ipike_array_free((void**)transform.attributes, IP_NULL);
return length;
}
/*
*===========================================================================
* ipike_copy_proposal_value
*===========================================================================
*/
IP_STATIC Ip_size_t
ipike_copy_proposal_value(
Ipike2_proposal * p,
Ip_u8 * data,
Ip_size_t size)
{
Ip_size_t length = 0;
Ip_size_t length2 = 0;
Ip_u8 i;
/* Size should be enough, so just ignore if too small */
ip_assert(size >= ip_htons(p->info.length));
if (size >= ip_htons(p->info.length))
{
/* Copy info part */
length2 = sizeof(p->info);
ipcom_memcpy((void*)data, (void*)&p->info, length2);
data += length2;
length += length2;
size -= length2;
/* Copy in optional SPI */
if (p->info.spi_size != 0)
{
length2 = p->info.spi_size;
ipcom_memcpy(data, p->spi, length2);
data += length2;
length += length2;
size -= length2;
}
/* Copy all transforms */
for (i = 0; p->transforms[i] != IP_NULL; i++)
{
length2 = ipike_copy_transform_value(p->transforms[i], data, size);
data += length2;
length += length2;
size -= length2;
}
ip_assert(i == p->info.transform_count);
ip_assert(length == ip_htons(p->info.length));
}
return length;
}
/*
*===========================================================================
* ipike_copy_proposal_value
*===========================================================================
*/
IP_STATIC Ip_size_t
ipike_copy_selected_proposal(
Ipike2_sa * sa,
Ip_u8 * data,
Ip_size_t size)
{
Ip_size_t n;
Ipike2_proposal_info* info;
Ipike_attribute attr;
Ip_bool more;
/* Proposal header */
info = (Ipike2_proposal_info*)data;
ipcom_memset(info, 0, sizeof(*info));
info->proto_id = sa->proposals[sa->selected_proposal]->info.proto_id;
info->number = sa->proposals[sa->selected_proposal]->info.number;
n = sizeof(Ipike2_proposal_info);
data += n;
size -= n;
info->length = (Ip_u16) n;
/* Proposal spi */
n = sa->proposals[sa->selected_proposal]->info.spi_size;
ipcom_memcpy(data, sa->proposals[sa->selected_proposal]->spi, n);
data += n;
size -= n;
info->spi_size = (Ip_u8)n;
info->length = (Ip_u16)(info->length + n);
/* Add the selected transforms */
if (sa->selected_esn != IPIKE_TRANSFORM_UNKNOWN)
{
more = ((sa->selected_encr != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_integ != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_prf != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_dh != IPIKE_TRANSFORM_UNKNOWN));
n = ipike_copy_transform_content(more,
IPIKE_TRANSFORM_TYPE_ESN,
sa->selected_esn,
IP_NULL,
data,
size);
data += n;
size -= n;
info->transform_count++;
info->length = (Ip_u16)(info->length + n);
}
if (sa->selected_encr != IPIKE_TRANSFORM_UNKNOWN)
{
more = ((sa->selected_integ != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_prf != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_dh != IPIKE_TRANSFORM_UNKNOWN));
/* Only DES and 3DES have default key lengths */
if ((sa->selected_key_length != 0) &&
(sa->selected_encr != IPIKE_ENCR_DES) &&
(sa->selected_encr != IPIKE_ENCR_3DES))
{
attr.type = (Ip_u16)(IPIKE_ATTR_BASIC | IPIKE_ATTR_CLS_KEY_LENGTH);
attr.type = ip_htons(attr.type);
attr.value = (Ip_u16)(sa->selected_key_length*8);
attr.value = ip_htons(attr.value);
n = ipike_copy_transform_content(more,
IPIKE_TRANSFORM_TYPE_ENCR,
sa->selected_encr,
&attr,
data,
size);
}
else
{
n = ipike_copy_transform_content(more,
IPIKE_TRANSFORM_TYPE_ENCR,
sa->selected_encr,
IP_NULL,
data,
size);
}
data += n;
size -= n;
info->transform_count++;
info->length = (Ip_u16) (info->length + n);
}
if (sa->selected_integ != IPIKE_TRANSFORM_UNKNOWN)
{
more = ((sa->selected_prf != IPIKE_TRANSFORM_UNKNOWN) ||
(sa->selected_dh != IPIKE_TRANSFORM_UNKNOWN));
n = ipike_copy_transform_content(more,
IPIKE_TRANSFORM_TYPE_INTEG,
sa->selected_integ,
IP_NULL,
data,
size);
data += n;
size -= n;
info->transform_count++;
info->length = (Ip_u16)(info->length + n);
}
if (sa->selected_prf != IPIKE_TRANSFORM_UNKNOWN)
{
more = (sa->selected_dh != IPIKE_TRANSFORM_UNKNOWN);
n = ipike_copy_transform_content(more,
IPIKE_TRANSFORM_TYPE_PRF,
sa->selected_prf,
IP_NULL,
data,
size);
data += n;
size -= n;
info->transform_count++;
info->length = (Ip_u16)(info->length + n);
}
if (sa->selected_dh != IPIKE_TRANSFORM_UNKNOWN)
{
n = ipike_copy_transform_content(IP_FALSE,
IPIKE_TRANSFORM_TYPE_DH,
sa->selected_dh,
IP_NULL,
data,
size);
data += n;
size -= n;
info->transform_count++;
info->length = (Ip_u16)(info->length + n);
}
info->length = ip_htons(info->length);
return (ip_htons(info->length));
}
/*
*===========================================================================
* ipike_payload_sa_transform_extract
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_sa_transform_extract(
Ipike2_transform_info* info,
Ipike2_transform* transform)
{
Ipike_attribute* attr;
Ipike_attribute* attr2;
Ip_size_t length;
Ip_size_t size;
ipcom_memcpy((void*)&transform->info, (void*)info, sizeof(*info));
length = ipike_payload_sa_attributes_length(info);
if (length > 0)
{
attr = ipike_payload_sa_attributes_data(info);
while (attr != IP_NULL)
{
size = ipike_attribute_size(attr);
ip_assert(size <= length);
if (size > 0)
{
attr2 = ipcom_malloc(size);
if (IP_NULL == attr2)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
ipcom_memcpy((void*)attr2, (void*)attr, size);
if (IPIKE_SUCCESS != ipike_array_add((void***)&transform->attributes, attr2))
{
ipcom_free(attr2);
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
}
length -= size;
attr = ipike_payload_sa_next_attribute(attr, length);
}
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_sa_proposal_extract
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_sa_proposal_extract(
Ipike2_proposal_info* info,
Ipike2_proposal* proposal)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike2_transform_info* transform_info;
Ipike2_transform* transform;
ipcom_memcpy((void*)&proposal->info, (void*)info, sizeof(*info));
if (info->spi_size != 0)
{
if ( info->spi_size > sizeof(proposal->spi) )
return IPIKE_FAILED;
ipcom_memcpy(proposal->spi, ipike_payload_sa_proposal_spi_data(info), info->spi_size);
}
transform_info = ipike_payload_sa_transform_data(info);
while ((err == IPIKE_SUCCESS) && (transform_info != IP_NULL))
{
if (IP_NULL == (transform = ipcom_calloc(1, sizeof(Ipike2_transform))))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else if (IPIKE_SUCCESS != (err = ipike_payload_sa_transform_extract(transform_info, transform)))
{
ipike_free_transform(transform);
IPCOM_LOG0(DEBUG, "ipike_payload_sa_proposal_extract: failed to extract transform");
}
else if (IPIKE_SUCCESS != (err = ipike_array_add((void***)&proposal->transforms, transform)))
{
ipike_free_transform(transform);
IPCOM_LOG0(DEBUG, "ipike_payload_sa_proposal_extract: failed to add transform to array");
}
transform_info = ipike_payload_sa_next_transform(transform_info);
}
return err;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_sa_transform_id_available
*===========================================================================
*/
IP_GLOBAL Ip_bool
ipike_sa_transform_id_available(Ip_u8 type, Ip_u16 id)
{
const char* s;
id = ip_ntohs(id);
switch (type)
{
case IPIKE_TRANSFORM_TYPE_ENCR:
if ((ipike_map_string(ipike.transform_encr_id_map, id, &s)))
return IP_FALSE;
break;
case IPIKE_TRANSFORM_TYPE_PRF:
if ((ipike_map_string(ipike.transform_prf_id_map, id, &s)))
return IP_FALSE;
break;
case IPIKE_TRANSFORM_TYPE_INTEG:
if ((ipike_map_string(ipike.transform_integ_id_map, id, &s)))
return IP_FALSE;
break;
case IPIKE_TRANSFORM_TYPE_DH:
if ((ipike_map_string(ipike.transform_dh_id_map, id, &s)))
return IP_FALSE;
break;
case IPIKE_TRANSFORM_TYPE_ESN:
return IP_TRUE;
default:
return IP_FALSE;
}
return IP_TRUE;
}
/*
*===========================================================================
* ipike_sa_transform_id_from_string
*===========================================================================
*/
IP_GLOBAL Ip_u16
ipike_sa_transform_id_from_string(Ip_u8 type, const char *s)
{
Ip_u16 id = IPIKE_ATTR_INVALID;
switch (type)
{
case IPIKE_TRANSFORM_TYPE_ENCR:
if ((ipike_attribute_map_Ip_u16(ipike.transform_encr_id_map, s, &id)))
return IPIKE_ATTR_INVALID;
break;
case IPIKE_TRANSFORM_TYPE_PRF:
if ((ipike_attribute_map_Ip_u16(ipike.transform_prf_id_map, s, &id)))
return IPIKE_ATTR_INVALID;
break;
case IPIKE_TRANSFORM_TYPE_INTEG:
if ((ipike_attribute_map_Ip_u16(ipike.transform_integ_id_map, s, &id)))
return IPIKE_ATTR_INVALID;
break;
case IPIKE_TRANSFORM_TYPE_DH:
if ((ipike_attribute_map_Ip_u16(ipike.transform_dh_id_map, s, &id)))
return IPIKE_ATTR_INVALID;
break;
case IPIKE_TRANSFORM_TYPE_ESN:
IP_PANIC();
break;
default:
return IPIKE_ATTR_INVALID;
}
return id;
}
/*
*===========================================================================
* ipike_transform_encryption_to_string
*===========================================================================
*/
IP_GLOBAL const char *
ipike_transform_encryption_to_string(Ip_u16 id)
{
return ipike_sa_transform_id_to_string(IPIKE_TRANSFORM_TYPE_ENCR, id);
}
/*
*===========================================================================
* ipike_transform_integrity_to_string
*===========================================================================
*/
IP_GLOBAL const char *
ipike_transform_integrity_to_string(Ip_u16 id)
{
return ipike_sa_transform_id_to_string(IPIKE_TRANSFORM_TYPE_INTEG, id);
}
/*
*===========================================================================
* ipike_transform_hash_to_string
*===========================================================================
*/
IP_GLOBAL const char *
ipike_transform_hash_to_string(Ip_u16 id)
{
return ipike_sa_transform_id_to_string(IPIKE_TRANSFORM_TYPE_PRF, id);
}
/*
*===========================================================================
* ipike_transform_dh_group_to_string
*===========================================================================
*/
IP_GLOBAL const char *
ipike_transform_dh_group_to_string(Ip_u16 id)
{
return ipike_sa_transform_id_to_string(IPIKE_TRANSFORM_TYPE_DH, id);
}
/*
*===========================================================================
* ipike_transform_dh_group_to_string
*===========================================================================
*/
IP_GLOBAL const char *
ipike_transform_esn_to_string(Ip_u16 id)
{
return ipike_sa_transform_id_to_string(IPIKE_TRANSFORM_TYPE_ESN, id);
}
/*
*===========================================================================
* ipike_payload_sa_create
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_sa_create(Ipike2_sa* sa, Ipike2_sa_payload** payload)
{
Ipike_error err = IPIKE_SUCCESS;
Ip_size_t sa_header_size;
Ip_size_t sa_size;
Ip_size_t n;
Ipike2_sa_payload* sa_payload;
Ip_u8* proposal_data;
int i;
sa_header_size = ipike_payload_sa_header_size();
sa_size = ipike_payload_sa_size(sa);
if (sa->proposal_count == 0)
{
IPCOM_LOG0(CRIT, "ipike_payload_sa_create: no proposals");
err = IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN;
}
else if (IP_NULL == (sa_payload = ipcom_calloc(1, sa_size)))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
/* Copy payload header */
sa_payload->header.next_payload = IPIKE2_PAYLOAD_SECURITY_ASSOCIATION;
sa_payload->header.length = ip_htons(sa_size);
proposal_data = ((Ip_u8*) sa_payload + sa_header_size);
sa_size -= sa_header_size;
/* Create either a specific SA payload or all */
if (sa->selected_proposal != -1)
{
n = ipike_copy_selected_proposal(sa, proposal_data, sa_size);
ip_assert(sa_size >= n);
sa_payload->header.length = ip_htons(n + sa_header_size);
}
else
{
for (i = 0; sa->proposals[i] != IP_NULL; i++)
{
if (sa->selected_proposal == -1
|| sa->selected_proposal == sa->proposals[i]->info.number)
{
n = ipike_copy_proposal_value(sa->proposals[i], proposal_data, sa_size);
proposal_data += n;
sa_size -= n;
}
}
ip_assert(sa_size == 0);
}
*payload = sa_payload;
}
return err;
}
/*
*===========================================================================
* ipike_payload_sa_free
*===========================================================================
*/
IP_GLOBAL void
ipike_payload_sa_free(Ipike2_sa *s, void(*free_func)(void*))
{
ip_assert(s != IP_NULL);
ipike_array_free((void**)s->proposals, (void(*)(void*))ipike_free_proposal);
/* Reset all negotiated SA values, keep the others unchanged */
s->selected_proposal = -1;
s->proposal_count = 0;
s->proposals = IP_NULL;
s->selected_encr = IPIKE_TRANSFORM_UNKNOWN;
s->selected_prf = IPIKE_TRANSFORM_UNKNOWN;
s->selected_integ = IPIKE_TRANSFORM_UNKNOWN;
s->selected_dh = IPIKE_TRANSFORM_UNKNOWN;
s->selected_esn = IPIKE_TRANSFORM_UNKNOWN;
s->selected_key_length = 0;
if (free_func)
free_func(s);
}
/*
*===========================================================================
* ipike_payload_sa_initialize
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_sa_initialize(Ip_bool is_ike, Ipike_config_proposal **proposals, Ipike2_sa *sa)
{
Ipike_error err;
int i;
ipcom_memset(sa, 0, sizeof(*sa));
err = ipike_create_proposals(is_ike, proposals, &sa->proposals);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_payload_sa_initialize() :: failed to create proposals");
return err;
}
if (sa->proposals != IP_NULL)
for (i = 0; sa->proposals[i] != IP_NULL; i++)
sa->proposal_count++;
sa->selected_proposal = -1;
return err;
}
/*
*===========================================================================
* ipike_payload_sa_check
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_sa_check(Ipike2_sa_payload* sa)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike2_proposal_info* proposal;
Ip_u32 total_length;
Ip_s32 chain_length;
proposal = (Ipike2_proposal_info*)ipike_payload_sa_proposal_data(sa);
if (proposal==IP_NULL)
{
IPCOM_LOG0(ERR,
"The proposals extends beyond the end of the SA payload size");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
return err;
}
total_length = ipike_payload_sa_proposal_length(sa);
chain_length = ipike_payload_sa_proposal_chain_length(proposal, total_length);
if (chain_length < 0)
{
IPCOM_LOG0(ERR,
"The proposals extends beyond the end of the SA payload size");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
else if (chain_length != (Ip_s32) total_length)
{
IPCOM_LOG0(ERR,
"The proposals is not as long as indicated by the SA payload header");
err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR;
}
else
{
for (;IP_NULL != proposal; proposal = ipike_payload_sa_next_proposal(proposal))
{
if (IPIKE_SUCCESS != (err = ipike_payload_sa_proposal_check(proposal)))
break;
}
}
return err;
}
/*
*===========================================================================
* ipike_payload_sa_print
*===========================================================================
*/
IP_GLOBAL void
ipike_payload_sa_print(Ipike2_sa_payload* sa)
{
Ipike2_proposal_info* proposal;
Ipike2_transform_info* transform;
const char* s = IP_NULL;
/* lint */
(void)s;
/* The payload must be correct, will assume check already run */
proposal = ipike_payload_sa_proposal_data(sa);
for (;IP_NULL != proposal; proposal = ipike_payload_sa_next_proposal(proposal))
{
s = ipike_sa_proposal_proto_id_to_string(proposal->proto_id);
IPCOM_LOG0(DEBUG2, " << proposal >>");
IPCOM_LOG1(DEBUG2, " Proposal #: %d", proposal->number);
IPCOM_LOG1(DEBUG2, " Protocol ID: %s", s);
IPCOM_LOG1(DEBUG2, " SPI Size: %d", (int)proposal->spi_size);
if (proposal->spi_size != 0)
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " spi data: ",
ipike_payload_sa_proposal_spi_data(proposal),
proposal->spi_size);
}
IPCOM_LOG1(DEBUG2, " # of Transforms: %d",
(int)proposal->transform_count);
transform = ipike_payload_sa_transform_data(proposal);
for (;IP_NULL != transform; transform = ipike_payload_sa_next_transform(transform))
{
IPCOM_LOG0(DEBUG2, " <<< transform >>>");
s = ipike_sa_transform_type_to_string(transform->type);
IPCOM_LOG1(DEBUG2, " Type: %s", s);
s = ipike_sa_transform_id_to_string(transform->type, ip_htons(transform->id));
IPCOM_LOG1(DEBUG2, " ID: %s", s);
if (ipike_payload_sa_attributes_length(transform) > 0)
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2,
" Attr: ",
(Ip_u8 *)ipike_payload_sa_attributes_data(transform),
ipike_payload_sa_attributes_length(transform));
}
}
}
return;
}
/*
*===========================================================================
* ipike_payload_sa_extract
*===========================================================================
* Description: V1V2
* Parameters:
* Returns:
*/
IP_GLOBAL Ipike_error
ipike_payload_sa_extract(Ipike2_sa_payload *payload, Ipike2_sa *sa)
{
Ipike_error err = IPIKE_SA_NO_ACCEPTED_PROPOSAL;
Ipike2_proposal_info *proposal_info;
Ipike2_proposal *proposal;
ipike_payload_sa_free(sa, IP_NULL);
/* The payload must be correct, will assume check already run */
proposal_info = ipike_payload_sa_proposal_data(payload);
while (proposal_info != IP_NULL)
{
proposal = ipcom_calloc(1, sizeof(Ipike2_proposal));
if (proposal == IP_NULL)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
break;
}
err = ipike_payload_sa_proposal_extract(proposal_info, proposal);
if (err != IPIKE_SUCCESS)
{
ipike_free_proposal(proposal);
IPCOM_LOG0(DEBUG, "ipike_payload_sa_extract: failed to extract proposal");
break;
}
switch (proposal->info.proto_id)
{
case IPIKE_PROTO_ISAKMP:
break;
case IPIKE_PROTO_IPSEC_AH:
case IPIKE_PROTO_IPSEC_ESP:
break;
default:
/* wrong protocol proposal -> ignore */
ipike_free_proposal(proposal);
goto ignore;
}
err = ipike_array_add((void***)&sa->proposals, proposal);
if (err != IPIKE_SUCCESS)
{
ipike_free_proposal(proposal);
IPCOM_LOG0(DEBUG, "ipike_payload_sa_extract: failed to add proposal to array");
break;
}
sa->proposal_count++;
ignore:
proposal_info = ipike_payload_sa_next_proposal(proposal_info);
}
sa->selected_proposal = -1; /* No selected proposal */
if (err == IPIKE_SUCCESS && sa->proposal_count == 0)
err = IPIKE_SA_NO_ACCEPTED_PROPOSAL;
return err;
}
/*
*===========================================================================
* ipike_payload_sa_set_spi
*===========================================================================
* Description: Set spi value for all SA proposals.
* Parameters: sa - Will be updated with the new spi value if the call was
* successful.
* spi - New spi value.
* Returns: IPIKE_SUCCESS
* IPIKE_OUT_OF_MEMORY
*/
IP_GLOBAL Ipike_error
ipike_payload_sa_set_spi(Ipike2_sa *sa, Ip_u8 *spi_data, Ip_u16 spi_len)
{
Ip_u8 i;
for (i = 0; i < sa->proposal_count; i++)
{
if ( spi_len > sizeof(sa->proposals[0]->spi) )
return IPIKE_FAILED;
sa->proposals[i]->info.spi_size = (Ip_u8)spi_len;
ipcom_memcpy(sa->proposals[i]->spi, spi_data, spi_len);
sa->proposals[i]->info.length = (Ip_u16)(ip_ntohs(sa->proposals[i]->info.length)
+ spi_len);
sa->proposals[i]->info.length = ip_htons(sa->proposals[i]->info.length);
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_proposal_get_next_transform
*===========================================================================
*/
IP_GLOBAL Ip_u16
ipike_proposal_get_next_transform(Ipike2_sa* sa, Ip_u16 type, Ip_u16 old_id)
{
Ip_u8 i, j;
Ip_u16 id;
for (i=0; i<sa->proposal_count; i++)
{
for (j=0; (sa->proposals[i]->transforms[j] != 0); j++)
{
if (sa->proposals[i]->transforms[j]->info.type == type)
{
id = ip_htons(sa->proposals[i]->transforms[j]->info.id);
if (old_id == 0)
return id;
else if (old_id == id)
old_id = 0;
}
}
}
return IPIKE_ATTR_INVALID;
}
/*
*===========================================================================
* ipike_proposal_has_transform
*===========================================================================
*/
IP_GLOBAL Ip_bool
ipike_proposal_has_transform(Ipike2_proposal* proposal, Ip_u16 type, Ip_u16 id)
{
Ip_u8 i;
for (i=0; (proposal->transforms[i] != 0); i++)
if (proposal->transforms[i]->info.type == type)
if (id == ip_htons(proposal->transforms[i]->info.id))
return IP_TRUE;
return IP_FALSE;
}
/*
*===========================================================================
* ipike_proposal_has_transform_type
*===========================================================================
*/
IP_GLOBAL Ip_bool
ipike_proposal_has_transform_type(Ipike2_proposal* proposal, Ip_u16 type)
{
Ip_u8 i;
for (i=0; (proposal->transforms[i] != 0); i++)
{
if (proposal->transforms[i]->info.type == type)
{
return IP_TRUE;
}
}
return IP_FALSE;
}
/*
*===========================================================================
* ipike_proposal_remove_transform_type
*===========================================================================
*/
IP_GLOBAL void
ipike_proposal_remove_transform_type(Ipike2_sa* sa, Ip_u16 type)
{
Ip_u16 i, j;
Ip_u16 size;
for (i = 0; i<sa->proposal_count; i++)
{
for (j = 0; j<sa->proposals[i]->info.transform_count; j++)
{
if (sa->proposals[i]->transforms[j]->info.type == type)
{
size = (Ip_u16)(ip_ntohs(sa->proposals[i]->info.length) -
ip_ntohs(sa->proposals[i]->transforms[j]->info.length));
sa->proposals[i]->info.length = ip_htons(size);
ipike_array_remove((void***) &sa->proposals[i]->transforms,
sa->proposals[i]->transforms[j],
ipcom_free);
j--;
sa->proposals[i]->info.transform_count--;
}
}
}
}
/*
*===========================================================================
* ipike_transform_get_key_length
*===========================================================================
*/
IP_GLOBAL Ip_u16
ipike_transform_get_key_length(Ipike2_transform* transform)
{
Ip_u16 i;
Ipike_attribute* attr;
Ip_u16 type;
if (IP_NULL != transform->attributes)
{
for (i=0; ((attr = transform->attributes[i]) != IP_NULL); i++)
{
type = ip_htons(attr->type);
if (IPIKE_ATTR_AF(type) &&
(IPIKE_ATTR_TYPE(type) == IPIKE_ATTR_CLS_KEY_LENGTH))
{
return (Ip_u16)(ip_ntohs(attr->value)/8);
}
}
}
return 0;
}
#else
int ipike_payload_sa_empty_file = 0;
#endif /* IPIKE_USE_VERSION2 */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/