/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike2_payload_notify.c,v $ $Revision: 1.53.10.12 $ * $Source: /home/interpeak/CVSRoot/ipike/src/ipike2_payload_notify.c,v $ * $Author: yli12 $ $Date: 2017-08-14 02:19:00 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* Notify payload (IKE version 2) */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipike_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPIKE_USE_VERSION2 #include "ipike_h.h" #include "ipike2_payload_notify.h" #include "ipike2_exchange_sa_init.h" #include "ipike2_exchange_info.h" #include "ipike_util.h" #include "ipike_crypto.h" #include "ipike_sadb.h" #include "ipike_ipsec_attributes.h" #include "ipike_ipsec_sadb.h" #include #include #include /* **************************************************************************** * 4 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* **************************************************************************** * 6 TYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* *=========================================================================== * Ipike_payload_notify_spi *=========================================================================== * Description: Returns a pointer to the SPI data in the payload. * Parameters: notify - a notification payload. * Returns: A pointer to the SPI data. * */ IP_STATIC Ip_u8 * Ipike_payload_notify_spi(Ipike2_notify_payload* notify); /* *=========================================================================== * Ipike_payload_notify_data *=========================================================================== * Description: Returns a pointer to the notification data in the payload. * Parameters: notify - a notification payload. * Returns: A pointer to the notification data. * */ IP_STATIC Ip_u8 * Ipike_payload_notify_data(Ipike2_notify_payload* notify); /* *=========================================================================== * Ipike_payload_notify_data_length *=========================================================================== * Description: Returns the length of the hash data. * Parameters: notify - a notification payload. * Returns: The length of the notification data (in bytes). * * */ IP_STATIC Ip_u16 Ipike_payload_notify_data_length(Ipike2_notify_payload* notify); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * Ipike_payload_notify_spi *=========================================================================== */ IP_STATIC Ip_u8 * Ipike_payload_notify_spi(Ipike2_notify_payload* notify) { return (Ip_u8*) notify + IPIKE_NOTIFY_HEADER_LENGTH; } /* *=========================================================================== * Ipike_payload_notify_data *=========================================================================== */ IP_STATIC Ip_u8 * Ipike_payload_notify_data(Ipike2_notify_payload* notify) { return (Ip_u8*) notify + IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size; } /* *=========================================================================== * Ipike_payload_notify_data_length *=========================================================================== */ IP_STATIC Ip_u16 Ipike_payload_notify_data_length(Ipike2_notify_payload* notify) { return IPIKE_PAYLOAD_DATA_LENGTH(notify->header.length, (IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size)); } /* *=========================================================================== * ipike_payload_notify_generate_nat_detection_data *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_generate_nat_detection_data( Ip_u8 cookie_i[IPIKE_ISAKMP_COOKIE_SIZE], Ip_u8 cookie_r[IPIKE_ISAKMP_COOKIE_SIZE], union Ip_sockaddr_union* address, Ipike_value *hash) { Ipike_value data; Ipike_error err = IPIKE_SUCCESS; Ip_u8 port[2]; data.len = 0; data.value = IP_NULL; hash->value = IP_NULL; /* Hash spi values and ip address */ port[0] = (Ip_u8)(ipike_addr_get_port(address) >> 8); port[1] = (Ip_u8)(ipike_addr_get_port(address)); err = ipike_set_data(&data, cookie_i, IPIKE_ISAKMP_COOKIE_SIZE); if ( IPIKE_SUCCESS != err ) goto out; err = ipike_append_data(&data, cookie_r, IPIKE_ISAKMP_COOKIE_SIZE); if ( IPIKE_SUCCESS != err ) goto out; err = ipike_append_data(&data, ipike_addr_get_ptr(address), ipike_addr_get_len(address)); if ( IPIKE_SUCCESS != err ) goto out; err = ipike_append_data(&data, port, 2); if ( IPIKE_SUCCESS != err ) goto out; err = ipike_crypto_hash(IPIKE_ATTR_HASH_SHA1, &data, hash); if ( IPIKE_SUCCESS != err ) goto out; IPCOM_LOG2(DEBUG2, "NAT Traversal for %s[%d]", ipike_addr_to_str(address), ipike_addr_get_port(address)); IPCOM_LOG1(DEBUG2, " Initiator cookie %s", ipike_cookie_to_string(cookie_i)); IPCOM_LOG1(DEBUG2, " Responder cookie %s", ipike_cookie_to_string(cookie_r)); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Hash: ", hash->value, hash->len); (void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Data: ", data.value, data.len); out: if (IP_NULL != data.value) ipcom_free(data.value); return err; } /* *=========================================================================== * ipike_payload_notify_process_invalid_ke *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_invalid_ke( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { Ip_u8* data; Ip_u16 len; Ip_u16 group; data = Ipike_payload_notify_data(payload); len = Ipike_payload_notify_data_length(payload); /* Responder didn't accept our d-h group, try with the specified group */ if (len == 2) { group = ip_htons(*((Ip_u16*)data)); DH_free(ie->dh); ie->dh = IP_NULL; if (IPIKE_SUCCESS == ipike_exchange_generate_dh_key(ie, IP_NULL, group)) { /* Restart message pair */ ie->message_number -= 2; /* Reset message ID if this is an IKE INIT message */ if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT ) { ie->ike_sa->v2.message_id = 0; /* RFC4718 Section 2.1 * Make sure that the responder SPI is set to zero */ ipcom_memset(ie->ike_sa->responder_cookie, 0, IPIKE_ISAKMP_COOKIE_SIZE); } return IPIKE_SUCCESS; } } return IPIKE_EXCH_FINNISHED; } /* *=========================================================================== * Ipike_payload_message_type_to_string *=========================================================================== */ IP_STATIC const char * ipike_payload_message_type_to_string(Ip_u16 message_type) { const char* s; if ((message_type >= IPIKE_NOTI_ERR_PRIVATE_USE_LOW) && (message_type <= IPIKE_NOTI_ERR_PRIVATE_USE_HIGH)) return "Error Private Use"; if (message_type >= IPIKE_NOTI_INF_PRIVATE_USE_LOW) return "Information Private Use"; if (ipike_map_string(ipike.notify_map, message_type, &s) != IPIKE_SUCCESS) return "Invalid message type"; return s; } /* *=========================================================================== * ipike_payload_notify_process_error *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_error( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload, Ip_u16 type) { Ipike_error err = IPIKE_SUCCESS; IPCOM_LOG1(INFO, "ipike_payload_notify_process_error() :: notify message '%s'", ipike_payload_message_type_to_string(ip_htons(payload->message_type))); /* Handle some error messages */ switch (type) { case IPIKE_NOTI_ERR_KE_PAYLOAD: err = ipike_payload_notify_process_invalid_ke(ie, payload); break; case IPIKE_NOTI_ERR_INVALID_IKE_SPI: /* The IKE SA doesn't exist for the other side, so delete it * Removing the IKE SA in IKEv2 will implicitly remove all * child IPsec SAs */ (void)ipike_sadb_set_state(ie, ie->ike_sa, IPIKE_SA_DYING); /* Always abort exchange */ err = IPIKE_EXCH_FINNISHED; break; case IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN: /* Handle denied IKE rekey request */ if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA && ie->ike_sa_new) { IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\ "IKE rekey exchange rejected with NO_PROPOSAL_CHOSEN"); ie->ike_sa_new->error = IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN; } else { IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\ "exchange rejected with NO_PROPOSAL_CHOSEN"); if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH || ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA) { /* RFC4718 Section 4.2: * This is also in line with how the CREATE_CHILD_SA exchange * works: a failure to create a CHILD_SA does not close the IKE_SA. */ ie->ipsec_sa->error = IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN; } else { /* Abort exchange */ err = IPIKE_EXCH_FINNISHED; } } break; case IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS: /* Handle denied IPsec rekey request */ if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA && ie->ipsec_sa ) { IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() ::"\ " IPsec rekey exchange rejected with NO_ADDITIONAL_SAS"); ie->ipsec_sa->error = IPIKE_ISAKMP_NO_ADDITIONAL_SAS; } else { IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\ "exchange rejected with NO_ADDITIONAL_SAS"); /* Abort exchange */ err = IPIKE_EXCH_FINNISHED; } break; default: /* Ignore error notifications in two cases: * 1. Send empty response if information exchange. * 2. This is a request that contains a notification error. * Otherwise, abort this exchange immediately */ if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_INFORMATIONAL || (ie->isakmp_flags & IPIKE_ISAKMP_RESPONSE) ) { IPCOM_LOG1(NOTICE, "ipike_payload_notify_process_error() :: "\ "ignoring error notification (%d)", type); } else { IPCOM_LOG1(NOTICE, "ipike_payload_notify_process_error() :: "\ "aborting exchange", type); err = IPIKE_EXCH_FINNISHED; } break; } return err; } /* *=========================================================================== * ipike_payload_notify_process_nat_detection *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_nat_detection( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload, Ip_bool source) { Ipike_error err; Ipike_value data; union Ip_sockaddr_union* address; /* We have at least got some NAT data and will be able to tell whether * a NAT is between */ ie->ike_sa->has_got_nat_data = IP_TRUE; if ( source ) { if (ie->msg.peer_addr.sa.sa_family != 0) address = &ie->msg.peer_addr; else address = &ie->ike_sa->peer_addr; } else { if (ie->msg.local_addr.sa.sa_family != 0) address = &ie->msg.local_addr; else address = &ie->ike_sa->local_addr; } /* As responder of the IKE INIT message we must calculate the hash with a zero responder cookie (spi) */ if ( !ie->ike_sa->is_initiator && ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT) { Ip_u8 zero_cookie[IPIKE_ISAKMP_COOKIE_SIZE] = {0}; /* Generate the notify data */ err = ipike_payload_notify_generate_nat_detection_data( ie->ike_sa->initiator_cookie, zero_cookie, address, &data); } else { /* Generate the notify data */ err = ipike_payload_notify_generate_nat_detection_data( ie->ike_sa->initiator_cookie, ie->ike_sa->responder_cookie, address, &data); } if ( IPIKE_SUCCESS != err ) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_nat_detection() :: failed to generate NAT data"); return err; } /* Verify data are equal */ if ( data.len == Ipike_payload_notify_data_length(payload) && ipcom_memcmp(data.value, Ipike_payload_notify_data(payload), data.len) == 0 ) { /* There is no NAT between source and destination */ if (source) ie->ike_sa->peer_behind_nat = IP_FALSE; else ie->ike_sa->local_behind_nat = IP_FALSE; } else { if (source) IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_nat_detection() :: source behind NAT"); else IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_nat_detection() :: destination behind NAT"); } ipcom_free(data.value); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_process_cookie *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_process_cookie( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { Ip_u8* data; Ip_size_t length; Ipike_error err; if (IPIKE_NOTI_INF_COOKIE != ip_htons(payload->message_type)) { IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_cookie - Not a cookie notify from initiator"); err = IPIKE_ISAKMP_INVALID_SYNTAX; } else { /* The initiator should resend the initial request with the same cookie * value. The responder must verify that correct notify value is sent. */ length = ip_ntohs(payload->header.length) - sizeof(*payload); data = ((Ip_u8*)payload) + sizeof(Ipike2_notify_payload); if ((length < 1) || (length > 64)) { err = IPIKE_ISAKMP_INVALID_SYNTAX; } else if (ie->ike_sa->is_initiator) { err = ipike_cpy_data(&(ie->cookie), data, length); /* Restart message pair */ ie->message_number -= 2; ie->message_id = 0; ie->ike_sa->v2.message_id--; } else { if (length != sizeof(ie->ike_sa->responder_cookie) || ipcom_memcmp(ie->cookie.value, data, length)) { IPCOM_LOG0(ERR, "Exchange aborted, bad cookie from initiator"); err = IPIKE_ISAKMP_INVALID_SYNTAX; } else { ipcom_memcpy(ie->ike_sa->responder_cookie, data, length); ie->has_cookie = IP_TRUE; err = IPIKE_SUCCESS; } } } return err; } /* *=========================================================================== * ipike_payload_notify_process_rekey *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_process_rekey( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { Ipike_error err = IPIKE_SUCCESS; if (IPIKE_NOTI_INF_REKEY_SA != ip_htons(payload->message_type)) { IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_rekey() ::"\ " not a rekey notify from initiator"); return IPIKE_ISAKMP_INVALID_SYNTAX; } if (payload->spi_size == 4) { Ipike_value spi_data; Ipike_ipsec_sadb_entry *ipsec_sa = IP_NULL; /* Need to switch the ie ipsec conf pointer based on rekey */ err = ipike_set_data(&spi_data,(const void*)Ipike_payload_notify_spi(payload), 4); if (err == IPIKE_SUCCESS) { err = ipike_ipsec_sadb_hash_get(spi_data.value, 0, &ie->msg.local_addr, &ie->msg.peer_addr, &ipsec_sa); if (err != IPIKE_SUCCESS) err = ipike_ipsec_sadb_hash_get(spi_data.value, 0, &ie->msg.peer_addr, &ie->msg.local_addr, &ipsec_sa); } if (err == IPIKE_SUCCESS) { Ipike_config_ipsec_sa *ipsec_conf; ip_assert(ipsec_sa != IP_NULL); ipsec_conf = ipike_config_get_ipsec_sa_from_id(ipike.config.ipsec_sa, ipsec_sa->ipsec_id); if (ipsec_conf == IP_NULL) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_rekey() ::"\ " unable to identify ipsec conf using rekey spi"); err = IPIKE_ISAKMP_INVALID_SPI; } else { IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_rekey() :: "\ "identified ipsec_conf using rekey spi"); ie->ipsec_conf = ipsec_conf; } /* The other side has initiated an rekey, steal reference to keep track of simultaneous IPsec rekey, will remove it when the exchange is done */ ie->ike_sa->v2.child_ike_sa_pair[IPIKE_SA_IPSEC_REKEY_RESP] = ie->ipsec_sa; /* Set IKE SA rekey flag */ IP_BIT_SET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IPSEC_RESP_REKEY); /* Make sure that this IPsec SA rekey does not collide with an IKE SA rekey */ if ( IP_BIT_ISSET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IKE_INIT_REKEY) || IP_BIT_ISSET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IKE_RESP_REKEY)) { IPCOM_LOG0(WARNING, "ipike_payload_notify_process_rekey() ::"\ " recevied IPsec SA rekey request during IKE rekey"); /* From RFC4718: "If a host receives a request to create or rekey a * CHILD_SA after it has started rekeying the IKE_SA, it should reply * with NO_ADDITIONAL_SAS." */ ie->ipsec_sa->error = IPIKE_ISAKMP_NO_ADDITIONAL_SAS; /* Continue the exchange so we can form a proper reply */ } } IPIKE_FREEP(spi_data.value); } return err; } /* *=========================================================================== * ipike_payload_notify_process_initial_contact *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_initial_contact(Ipike_isakmp_exchange* ie) { /* Remove all IKE SA:s with same local/peer and not this responder * and/or initiator cookie */ ipike_sadb_remove_all_except_this(ie->ike_sa); return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_process_mobike_supported *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_mobike_supported(Ipike_isakmp_exchange* ie) { /* Peer sends message that mobike is supported, so enable if we support */ if (ipcom_sysvar_get_as_int("ipike.mobike", 0) != 0) ie->ike_sa->mobike.enabled = IP_TRUE; return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_process_additional_address *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_additional_address( Ip_bool ip4, Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { union Ip_sockaddr_union* addr = IP_NULL; Ip_u8* data = IP_NULL; Ip_size_t len = 0; Ipike_error err = IPIKE_SUCCESS; /* Always clear list when new list of addresses arrives (from new exchange) */ if ((ie->ike_sa->mobike.peer_addresses != IP_NULL) && (ie->message_id != ie->ike_sa->mobike.message_id_addresses)) { ipike_array_free((void**)ie->ike_sa->mobike.peer_addresses, ipcom_free); ie->ike_sa->mobike.peer_addresses = IP_NULL; } ie->ike_sa->mobike.message_id_addresses = ie->message_id; /* Store address for future use */ if (IP_NULL == (addr = ipcom_calloc(1, sizeof(*addr)))) { IP_PANIC(); err = IPIKE_OUT_OF_MEMORY; } else { /* Initiate address structure */ len = ip_ntohs(payload->header.length) - sizeof(*payload); data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len); err = ipike_addr_set_from_data(data, len, addr); /* Check correct type of address */ #ifdef IPCOM_USE_INET if ((IPIKE_SUCCESS == err) && ip4 && (addr->sa.sa_family != IP_AF_INET)) err = IPIKE_ISAKMP_INVALID_PAYLOAD; #endif #ifdef IPCOM_USE_INET6 if ((IPIKE_SUCCESS == err) && !ip4 && (addr->sa.sa_family != IP_AF_INET6)) err = IPIKE_ISAKMP_INVALID_PAYLOAD; #endif /* Add to list */ if (IPIKE_SUCCESS == err) err = ipike_array_add((void***)&ie->ike_sa->mobike.peer_addresses, addr); if (IPIKE_SUCCESS != err) ipcom_free(addr); } return err; } /* *=========================================================================== * ipike_payload_notify_process_no_additional_addresses *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_no_additional_addresses(Ipike_isakmp_exchange* ie) { (void)ie; return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_process_update_sa_addresses *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_update_sa_addresses(Ipike_isakmp_exchange* ie) { if (ie->ike_conf == IP_NULL) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_update_sa_addresses() ::"\ "new address not allowed for configuration"); return IPIKE_UNACCEPTABLE_ADDRESSES; } /* Store address of the remote peer */ return ipike_addr_copy(&ie->ike_sa->mobike.update.peer_addr, &ie->msg.peer_addr); } /* *=========================================================================== * ipike_payload_notify_process_cookie2 *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_cookie2( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { Ip_u8* data = IP_NULL; Ip_size_t len = 0; Ipike_error err = IPIKE_SUCCESS; /* The responder should return the same cookie value. The initiator must * verify that correct notify value is returned. */ len = ip_ntohs(payload->header.length) - sizeof(*payload); data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len); if (ie->ike_sa->mobike.cookie2.value != IP_NULL) { /* Initiator side, verify received cookie2 with stored value */ if ( ie->ike_sa->mobike.cookie2.len != len || ipcom_memcmp(ie->ike_sa->mobike.cookie2.value, data, len) != 0 ) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_cookie2() ::"\ " bad cookie2 received, routability check failed"); } else { /* Commit address update */ err = ipike_dispatch_commit_address_update(ie->ike_sa); if (IPIKE_SUCCESS != err) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_cookie2() ::"\ " update address failed"); } /* Address updated, clear it */ ipcom_memset(&ie->ike_sa->mobike.update.peer_addr, 0, sizeof(ie->ike_sa->mobike.update.peer_addr)); } } else { /* Responder side, return cookie2 to initiator */ err = ipike_set_data(&ie->ike_sa->mobike.cookie2, data, len); /* Return cookie2 to initiator */ if (IPIKE_SUCCESS == err) err = ipike_payload_notify_cookie2(&ie->ike_sa->mobike.cookie2, (Ipike2_notify_payload**)&ie->phase2.notify_or_delete); } IPIKE_FREEP(ie->ike_sa->mobike.cookie2.value); return err; } /* *=========================================================================== * ipike_payload_notify_process_no_nats_allowed *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_no_nats_allowed( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload) { Ipike_error err = IPIKE_SUCCESS; Ip_u8* data = IP_NULL; Ip_size_t len = 0; Ip_u16 port = 0; union Ip_sockaddr_union src_addr; union Ip_sockaddr_union dst_addr; /* There are either src/dst ip4 or ip6 address followed by src/dst port */ len = ip_ntohs(payload->header.length) - sizeof(*payload); data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len); if ((len == (4 + 4 + 2 + 2)) || /* ip4 */ (len == (16 + 16 + 2 + 2))) /* ip6 */ { err = ipike_addr_set_from_data(data, (len-4)/2, &src_addr); if (IPIKE_SUCCESS == err) err = ipike_addr_set_from_data(data + (len-4)/2, (len - 4)/2, &dst_addr); ipcom_memcpy(&port, data + (len-4), sizeof(port)); (void)ipike_addr_set_port(&src_addr, ip_ntohs(port)); ipcom_memcpy(&port, data + (len-2), sizeof(port)); (void)ipike_addr_set_port(&dst_addr, ip_ntohs(port)); /* Compare addresses */ if (!ipike_addr_are_equal_port(&src_addr, &ie->msg.peer_addr) || !ipike_addr_are_equal_port(&dst_addr, &ie->msg.local_addr)) { IPCOM_LOG0(ERR, "ipike_payload_notify_process_no_nats_allowed: NAT between local and peer"); err = IPIKE_UNEXPECTED_NAT_DETECTED; } } else { err = IPIKE_ISAKMP_INVALID_PAYLOAD; } return err; } /* *=========================================================================== * ipike_payload_notify_process_no_nats_allowed *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_http_cert_lookup_supported( Ipike_isakmp_exchange* ie) { if ( ipike.use_hash_and_url ) { ie->ike_sa->v2.use_hash_and_url = IP_TRUE; IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_http_cert_lookup_supported: Hash and URL enabled"); } return IPIKE_SUCCESS;; } #ifdef IPIKE_USE_ROHC /* *=========================================================================== * ipike_payload_notify_process_rohc *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_rohc( Ipike2_notify_payload* payload, Ipike_isakmp_exchange* ie) { Ip_ssize_t data_len = 0; Ipike_attribute * attr; Ipike_rohc * rohc; /* Only applicable when negotiation IPsec SAs */ if ( ie->ipsec_sa == NULL ) return IPIKE_SUCCESS; if ( ie->ipsec_sa->v2.rohc == NULL ) { ie->ipsec_sa->v2.rohc = ipcom_malloc(sizeof(Ipike_rohc)); if ( ie->ipsec_sa->v2.rohc == NULL ) return IPIKE_OUT_OF_MEMORY; ipcom_memset(ie->ipsec_sa->v2.rohc, 0, sizeof(Ipike_rohc)); } rohc = ie->ipsec_sa->v2.rohc; attr = (Ipike_attribute * ) Ipike_payload_notify_data(payload); data_len = Ipike_payload_notify_data_length(payload); while ( attr != IP_NULL) { switch ( IPIKE_ATTR_TYPE(ip_ntohs(attr->type)) ) { case IPIKE_ATTR_ROHC_MAX_CID: rohc->remote.max_cid = ip_ntohs(attr->value); break; case IPIKE_ATTR_ROHC_PROFILE: if ( rohc->remote.num_profiles < IPIKE_CONFIG_ROHC_PROFILE_NUM_MAX - 1 ) rohc->remote.profiles[rohc->remote.num_profiles++] = ip_ntohs(attr->value); break; case IPIKE_ATTR_ROHC_INTEG: if ( rohc->remote.num_integ_algs < IPIKE_CONFIG_ROHC_INTEG_NUM_MAX - 1 ) rohc->remote.integ_algs[rohc->remote.num_integ_algs++] = ip_ntohs(attr->value); break; case IPIKE_ATTR_ROHC_ICV_LEN: rohc->remote.icv_len = ip_ntohs(attr->value); break; case IPIKE_ATTR_ROHC_MRRU: rohc->remote.mrru = ip_ntohs(attr->value); break; default: IPCOM_LOG1(WARNING, "ipike_payload_notify_process_rohc() ::"\ " received unknown ROHC attributes %d", ip_ntohs(attr->type)); break; } attr = ipike_next_attribute(attr, &data_len); } /* We have received a proposed ROHC suite */ IPCOM_LOG0(DEBUG, "ipike_payload_notify_process_rohc() ::"\ " received ROHC parameters"); #ifdef IP_DEBUG { Ip_u32 i = 0; IPCOM_LOG1(DEBUG2, " MAX_CID %u", rohc->remote.max_cid); IPCOM_LOG1(DEBUG2, " MRRU %u", rohc->remote.mrru); IPCOM_LOG1(DEBUG2, " ICV_LEN %u", rohc->remote.icv_len); for ( i = 0; i < rohc->remote.num_profiles; i++ ) IPCOM_LOG1(DEBUG2, " PROFILE %u", rohc->remote.profiles[i]); for ( i = 0; i < rohc->remote.num_integ_algs; i++ ) IPCOM_LOG1(DEBUG2, " INTEG %u", rohc->remote.integ_algs[i]); } #endif return IPIKE_SUCCESS; } #endif /* IPIKE_USE_ROHC */ /* *=========================================================================== * ipike_payload_notify_process_info *=========================================================================== */ IP_STATIC Ipike_error ipike_payload_notify_process_info( Ipike_isakmp_exchange* ie, Ipike2_notify_payload* payload, Ip_u16 type) { Ipike_error err = IPIKE_SUCCESS; /* Handle some notify messages */ switch (type) { case IPIKE_NOTI_INF_USE_TRANSPORT_MODE: ie->ike_sa->v2.transport_notify = IP_TRUE; break; case IPIKE_NOTI_INF_REKEY_SA: /*!!LOBREKEY * Only rekey of IPSEC SA supported, so fail if IKE SA. * IKE spi is 8 bytes and IPSEC spi is 4 bytes */ if (payload->spi_size != 4) err = IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS; else err = ipike_payload_notify_process_rekey(ie, payload); break; case IPIKE_NOTI_INF_NAT_DETECTION_DESTINATION_IP: err = ipike_payload_notify_process_nat_detection(ie, payload, IP_FALSE); break; case IPIKE_NOTI_INF_NAT_DETECTION_SOURCE_IP: err = ipike_payload_notify_process_nat_detection(ie, payload, IP_TRUE); break; case IPIKE_NOTI_INF_COOKIE: err = ipike_payload_notify_process_cookie(ie, payload); break; case IPIKE_NOTI_INF_INITIAL_CONTACT: err = ipike_payload_notify_process_initial_contact(ie); break; case IPIKE_NOTI_INF_MOBIKE_SUPPORTED: err = ipike_payload_notify_process_mobike_supported(ie); break; case IPIKE_NOTI_INF_ADDITIONAL_IP4_ADDRESS: err = ipike_payload_notify_process_additional_address(IP_TRUE, ie, payload); break; case IPIKE_NOTI_INF_ADDITIONAL_IP6_ADDRESS: err = ipike_payload_notify_process_additional_address(IP_FALSE, ie, payload); break; case IPIKE_NOTI_INF_NO_ADDITIONAL_ADDRESSES: err = ipike_payload_notify_process_no_additional_addresses(ie); break; case IPIKE_NOTI_INF_UPDATE_SA_ADDRESSES: err = ipike_payload_notify_process_update_sa_addresses(ie); break; case IPIKE_NOTI_INF_COOKIE2: err = ipike_payload_notify_process_cookie2(ie, payload); break; case IPIKE_NOTI_INF_NO_NATS_ALLOWED: err = ipike_payload_notify_process_no_nats_allowed(ie, payload); break; case IPIKE_NOTI_INF_ESP_TFC_PADDING_NOT_SUPPORTED: if (ie->ipsec_sa) ie->ipsec_sa->v2.use_tfc = IP_FALSE; break; case IPIKE_NOTI_INF_HTTP_CERT_LOOKUP_SUPPORTED: err = ipike_payload_notify_process_http_cert_lookup_supported(ie); break; #ifdef IPIKE_USE_ROHC case IPIKE_NOTI_INF_ROHC_SUPPORTED: err = ipike_payload_notify_process_rohc(payload, ie); break; #endif default: break; } return err; } /* *=========================================================================== * ipike_payload_notify_error_to_message_type *=========================================================================== */ IP_STATIC Ip_bool ipike_payload_notify_error_require_spi( Ipike_error err) { /* Add error codes that requires the SPI to be added in the * notify payload */ switch (err) { case IPIKE_ISAKMP_INVALID_IKE_SPI: return IP_TRUE; default: return IP_FALSE; } return IP_FALSE; } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipike_payload_notify_error_to_message_type *=========================================================================== */ IP_PUBLIC Ipike_error ipike_payload_notify_error_to_message_type( Ipike_error err, Ip_u16* message_type) { switch (err) { case IPIKE_ISAKMP_UNSUPPORTED_CRITICAL_PAYLOAD: *message_type = IPIKE_NOTI_ERR_UNSUPPORTED_CRITICAL_PAYLOAD; break; case IPIKE_ISAKMP_INVALID_IKE_SPI: *message_type = IPIKE_NOTI_ERR_INVALID_IKE_SPI; break; case IPIKE_ISAKMP_INVALID_MAJOR_VERSION: *message_type = IPIKE_NOTI_ERR_INVALID_MAJOR_VERSION; break; case IPIKE_ISAKMP_INVALID_SYNTAX: *message_type = IPIKE_NOTI_ERR_INVALID_SYNTAX; break; case IPIKE_ISAKMP_INVALID_MESSAGE_ID: *message_type = IPIKE_NOTI_ERR_INVALID_MESSAGE_ID; break; case IPIKE_ISAKMP_INVALID_SPI: *message_type = IPIKE_NOTI_ERR_INVALID_SPI; break; case IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN: *message_type = IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN; break; case IPIKE_ISAKMP_KE_PAYLOAD: *message_type = IPIKE_NOTI_ERR_KE_PAYLOAD; break; case IPIKE_ISAKMP_INVALID_ID_TYPE: *message_type = IPIKE_NOTI_ERR_INVALID_ID_INFORMATION; break; case IPIKE_ISAKMP_AUTHENTICATION_FAILED: /* Returned from ipike_policy_accept_id */ case IPIKE_AUTHENTICATION_FAILED: *message_type = IPIKE_NOTI_ERR_AUTHENTICATION_FAILED; break; case IPIKE_ISAKMP_SINGLE_PAIR_REQUIRED: *message_type = IPIKE_NOTI_ERR_SINGLE_PAIR_REQUIRED; break; case IPIKE_ISAKMP_NO_ADDITIONAL_SAS: *message_type = IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS; break; case IPIKE_ISAKMP_INTERNAL_ADDRESS_FAILURE: *message_type = IPIKE_NOTI_ERR_INTERNAL_ADDRESS_FAILURE; break; case IPIKE_ISAKMP_FAILED_CP_REQUIRED: *message_type = IPIKE_NOTI_ERR_FAILED_CP_REQUIRED; break; case IPIKE_ISAKMP_TS_UNACCEPTABLE: *message_type = IPIKE_NOTI_ERR_TS_UNACCEPTABLE; break; case IPIKE_ISAKMP_INVALID_SELECTORS: *message_type = IPIKE_NOTI_ERR_INVALID_SELECTORS; break; case IPIKE_NONCE_INVALID_SIZE: *message_type = IPIKE_NOTI_ERR_INVALID_SYNTAX; break; case IPIKE_UNACCEPTABLE_ADDRESSES: *message_type = IPIKE_NOTI_ERR_UNACCEPTABLE_ADDRESSES; break; case IPIKE_UNEXPECTED_NAT_DETECTED: *message_type = IPIKE_NOTI_ERR_UNEXPECTED_NAT_DETECTED; break; case IPIKE_SA_NOT_FOUND: *message_type = IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN; break; default: /* Can not inform the other party about the error condition */ return IPIKE_INTERNAL_ERROR; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_add_error_reply *=========================================================================== */ IP_PUBLIC Ipike_error ipike_payload_notify_add_error_reply( Ipike_isakmp_exchange *ie, Ipike_payload_header*** reply_payloads) { Ipike_sadb_entry* sa; Ipike2_notify_payload* notify; Ip_size_t size; Ipike_error err; Ip_u8 spi_size = 0; Ip_u8* spi_data = IP_NULL; /* Only responses may send errors. The exchange should be ended in case requests fail */ if ( !(ie->isakmp_flags & IPIKE_ISAKMP_RESPONSE) ) return IPIKE_EXCH_FINNISHED; /* Create notify payload */ if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_INFORMATIONAL || ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT || ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH) { sa = ie->ike_sa; /* Only handle IPsec SA errors if we don't have IKE SA errors */ if ( sa->error == IPIKE_SUCCESS && ie->ipsec_sa != IP_NULL && ie->ipsec_sa-> error != IPIKE_SUCCESS) sa = ie->ipsec_sa; } else { if (ie->ike_sa_new != IP_NULL) sa = ie->ike_sa_new; else sa = ie->ipsec_sa; ip_assert(sa != IP_NULL); if ( ipike_payload_notify_error_require_spi(sa->error) ) { if (sa->is_initiator) { spi_size = (Ip_u8)sa->v2.spi_i.len; spi_data = sa->v2.spi_i.value; } else { spi_size = (Ip_u8)sa->v2.spi_r.len; spi_data = sa->v2.spi_r.value; } } } size = sizeof(*notify) + spi_size + sa->notify_data.len; notify = (Ipike2_notify_payload*)ipcom_calloc(1, size); if (IP_NULL == notify) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } notify->header.next_payload = IPIKE2_PAYLOAD_NOTIFY; notify->header.length = ip_htons((Ip_u16)size); if (ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT || ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH) /*Fix vxw6-80697. RFC 4306, protocol id must be sent as zero, *for notifications that do not relate to an existing SA*/ notify->protocol_id = 0; /*IPIKE_PROTO_ISAKMP;*/ else notify->protocol_id = sa->v2.sa.proto_id; err = ipike_payload_notify_error_to_message_type(sa->error, ¬ify->message_type); if (err != IPIKE_SUCCESS) { ipcom_free(notify); IPCOM_LOG0(DEBUG, "ipike_payload_notify_add_error_reply() :: unknown error message"); } else { notify->message_type = ip_htons(notify->message_type); notify->spi_size = spi_size; ipcom_memcpy(Ipike_payload_notify_spi(notify), spi_data, spi_size); ipcom_memcpy(Ipike_payload_notify_data(notify), sa->notify_data.value, sa->notify_data.len); /* Add notify to payload list */ err = ipike_array_add((void***) reply_payloads, notify); if (err != IPIKE_SUCCESS) ipcom_free(notify); } return err; } /* *=========================================================================== * Ipike_payload_notify_create *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_create( Ip_u8 protocol_id, Ip_u16 message_type, Ipike_value* spi, Ipike_value* data, Ipike2_notify_payload** payload) { Ip_u16 length; Ipike2_notify_payload* notify; length = IPIKE_NOTIFY_HEADER_LENGTH; if (IP_NULL != spi) length = (Ip_u16)(length + spi->len); if (IP_NULL != data) length = (Ip_u16)(length + data->len); if (IP_NULL == (notify = ipcom_calloc(1, length))) { IP_PANIC(); return IPIKE_OUT_OF_MEMORY; } notify->header.length = ip_htons(length); notify->header.next_payload = IPIKE2_PAYLOAD_NOTIFY; notify->protocol_id = protocol_id; notify->message_type = ip_ntohs(message_type); if (IP_NULL != spi) { notify->spi_size = (Ip_u8)spi->len; ipcom_memcpy(Ipike_payload_notify_spi(notify), spi->value, spi->len); } if (IP_NULL != data) { ipcom_memcpy(Ipike_payload_notify_data(notify), data->value, data->len); } *payload = notify; return IPIKE_SUCCESS; } /* *=========================================================================== * Ipike_payload_notify_check *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_check(Ipike2_notify_payload* notify) { if (ip_ntohs(notify->header.length) < IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size) { IPCOM_LOG3(ERR, "Ipike_payload_notify_check: The indicated length of the notify payload (%d) is less than the header (%d) + spi size (%d)", ip_ntohs(notify->header.length), IPIKE_NOTIFY_HEADER_LENGTH, notify->spi_size); return IPIKE_ISAKMP_INVALID_SYNTAX; } return IPIKE_SUCCESS; } /* *=========================================================================== * ipike_payload_notify_process *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_process(Ipike_isakmp_exchange *ie, Ipike2_notify_payload *payload) { Ip_u16 type; type = ip_htons(payload->message_type); if (type >= 1 && type <= IPIKE_NOTI_ERR_PRIVATE_USE_HIGH) return ipike_payload_notify_process_error(ie, payload, type); else return ipike_payload_notify_process_info(ie, payload, type); } /* *=========================================================================== * Ipike_payload_notify_print *=========================================================================== */ IP_GLOBAL void Ipike_payload_notify_print(Ipike2_notify_payload* notify) { const char* type = IP_NULL; /* lint */ (void)type; type = ipike_payload_message_type_to_string(ip_ntohs(notify->message_type)); IPCOM_LOG2(DEBUG2, " message type: %s (%d)", type, ip_ntohs(notify->message_type)); if (notify->protocol_id != 0) { IPCOM_LOG1(DEBUG2, " protocol id: %s", ipike_proposal_proto_id_to_string(notify->protocol_id)); } if (notify->spi_size != 0) { (void)ipike_print_memory(IPCOM_LOG_DEBUG2, " spi: ", Ipike_payload_notify_spi(notify), notify->spi_size); } if (Ipike_payload_notify_data_length(notify) > 0) { if (Ipike_payload_notify_data_length(notify) > 16) { (void)ipike_print_memory(IPCOM_LOG_DEBUG2, " data:\n", Ipike_payload_notify_data(notify), Ipike_payload_notify_data_length(notify)); } else { (void)ipike_print_memory(IPCOM_LOG_DEBUG2, " data: ", Ipike_payload_notify_data(notify), Ipike_payload_notify_data_length(notify)); } } return; } /* *=========================================================================== * ipike_payload_notify_transport_mode *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_transport_mode(Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_USE_TRANSPORT_MODE, IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_transport_mode: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_dont_use_tfc *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_dont_use_tfc(Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_ESP_TFC_PADDING_NOT_SUPPORTED , IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_dont_use_tfc: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_rekey_sa *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_rekey_sa( Ip_u16 proto_id, Ipike_value *spi, Ipike2_notify_payload **payload) { Ipike_error err; err = ipike_payload_notify_create((Ip_u8)proto_id, IPIKE_NOTI_INF_REKEY_SA,spi, IP_NULL, payload); if (err != IPIKE_SUCCESS) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_rekey_sa: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_nat_detection *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_nat_detection( Ipike_isakmp_exchange* ie, Ip_bool source, Ipike2_notify_payload** payload) { Ipike_error err; Ipike_value data; Ip_u16 type; union Ip_sockaddr_union* address; data.value = IP_NULL; if ( source ) { if (ie->msg.local_addr.sa.sa_family != 0) address = &ie->msg.local_addr; else address = &ie->ike_sa->local_addr; } else { if (ie->msg.peer_addr.sa.sa_family != 0) address = &ie->msg.peer_addr; else address = &ie->ike_sa->peer_addr; } err = ipike_payload_notify_generate_nat_detection_data(ie->ike_sa->initiator_cookie, ie->ike_sa->responder_cookie, address, &data); if ( IPIKE_SUCCESS == err ) { if ( source ) type = IPIKE_NOTI_INF_NAT_DETECTION_SOURCE_IP; else type = IPIKE_NOTI_INF_NAT_DETECTION_DESTINATION_IP; err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP, type, IP_NULL, &data, payload); if ( IPIKE_SUCCESS != err ) IPCOM_LOG0(DEBUG, "ipike_payload_notify_nat_detection() :: failed to create"); } if (IP_NULL != data.value) ipcom_free(data.value); return err; } /* *=========================================================================== * ipike_payload_notify_cookie *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_cookie( Ipike_isakmp_exchange* ie, Ipike_value* cookie, Ipike2_notify_payload** payload) { Ipike_error err = IPIKE_SUCCESS; if (IP_NULL == cookie->value) { /* This will be called by responder to get the cookie value to send to * initiator. We will use the exchange responder cookie as the cookie * value, since we need to set the responder cookie value to zero and * still remember that value since we should restore it later (the value * is used to get unique ike sa). */ cookie->len = sizeof(ie->ike_sa->responder_cookie); cookie->value = ipcom_malloc(cookie->len); if (IP_NULL == cookie->value) { IP_PANIC(); err = IPIKE_OUT_OF_MEMORY; } else { ipcom_memcpy(cookie->value, ie->ike_sa->responder_cookie, cookie->len); } } if ((IPIKE_SUCCESS == err) && (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_COOKIE, IP_NULL, cookie, payload)))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_cookie: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_initial_contact *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_initial_contact( Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_INITIAL_CONTACT, IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_initial_contact: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_mobike_supported *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_mobike_supported( Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_MOBIKE_SUPPORTED, IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_mobike_supported: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_additional_ip_address *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_additional_ip_address( union Ip_sockaddr_union* addr, Ipike2_notify_payload** payload) { Ipike_error err = IPIKE_SUCCESS; Ipike_value data = {0}; Ip_u16 type = 0; #ifdef IPCOM_USE_INET if (addr->sin.sin_family == IP_AF_INET) type = IPIKE_NOTI_INF_ADDITIONAL_IP4_ADDRESS; #endif #ifdef IPCOM_USE_INET6 if (addr->sin.sin_family == IP_AF_INET6) type = IPIKE_NOTI_INF_ADDITIONAL_IP6_ADDRESS; #endif if (type == 0) err = IPIKE_INTERNAL_ERROR; if (IPIKE_SUCCESS == err) { data.len = ipike_addr_get_len(addr); data.value = ipike_addr_get_ptr(addr); if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, type, IP_NULL, &data, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_additional_ip_address: failed to create"); } } return err; } /* *=========================================================================== * ipike_payload_notify_no_additional_addresses *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_no_additional_addresses( Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_NO_ADDITIONAL_ADDRESSES, IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_no_additional_addresses: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_update_sa_addresses *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_update_sa_addresses( Ipike2_notify_payload** payload) { Ipike_error err; if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_UPDATE_SA_ADDRESSES, IP_NULL, IP_NULL, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_update_sa_addresses: failed to create"); } return err; } /* *=========================================================================== * ipike_payload_notify_cookie2 *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_cookie2( Ipike_value* cookie2, Ipike2_notify_payload** payload) { Ipike_error err = IPIKE_SUCCESS; /* Generate cookie2 if not set */ if (cookie2->value == IP_NULL) { cookie2->len = (Ip_size_t)ipcom_sysvar_get_as_int("ipike.nonce_size", 64); if (cookie2->len > 64) cookie2->len = 64; if (cookie2->len < 8) cookie2->len = 8; if ((cookie2->value = ipcom_malloc(cookie2->len)) == IP_NULL) { IP_PANIC(); err = IPIKE_OUT_OF_MEMORY; } else if (RAND_bytes(cookie2->value, (int)cookie2->len) == 0) { err = IPIKE_INVALID_VALUE; } } /* Create payload */ if (IPIKE_SUCCESS == err) { if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_COOKIE2, IP_NULL, cookie2, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_cookie2: failed to create"); } } return err; } /* *=========================================================================== * ipike_payload_notify_no_nats_allowed *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_no_nats_allowed( union Ip_sockaddr_union* src_addr, union Ip_sockaddr_union* dst_addr, Ipike2_notify_payload** payload) { Ipike_error err = IPIKE_SUCCESS; Ipike_value data = {0}; Ip_u16 port = 0; data.value = ipcom_malloc(sizeof(*src_addr) + sizeof(*dst_addr)); if (data.value == IP_NULL) { IP_PANIC(); err = IPIKE_OUT_OF_MEMORY; } else { data.len = 0; ipcom_memcpy(data.value + data.len, ipike_addr_get_ptr(src_addr), ipike_addr_get_len(src_addr)); data.len += ipike_addr_get_len(src_addr); ipcom_memcpy(data.value + data.len, ipike_addr_get_ptr(dst_addr), ipike_addr_get_len(dst_addr)); data.len += ipike_addr_get_len(dst_addr); port = ipike_addr_get_port(src_addr); port = ip_htons(port); ipcom_memcpy(data.value + data.len, &port, sizeof(port)); data.len += sizeof(port); port = ipike_addr_get_port(dst_addr); port = ip_htons(port); ipcom_memcpy(data.value + data.len, &port, sizeof(port)); data.len += sizeof(port); if (IPIKE_SUCCESS != (err = ipike_payload_notify_create( IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_NO_NATS_ALLOWED, IP_NULL, &data, payload))) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_no_nats_allowed: failed to create"); } ipcom_free(data.value); } return err; } /* *=========================================================================== * ipike_payload_notify_http_cert_lookup_support *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_http_cert_lookup_support( Ipike2_notify_payload** payload) { Ipike_error err; err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_HTTP_CERT_LOOKUP_SUPPORTED, IP_NULL, IP_NULL, payload); if (err != IPIKE_SUCCESS) { IPCOM_LOG0(DEBUG, "ipike_payload_notify_http_cert_lookup_support() ::"\ " failed to create"); } return err; } #ifdef IPIKE_USE_ROHC /* *=========================================================================== * ipike_payload_notify_http_cert_lookup_support *=========================================================================== */ IP_GLOBAL Ipike_error ipike_payload_notify_rohc( Ipike2_notify_payload** payload, Ipike_isakmp_exchange* ie) { Ipike_attribute attr_list[IPIKE_ATTR_ROHC_NUM_MAX]; Ipike_attribute * attr; Ipike_attribute * attr_end; Ipike_value data; Ipike_error err; Ipike_rohc * rohc; Ip_u32 i; /* Only applicable when negotiation IPsec SAs */ if ( ie->ipsec_sa == NULL || ie->ipsec_sa->v2.rohc == IP_NULL ) return IPIKE_SUCCESS; rohc = ie->ipsec_sa->v2.rohc; attr = &attr_list[0]; attr_end = &attr_list[IPIKE_ATTR_ROHC_NUM_MAX]; ip_assert(IPIKE_ATTR_ROHC_NUM_MAX > 5); /* Exactly one MAX_CID attribute MUST be sent */ attr->type = ip_htons(IPIKE_ATTR_ROHC_MAX_CID | IPIKE_ATTR_BASIC); attr->value = ip_htons(rohc->local.max_cid); attr++; /* There MUST be at least one ROHC_INTEG attribute contained within the * ROHC_SUPPORTED Notify message */ for ( i = 0; i < rohc->local.num_integ_algs; i++ ) { attr->type = ip_htons(IPIKE_ATTR_ROHC_INTEG | IPIKE_ATTR_BASIC); attr->value = ip_htons(rohc->local.integ_algs[i]); attr++; } /* There MAY be zero or one ROHC_ICV_LEN attribute contained within the * ROHC_SUPPORTED Notify message */ attr->type = ip_htons(IPIKE_ATTR_ROHC_ICV_LEN | IPIKE_ATTR_BASIC); attr->value = ip_htons(rohc->local.icv_len); attr++; /* There MAY be zero or one MRRU attribute contained within the * ROHC_SUPPORTED Notify message */ attr->type = ip_htons(IPIKE_ATTR_ROHC_MRRU | IPIKE_ATTR_BASIC); attr->value = ip_htons(rohc->local.mrru); attr++; /* There MUST be at least one ROHC_PROFILE attribute included in the * ROHC_SUPPORTED Notify message */ for ( i = 0; i < rohc->local.num_profiles; i++ ) { attr->type = ip_htons(IPIKE_ATTR_ROHC_PROFILE | IPIKE_ATTR_BASIC); attr->value = ip_htons(rohc->local.profiles[i]); attr++; if ( attr >= attr_end ) break; } if ( attr == &attr_list[IPIKE_ATTR_ROHC_NUM_MAX] ) { /* Increase IPIKE_ATTR_ROHC_NUM_MAX if this happens */ IPCOM_LOG0(WARNING, "ipike_payload_notify_rohc() :: All profiles may"\ " not have been added"); } data.value = (Ip_u8 *) attr_list; data.len = (Ip_size_t)(attr - attr_list) * sizeof(Ipike_attribute); err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP, IPIKE_NOTI_INF_ROHC_SUPPORTED, IP_NULL, &data, payload); if (err != IPIKE_SUCCESS) { IPCOM_LOG0(ERR, "ipike_payload_notify_rohc() :: failed to create"); return err; } return err; } #endif /* IPIKE_USE_ROHC */ #else int ipike_payload_notify_empty_file = 0; #endif /* IPIKE_USE_VERSION2 */ /* **************************************************************************** * END OF FILE **************************************************************************** */