/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 #include /* **************************************************************************** * 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; iproposal_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; iproposal_count; i++) { for (j = 0; jproposals[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 **************************************************************************** */