/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipike_payload.c,v $ $Revision: 1.38.10.9 $ * $Source: /home/interpeak/CVSRoot/ipike/src/ipike_payload.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 **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipike_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #include "ipike_h.h" #include "ipike_payload.h" #include "ipike2_payload_authentication.h" #include "ipike2_payload_configuration.h" #include "ipike2_payload_delete.h" #include "ipike2_payload_encrypted.h" #include "ipike2_payload_identification.h" #include "ipike2_payload_key_exchange.h" #include "ipike2_payload_notify.h" #include "ipike2_payload_sa.h" #include "ipike2_payload_traffic_selector.h" #include "ipike2_payload_eap.h" #include "ipike_payload_sa.h" #include "ipike_payload_key_exchange.h" #include "ipike_payload_nonce.h" #include "ipike_payload_delete.h" #include "ipike_payload_identification.h" #include "ipike_payload_notification.h" #include "ipike_payload_hash.h" #include "ipike_payload_certificate.h" #include "ipike_payload_sign.h" #include "ipike_payload_vendor_id.h" #include "ipike_payload_nat.h" #include #include /* **************************************************************************** * 4 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* **************************************************************************** * 6 TYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_check_payloads *=========================================================================== */ IP_GLOBAL Ipike_error ipike_check_payloads(Ipike_isakmp_header *isakmp,Ip_bool phase1) { Ipike_error err = IPIKE_SUCCESS; Ipike_payload_header *payload; Ip_u8 this_payload; Ip_u32 max_length; Ip_s32 chain_length; Ipike_payload_enum ctx; if (isakmp->next_payload == IPIKE_PAYLOAD_NONE) { /* The message may have no payloads for IKEv2, so accept if v2 message */ IPCOM_LOG0(DEBUG, "ipike_check_payloads() :: no payloads exist"\ " according to the ISAKMP header"); if (isakmp->version >= 0x20) return IPIKE_SUCCESS; else return IPIKE_ISAKMP_NO_PAYLOAD; } this_payload = isakmp->next_payload; max_length = (Ip_u32)(ip_ntohl(isakmp->length) - sizeof(Ipike_isakmp_header)); if (max_length == 0) { IPCOM_LOG0(DEBUG, "ipike_check_payloads() :: next_payload is not none"\ " but no payload exist"); return IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR; } payload = (Ipike_payload_header*)((Ip_u8*)isakmp + sizeof(Ipike_isakmp_header)); chain_length = ipike_payload_chain_size(payload, max_length); if (chain_length < 0 || chain_length > 0xffff) { IPCOM_LOG0(ERR, "ipike_check_payloads() :: the payloads extends"\ " beyond the end of the ISAKMP package"); return IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR; } payload = ipike_first_payload(isakmp, &ctx); while (IPIKE_SUCCESS == err && IPIKE_PAYLOAD_NONE != this_payload) { /* Check reserved field, must be zero in IKEv1 */ #ifdef IPIKE_USE_VERSION1 if ( isakmp->version == 0x10 ) { if ( payload->flags != 0 ) { IPCOM_LOG1(ERR, "ipike_check_payloads() :: "\ "invalid reserved field (0x%.2x)", payload->flags); err = IPIKE_ISAKMP_INVALID_PAYLOAD; break; } switch (this_payload) { case IPIKE_PAYLOAD_SECURITY_ASSOCIATION: err = ipike_sa_check_payload((Ipike_sa_payload*) payload,phase1); break; case IPIKE_PAYLOAD_KEY_EXCHANGE: err = ipike_key_exchange_check_payload((Ipike_ke_payload*) payload); break; case IPIKE_PAYLOAD_IDENTFICATION: err = ipike_identification_check_payload((Ipike_id_payload*) payload); break; case IPIKE_PAYLOAD_HASH: err = ipike_hash_check_payload((Ipike_hash_payload*) payload); break; case IPIKE_PAYLOAD_NONCE: err = ipike_payload_nonce_check((Ipike_nonce_payload*) payload); break; case IPIKE_PAYLOAD_NOTIFICATION: err = ipike_notification_check_payload((Ipike_notification_payload*) payload); break; case IPIKE_PAYLOAD_CERTIFICATE: err = ipike_payload_certificate_check((Ipike_cert_payload*) payload); break; case IPIKE_PAYLOAD_SIGNATURE: err = ipike_sign_check_payload((Ipike_sign_payload*) payload); break; case IPIKE_PAYLOAD_DELETE: err = ipike_payload_delete_check((Ipike_delete_payload*) payload); break; case IPIKE_PAYLOAD_VENDOR_ID: err = ipike_payload_vendor_id_check((Ipike_vendor_id_payload*) payload); break; case IPIKE_PAYLOAD_ATTRIBUTES: err = ipike_payload_configuration_check((Ipike2_cp_payload*) payload); break; case IPIKE_PAYLOAD_NAT_DISCOVERY: err = ipike_nat_discovery_check_payload((Ipike_nat_discovery_payload*) payload); break; case IPIKE_PAYLOAD_NAT_ORIGINAL_ADDRESS: err = ipike_nat_original_address_check_payload((Ipike_nat_org_addr_payload*) payload); break; case IPIKE_PAYLOAD_CERTIFICATE_REQUEST: err = ipike_payload_certificate_request_check((Ipike_cert_req_payload*) payload); break; default: IPCOM_LOG1(ERR, "ipike_check_payloads() :: payload check failed "\ "since %d is an unsupported payload type", this_payload); err = IPIKE_ISAKMP_UNSUPPORTED_PAYLOAD; break; } } /* if ( isakmp->version == 0x10 ) */ #endif #ifdef IPIKE_USE_VERSION2 else if ( isakmp->version >= 0x20 ) { switch (this_payload) { case IPIKE2_PAYLOAD_SECURITY_ASSOCIATION: err = ipike_payload_sa_check((Ipike2_sa_payload*) payload); break; case IPIKE2_PAYLOAD_KEY_EXCHANGE: err = ipike_payload_key_exchange_check((Ipike2_ke_payload*) payload); break; case IPIKE2_PAYLOAD_IDENTIFICATION_I: case IPIKE2_PAYLOAD_IDENTIFICATION_R: err = ipike_payload_identification_check((Ipike2_id_payload*) payload); break; case IPIKE2_PAYLOAD_CERTIFICATE: err = ipike_payload_certificate_check((Ipike_cert_payload*) payload); break; case IPIKE2_PAYLOAD_CERTIFICATE_REQUEST: err = ipike_payload_certificate_request_check((Ipike_cert_req_payload*) payload); break; case IPIKE2_PAYLOAD_AUTHENTICATION: err = ipike_payload_authentication_check((Ipike2_auth_payload*) payload); break; case IPIKE2_PAYLOAD_NONCE: err = ipike2_payload_nonce_check((Ipike_nonce_payload*) payload); break; case IPIKE2_PAYLOAD_NOTIFY: err = ipike_payload_notify_check((Ipike2_notify_payload*) payload); break; case IPIKE2_PAYLOAD_DELETE: err = ipike2_payload_delete_check((Ipike2_del_payload*) payload); break; case IPIKE2_PAYLOAD_VENDOR_ID: err = ipike_payload_vendor_id_check((Ipike_vendor_id_payload*) payload); break; case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_I: case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_R: err = ipike_payload_traffic_selector_check((Ipike2_ts_payload*) payload); break; case IPIKE2_PAYLOAD_CONFIGURATION: err = ipike_payload_configuration_check((Ipike2_cp_payload*) payload); break; case IPIKE2_PAYLOAD_EAP: err = ipike_payload_eap_check((Ipike2_eap_payload*) payload); break; default: /* IKE v2 is capable of handling unknown payload types */ IPCOM_LOG1(WARNING, "ipike_check_payloads() :: payload check failed "\ "since %d is an unsupported payload type", this_payload); break; } /* switch */ } /* if ( isakmp->version >= 0x20 ) */ #endif /* IPIKE_USE_VERSION2 */ if (err != IPIKE_SUCCESS) break; this_payload = payload->next_payload; payload = ipike_next_payload(&ctx); if (payload == IP_NULL && this_payload != IPIKE_PAYLOAD_NONE) err = IPIKE_ISAKMP_PAYLOAD_LENGTH_ERROR; } /* while */ ipike_free_payload_enumerator(&ctx); return err; } /* *=========================================================================== * ipike_first_payload *=========================================================================== */ #ifdef IPCOM_USE_DMALLOC IP_GLOBAL Ipike_payload_header * ipike_first_payload_debug(Ipike_isakmp_header *isakmp, Ipike_payload_enum *ctx, const char *file, const char *function, Ip_u32 line) #else IP_GLOBAL Ipike_payload_header * ipike_first_payload(Ipike_isakmp_header *isakmp, Ipike_payload_enum *ctx) #endif { Ip_u32 len; ctx->real_header = (Ipike_payload_header *) ((Ip_u8*) isakmp + sizeof(Ipike_isakmp_header)); ctx->allocated_header = IP_NULL; len = ip_ntohl(isakmp->length); if (len < sizeof(Ipike_isakmp_header)) { IPCOM_LOG1(DEBUG2, "ipike_first_payload - isakmp header length too small %d", len); return IP_NULL; } else if (len == sizeof(Ipike_isakmp_header)) { return IP_NULL; /* No payloads */ } len -= (Ip_u32)sizeof(Ipike_isakmp_header); ctx->max_len = (Ip_u32)ipike_payload_chain_size(ctx->real_header, len); if (ctx->max_len == 0xffffffff) { IPCOM_LOG0(DEBUG2, "ipike_first_payload - bad payload chain size"); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, " ISAKMP data:\n", (Ip_u8*)isakmp, ip_ntohl(isakmp->length)); return IP_NULL; } #ifdef IPCOM_USE_DMALLOC return ipike_next_payload_debug(ctx, file, function, line); #else return ipike_next_payload(ctx); #endif } /* *=========================================================================== * ipike_next_payload *=========================================================================== */ #ifdef IPCOM_USE_DMALLOC IP_GLOBAL Ipike_payload_header* ipike_next_payload_debug(Ipike_payload_enum *ctx, const char *file, const char *function, Ip_u32 line) #else IP_GLOBAL Ipike_payload_header * ipike_next_payload(Ipike_payload_enum *ctx) #endif { Ipike_payload_header payload_test; Ip_u16 len; /* We may get alignment problem, so always make a copy */ ipcom_free(ctx->allocated_header); ctx->allocated_header = IP_NULL; if (IP_NULL == ctx->real_header) return IP_NULL; ipcom_memcpy((void*)&payload_test, (void*)ctx->real_header, sizeof(payload_test)); len = ip_htons(payload_test.length); if ((ctx->max_len > 0) && (len > ctx->max_len)) return IP_NULL; #ifdef IPCOM_USE_DMALLOC ctx->allocated_header = ipcom_dcalloc(sizeof(Ipike_payload_header), len/sizeof(Ipike_payload_header) + 1, file, function, line); #else ctx->allocated_header = ipcom_calloc(sizeof(Ipike_payload_header), len/sizeof(Ipike_payload_header) + 1); #endif if (IP_NULL == ctx->allocated_header) return IP_NULL; ipcom_memcpy((void*)ctx->allocated_header, (void*)ctx->real_header, len); if (IPIKE_PAYLOAD_NONE == ctx->real_header->next_payload) ctx->real_header = IP_NULL; else ctx->real_header = (Ipike_payload_header*)(((Ip_u8*)ctx->real_header) + len); return ctx->allocated_header; } /* *=========================================================================== * ipike_payload_sa_next_proposal *=========================================================================== */ IP_GLOBAL Ipike_payload_header* ipike_next_payload_structure(Ipike_payload_header* p) { if (p->next_payload == IPIKE_PAYLOAD_NONE) return IP_NULL; p = (Ipike_payload_header*)((Ip_u8*)p + ip_htons(p->length)); return p; } /* *=========================================================================== * ipike_free_payload_enumerator *=========================================================================== */ IP_GLOBAL void ipike_free_payload_enumerator(Ipike_payload_enum* ctx) { ipcom_free(ctx->allocated_header); } /* *=========================================================================== * ipike_payload_array_size *=========================================================================== */ IP_GLOBAL Ip_u32 ipike_payload_array_size(Ipike_payload_header** payloads) { int i; Ip_u32 size = 0; if (IP_NULL != payloads) for (i = 0; payloads[i] != IP_NULL; i++) size += ip_ntohs(payloads[i]->length); return size; } /* *=========================================================================== * ipike_payload_chain_size *=========================================================================== */ IP_GLOBAL Ip_s32 ipike_payload_chain_size(Ipike_payload_header* first_payload, Ip_u32 max_size) { Ip_u32 size = 0; Ipike_payload_header payload = {0}; if (max_size != 0 && max_size < sizeof(payload)) return -1; while (1) { if (max_size - size < sizeof(payload)) return -1; ipcom_memcpy((void*)&payload, (void*)(((Ip_u8*)first_payload)+size), sizeof(payload)); size += ip_htons(payload.length); if (size > max_size) return -1; if ( payload.next_payload == IPIKE_PAYLOAD_NONE || payload.length == 0 || size == 0) break; } return (Ip_s32) size; } /* *=========================================================================== * ipike_payload_type_to_string *=========================================================================== */ IP_GLOBAL const char * ipike_payload_type_to_string(Ip_u8 payload_type) { const char *s; if (ipike_map_string(ipike.payload_map, payload_type, &s) != IPIKE_SUCCESS) return "invalid payload type"; return s; } /* *=========================================================================== * ipike_payload_print *=========================================================================== */ IP_GLOBAL void ipike_payload_print(Ipike_isakmp_header* isakmp, Ip_bool is_phase1, int version) { Ip_u8 this_payload; Ipike_payload_header *payload; Ipike_payload_enum ctx; this_payload = isakmp->next_payload; payload = ipike_first_payload(isakmp, &ctx); /* The last payload is either a none payload or an encrypted payload */ while (IP_NULL != payload && IPIKE_PAYLOAD_NONE != this_payload && IPIKE2_PAYLOAD_ENCRYPTED != this_payload) { IPCOM_LOG1(DEBUG2, " < %s >", ipike_payload_type_to_string(this_payload)); IPCOM_LOG2(DEBUG2, " Next Payload: %s (%d)", ipike_payload_type_to_string(payload->next_payload), (int) payload->next_payload); IPCOM_LOG2(DEBUG2, " Payload Length: %d (%#x)", ip_ntohs(payload->length), ip_ntohs(payload->length)); if ( version == 0x10 ) { switch (this_payload) { #ifdef IPIKE_USE_VERSION1 case IPIKE_PAYLOAD_SECURITY_ASSOCIATION: if (is_phase1) ipike_sa_ike_print_payload((Ipike_sa_payload*) payload); else ipike_sa_ipsec_print_payload((Ipike_sa_payload*) payload); break; case IPIKE_PAYLOAD_KEY_EXCHANGE: ipike_key_exchange_print_payload((Ipike_ke_payload*) payload); break; case IPIKE_PAYLOAD_IDENTFICATION: ipike_identification_print_payload((Ipike_id_payload*) payload); break; case IPIKE_PAYLOAD_HASH: ipike_hash_print_payload((Ipike_hash_payload*) payload); break; case IPIKE_PAYLOAD_NONCE: ipike_payload_nonce_print((Ipike_nonce_payload*) payload); break; case IPIKE_PAYLOAD_NOTIFICATION: ipike_notification_print_payload((Ipike_notification_payload*) payload); break; case IPIKE_PAYLOAD_CERTIFICATE: ipike_payload_certificate_print((Ipike_cert_payload*) payload); break; case IPIKE_PAYLOAD_CERTIFICATE_REQUEST: ipike_payload_certificate_request_print((Ipike_cert_req_payload*) payload); break; case IPIKE_PAYLOAD_SIGNATURE: ipike_sign_print_payload((Ipike_sign_payload*) payload); break; case IPIKE_PAYLOAD_DELETE: ipike_payload_delete_print((Ipike_delete_payload*) payload); break; case IPIKE_PAYLOAD_VENDOR_ID: ipike_payload_vendor_id_print((Ipike_vendor_id_payload*) payload); break; case IPIKE_PAYLOAD_ATTRIBUTES: ipike_payload_configuration_print((Ipike2_cp_payload*) payload); break; case IPIKE_PAYLOAD_NAT_DISCOVERY: ipike_nat_discovery_print_payload((Ipike_nat_discovery_payload*) payload); break; case IPIKE_PAYLOAD_NAT_ORIGINAL_ADDRESS: ipike_nat_original_address_print_payload((Ipike_nat_org_addr_payload*) payload); break; #endif /* IPIKE_USE_VERSION1 */ default: IPCOM_LOG1(WARNING, "printing of payload failed since %d is a unknown payload type", this_payload); break; } } else if ( version >= 0x20 ) { switch (this_payload) { #ifdef IPIKE_USE_VERSION2 case IPIKE2_PAYLOAD_SECURITY_ASSOCIATION: ipike_payload_sa_print((Ipike2_sa_payload*) payload); break; case IPIKE2_PAYLOAD_KEY_EXCHANGE: ipike_payload_key_exchange_print((Ipike2_ke_payload*) payload); break; case IPIKE2_PAYLOAD_IDENTIFICATION_I: case IPIKE2_PAYLOAD_IDENTIFICATION_R: ipike_payload_identification_print((Ipike2_id_payload*) payload); break; case IPIKE2_PAYLOAD_CERTIFICATE: ipike_payload_certificate_print((Ipike_cert_payload*) payload); break; case IPIKE2_PAYLOAD_CERTIFICATE_REQUEST: ipike_payload_certificate_request_print((Ipike_cert_req_payload*) payload); break; case IPIKE2_PAYLOAD_AUTHENTICATION: ipike_payload_authentication_print((Ipike2_auth_payload*) payload); break; case IPIKE2_PAYLOAD_NONCE: ipike_payload_nonce_print((Ipike_nonce_payload*) payload); break; case IPIKE2_PAYLOAD_NOTIFY: Ipike_payload_notify_print((Ipike2_notify_payload*) payload); break; case IPIKE2_PAYLOAD_DELETE: ipike2_payload_delete_print((Ipike2_del_payload*) payload); break; case IPIKE2_PAYLOAD_VENDOR_ID: break; case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_I: case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_R: ipike_payload_traffic_selector_print((Ipike2_ts_payload*) payload); break; case IPIKE2_PAYLOAD_CONFIGURATION: ipike_payload_configuration_print((Ipike2_cp_payload*) payload); break; case IPIKE2_PAYLOAD_EAP: ipike_payload_eap_print((Ipike2_eap_payload*) payload); break; #endif /* IPIKE_USE_VERSION2 */ default: IPCOM_LOG1(WARNING, "printing of payload failed since %d is a unknown payload type", this_payload); break; } } this_payload = payload->next_payload; payload = ipike_next_payload(&ctx); } ipike_free_payload_enumerator(&ctx); } /* *=========================================================================== * ipike_is_ike_rekeying *=========================================================================== * Check if we are doing IKE-rekeying (missing traffic selectors) */ #ifdef IPIKE_USE_VERSION2 IP_PUBLIC Ip_bool ipike_is_ike_rekeying(Ipike_isakmp_header *isakmp) { Ipike_payload_header *payload; Ip_u8 this_payload; Ipike_payload_enum ctx; Ip_bool is_ike_rekeying = IP_TRUE; if (isakmp->exchange_type != IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA) return IP_FALSE; this_payload = isakmp->next_payload; payload = ipike_first_payload(isakmp, &ctx); while (this_payload != IPIKE_PAYLOAD_NONE && payload != IP_NULL) { switch (this_payload) { case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_I: case IPIKE2_PAYLOAD_TRAFFIC_SELECTOR_R: is_ike_rekeying = IP_FALSE; break; case IPIKE2_PAYLOAD_SECURITY_ASSOCIATION: case IPIKE2_PAYLOAD_NONCE: case IPIKE2_PAYLOAD_KEY_EXCHANGE: case IPIKE2_PAYLOAD_NOTIFY: break; default: ipike_free_payload_enumerator(&ctx); return IP_FALSE; /* unexpected payload, be safe and ignore whole message */ } this_payload = payload->next_payload; payload = ipike_next_payload(&ctx); } ipike_free_payload_enumerator(&ctx); return is_ike_rekeying; } /* *=========================================================================== * ipike_exchange_verify_critial_payload *=========================================================================== */ IP_PUBLIC Ipike_error ipike_payload_handle_unsupported_payload( Ipike_value *notify_data, Ipike_payload_header *payload, Ip_u8 this_payload) { if (IPIKE_PAYLOAD_CRITICAL & payload->flags) { /* Critial payloads that are unsupported should be reported back to sender */ (void)ipike_cpy_data(notify_data, &this_payload, 1); IPCOM_LOG2(ERR, "ipike_payload_handle_unsupported_payload() :: '%s' (%d) is an unsupported payload type", ipike_payload_type_to_string(this_payload), this_payload); return IPIKE_ISAKMP_UNSUPPORTED_CRITICAL_PAYLOAD; } /* It's safe to ignore all payloads that isn't critical */ IPCOM_LOG2(DEBUG2, "ipike_payload_handle_unsupported_payload() :: '%s' (%d) is an unsupported payload type", ipike_payload_type_to_string(this_payload), this_payload); return IPIKE_SUCCESS; } #endif /* IPIKE_USE_VERSION2 */ /* **************************************************************************** * END OF FILE **************************************************************************** */