/* * Copyright (c) 2013-2019, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "nsconfig.h" #include "ns_types.h" #include "eventOS_event.h" #include "ns_trace.h" #include "string.h" #include "randLIB.h" #include "nsdynmemLIB.h" #include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "ccmLIB.h" #include "shalib.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h" #ifdef ECC #include "libX509_V3.h" #include "ecc.h" #endif #include "Security/TLS/tls_lib.h" #include "Security/Common/sec_lib.h" #include "net_nvm_api.h" #include "Security/PANA/pana.h" #include "Security/PANA/pana_internal_api.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "6LoWPAN/ND/nd_router_object.h" #include "Common_Protocols/udp.h" #ifdef ECC #include "ecc.h" #endif #include "common_functions.h" #include "Security/PANA/pana_nvm.h" #include "Security/PANA/pana_avp.h" #include "Security/PANA/pana_eap_header.h" #include "Security/PANA/pana_header.h" #include "Security/PANA/eap_protocol.h" #include "net_pana_parameters_api.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "socket_api.h" #ifdef PANA #define TRACE_GROUP "pana" typedef enum { ARM_PANA_INIT = 0, ARM_PANA_TLS_CB = 1, } arm_pana_event_id_e; //Pana Relay Constant const uint8_t PANA_AUTH_STRING[9] = {'I', 'E', 'T', 'F', ' ', 'P', 'A', 'N', 'A'}; const uint8_t PANA_PAA_ENC_KEY_STRING[18] = {'I', 'E', 'T', 'F', ' ', 'P', 'A', 'N', 'A', ' ', 'P', 'A', 'A', ' ', 'E', 'n', 'c', 'r'}; const uint8_t PANA_PAC_ENC_KEY_STRING[18] = {'I', 'E', 'T', 'F', ' ', 'P', 'A', 'N', 'A', ' ', 'P', 'a', 'C', ' ', 'E', 'n', 'c', 'r'}; static void pana_key_calc(bool enc_key, sec_suite_t *suite); static void pana_handshake_copy(uint8_t *ptr, uint16_t len, bool request, sec_suite_t *suite); //TLS message parse support NS_LARGE int8_t pana_socket = -1; /*socket variable*/ static int8_t pana_tasklet_id = -1; static pana_socket_packet_handler_cb *pana_socket_packet_handler = NULL; static pana_state_machine_step *pana_state_machine_step_cb = NULL; static pana_eap_tls_up_cb *pana_tls_handler_cb = NULL; static NS_LARGE uint8_t pana_key_material[32]; /** Pana Protocol Dynamic Parameters */ static pana_lib_parameters_s pana_library_params = { .PCI_IRT = 10, .PCI_MRT = 60, .PCI_MRC = 5, .REQ_IRT = 20, .REQ_MRT = 60, .REQ_MRC = 4, .AUTHENTICATION_TIMEOUT = 120, .KEY_UPDATE_THRESHOLD = 10, .KEY_ID_MAX_VALUE = 0xff, .EAP_FRAGMENT_SIZE = EAP_MTU_FRAG_SIZE, .AUTH_COUNTER_MAX = 0xff }; pana_lib_parameters_s *pana_parameters_get(void) { return &pana_library_params; } int8_t pana_socket_id_get(void) { return pana_socket; } void pana_common_state_machine(sec_suite_t *suite) { if (pana_state_machine_step_cb) { pana_state_machine_step_cb(suite); } } pana_session_t *pana_session_allocate(void) { pana_session_t *p_session = ns_dyn_mem_alloc(sizeof(pana_session_t)); if (p_session) { memset(p_session, 0, sizeof(pana_session_t)); p_session->session_ready = false; p_session->key_warp = false; p_session->user_server = false; p_session->eap_id_seq = randLIB_get_8bit(); //Take Random EAP ID } return p_session; } void pana_session_base_init(pana_session_t *p_session) { memset(p_session, 0, sizeof(pana_session_t)); p_session->session_ready = false; p_session->key_warp = false; p_session->user_server = false; p_session->eap_id_seq = randLIB_get_8bit(); //Take Random EAP ID } void pana_session_state_init(pana_session_t *p_session) { p_session->key_warp = false; p_session->address_status = 0; } pana_heap_t *pana_heap_structure_allocate(void) { pana_heap_t *heap = ns_dyn_mem_temporary_alloc(sizeof(pana_heap_t)); if (heap) { heap->handshake_len = 0; heap->handshake_req_offset = 0; randLIB_get_n_bytes_random(heap->client_nonce, 16); } return heap; } static buffer_t *pana_eap_payload_to_avp(buffer_t *buf) { uint8_t *ptr; uint16_t eap_len, padding; eap_len = buffer_data_length(buf); padding = eap_len; if ((buf = buffer_headroom(buf, 8)) == 0) { return NULL; } buffer_data_reserve_header(buf, 8); //tr_debug("EAP AVP LEN: %02x", eap_len); ptr = buffer_data_pointer(buf); ptr = pana_avp_base_write(AVP_EAP_PAYLOAD_CODE, eap_len, ptr, 0, 0); //Check Padding padding %= 4; if (padding) { padding = 4 - padding; //tr_debug("Add Pad: %02x", padding); if ((buf = buffer_headroom(buf, padding)) != 0) { uint8_t *ptr2; buffer_data_reserve_header(buf, padding); ptr = buffer_data_pointer(buf); ptr2 = ptr; ptr += padding; memmove(ptr2, ptr, eap_len + 8); } else { return NULL; } } return buf; } int8_t pana_get_params(pana_lib_parameters_s *params) { if (params) { *params = pana_library_params; return 0; } return -1; } int8_t pana_set_params(const pana_lib_parameters_s *params) { int8_t ret_val = -1; if (!params) { } else if (params->PCI_IRT == 0 || params->PCI_MRT == 0 || params->PCI_MRC == 0) { } else if (params->REQ_IRT == 0 || params->REQ_MRT == 0 || params->REQ_MRC == 0) { } else if (params->KEY_UPDATE_THRESHOLD == 0 || params->KEY_ID_MAX_VALUE < 3) { } else if (params->EAP_FRAGMENT_SIZE < 64 || params->EAP_FRAGMENT_SIZE >= 920) { } else if ((params->PCI_IRT > params->PCI_MRT) || (params->REQ_IRT > params->REQ_MRT)) { } else { ret_val = 0; pana_library_params = *params; } return ret_val; } const pana_lib_parameters_s *pana_get_params_ptr(void) { return &pana_library_params; } void pana_timeout_timer_set(sec_suite_t *suite, sec_state_machine_t cur_state) { uint32_t timer; uint32_t timer_inc; uint32_t timer_max; uint8_t retry; retry = suite->retry_counter; if (cur_state == PANA_PCI_TX) { timer_inc = (pana_library_params.PCI_IRT * 10); timer_max = (pana_library_params.PCI_MRT * 10); } else { timer_inc = (pana_library_params.REQ_IRT * 10); timer_max = (pana_library_params.REQ_MRT * 10); } timer = timer_inc; while (retry > 1) { timer += timer_inc; if (timer > timer_max) { timer = timer_max; retry = 0; } else { retry--; } } //Set State suite->state = cur_state; suite->timer = timer; } uint8_t pana_retry_req_max_get(void) { return pana_library_params.REQ_MRC; } uint32_t pana_handshake_timeout(void) { uint32_t ret_val = (pana_library_params.AUTHENTICATION_TIMEOUT * 10); return ret_val; } int pana_retry_check(uint8_t counter, sec_state_machine_t cur_state) { int ret_val = -1; if (cur_state == PANA_PCI_TX) { if (counter < pana_library_params.PCI_MRC) { ret_val = 0; } } else { if (counter < pana_library_params.REQ_MRC) { ret_val = 0; } } return ret_val; } uint8_t *pana_key_get(const uint8_t *key) { static uint8_t key_seed[8] = {'Z', 'i', 'g', 'B', 'e', 'e', 'I', 'P'}; SHALIB_init_HMAC(key, 16); SHALIB_push_data_HMAC(key_seed, 8); SHALIB_finish_HMAC(pana_key_material, 8); return pana_key_material; } //static void pana_key_pair_data_generate(sec_suite_t *suite) //{ // uint8_t *pac, *paa; // if (suite->setups & TLS_SERVER_MODE) { // //Server // paa = suite->interface->iid_eui64; // pac = &suite->session_address[8]; // } else { // pac = suite->interface->iid_eui64; // paa = &suite->session_address[8]; // // } // SHALIB_push_data_HMAC(paa, 8); // SHALIB_push_data_HMAC(pac, 8); //} ///* Define Pair wise Key*/ //static uint8_t pana_hmac_temp_key[64]; //static uint8_t *pana_generate_key_pair_key(sec_suite_t *suite, uint8_t *common_key, uint8_t *key_ptr) //{ // static uint8_t key_seed[8] = {'K', 'e', 'y', 'P', 'a', 'i', 'r', '?'}; // memcpy(pana_hmac_temp_key, suite->pana_session.pana_auth_key, 32); // memcpy(&pana_hmac_temp_key[32], common_key, 16); // // SHALIB_init_HMAC(pana_hmac_temp_key, 48); // // SHALIB_push_data_HMAC(key_seed, 8); // pana_key_pair_data_generate(suite); // SHALIB_push_data_HMAC(&suite->pana_session.auth_cnt, 1); // SHALIB_finish_HMAC(common_key, 4); // return common_key; //} void pana_session_init_by_session_ptr(sec_suite_t *suite, auth_info_t *auth_ptr) { if (suite) { suite->setups = 0; pana_session_state_init(&suite->pana_session); suite->pana_session.auth_info = auth_ptr; eap_fragmentation_init(suite); if (suite->pana_session.session_ready) { tr_debug("Ping Notify"); suite->state = PANA_PING_REQ; suite->timer = 1; suite->retry_counter = 0; } else { if (sec_pana_protocol_init(suite) == 0) { sec_lib_state_machine_trig(suite, PANA_ERROR); } } } } void pana_authentication_ready(uint8_t status, protocol_interface_info_entry_t *cur_interface) { if (status) { nwk_6lowpan_bootsrap_pana_authentication_cb(true, cur_interface); } else { nwk_6lowpan_bootsrap_pana_authentication_cb(false, cur_interface); } } #ifdef ECC extern void sec_ecc_state_free(sec_suite_t *suite); #endif void pana_reset_values(uint16_t pana_id) { sec_suite_t *suite = 0; suite = sec_suite_selected_py_pan_id(pana_id); if (suite) { suite->timer = 0; sec_suite_tls_free(suite, true); pana_free_dynamic_ram(suite); #ifdef ECC sec_ecc_state_free(suite); #endif } } static void pana_socket_callback(void *cb) { socket_buffer_callback_t *cb_buf = cb; if (cb_buf->event_type == SOCKET_DATA) { buffer_t *buf = cb_buf->buf; if (buf) { //Find or create session //Do CB HERE buf->socket = socket_dereference(buf->socket); buf->session_ptr = NULL; pana_socket_packet_handler(buf); } } else { sec_suite_socket_event(cb_buf->event_type, cb_buf->session_ptr); } } void pana_event_handler(arm_event_s *event) { switch (event->event_type) { case ARM_PANA_INIT: tr_debug("Pana Tasklet Init"); break; case ARM_PANA_TLS_CB: if (event->data_ptr) { buffer_t *buf = event->data_ptr; sec_suite_t *tls_suite = buf->session_ptr; buf->session_ptr = NULL; tls_suite = sec_suite_verify(tls_suite); if (tls_suite && pana_tls_handler_cb) { buf = pana_tls_handler_cb(buf, tls_suite); } else { tr_warn("Pana/TLS er"); } if (buf) { buffer_free(buf); } } break; default: break; } } bool pana_socket_init(pana_socket_packet_handler_cb *socket_handler, pana_state_machine_step *state_machine_stepper, pana_eap_tls_up_cb *tls_handler_cb) { tr_debug("Pana sub-layer init"); if (pana_socket == -1) { if (socket_create(SOCKET_FAMILY_IPV6, SOCKET_TYPE_DGRAM, 0, &pana_socket, UDP_PORT_PANA, pana_socket_callback, true) != eOK) { return false; } //GENERATE TASKLET if not created before if (pana_tasklet_id == -1) { pana_tasklet_id = eventOS_event_handler_create(&pana_event_handler, ARM_PANA_INIT); if (pana_tasklet_id < 0) { socket_close(pana_socket); pana_socket = -1; return false; } } } tr_debug("Pana socket Id %i", pana_socket); pana_socket_packet_handler = socket_handler; pana_state_machine_step_cb = state_machine_stepper; pana_tls_handler_cb = tls_handler_cb; return true; } void pana_set_agend_address(buffer_t *buf, bool relay, sec_suite_t *suite) { uint8_t *ptr = 0; buf->interface = suite->interface; protocol_interface_info_entry_t *cur = buf->interface; if (cur) { if (suite->pana_session.user_server) { if (relay) { ptr = protocol_6lowpan_nd_border_router_address_get(buf->interface->nwk_id); if (ptr) { memcpy(buf->src_sa.address, ptr, 16); ptr = suite->pana_session.session_relay_address; memcpy(buf->dst_sa.address, ptr, 16); } // buf->options.ll_security_bypass_tx = false; } else { //Default addr_interface_get_ll_address(cur, buf->src_sa.address, 2); ptr = suite->session_address; memcpy(buf->dst_sa.address, ptr, 16); buf->options.ll_security_bypass_tx = true; } } else { if (relay) { ptr = protocol_6lowpan_nd_border_router_address_get(buf->interface->nwk_id); if (ptr) { memcpy(buf->dst_sa.address, ptr, 16); memcpy(suite->pana_session.session_relay_address, ptr, 16); //Select source by Dst address (void) addr_interface_select_source(cur, buf->src_sa.address, buf->dst_sa.address, 0); } buf->options.ll_security_bypass_tx = false; } else { //tr_debug("LL Agent"); nd_router_t *object = nd_get_pana_address(); if (object) { icmp_nd_set_nd_def_router_address(buf->dst_sa.address, object); tr_debug("MD Router adr: %s", trace_ipv6(buf->dst_sa.address)); } else { //tr_debug("Use Mac Coordinator"); protocol_6lowpan_interface_get_link_local_cordinator_address(cur, buf->dst_sa.address); } ptr = suite->session_address; memcpy(ptr, buf->dst_sa.address, 16); addr_interface_get_ll_address(cur, buf->src_sa.address, 1); buf->options.ll_security_bypass_tx = true; } } } tr_debug("DST %s src %s", trace_ipv6(buf->dst_sa.address), trace_ipv6(buf->src_sa.address)); buf->src_sa.addr_type = ADDR_IPV6; buf->dst_sa.addr_type = ADDR_IPV6; } buffer_t *build_pana_base(buffer_t *buf, pana_header_t *header, sec_suite_t *suite) { uint8_t *ptr; buf->session_ptr = NULL; buf = buffer_headroom(buf, PANA_HEADER_LENGTH); if (!buf) { return NULL; } buf = buffer_turnaround(buf); // In case we're reusing a buffer ptr = buffer_data_reserve_header(buf, PANA_HEADER_LENGTH); header->payload_len = buffer_data_length(buf); pana_header_write(ptr, header); buf->src_sa.port = UDP_PORT_PANA; buf->dst_sa.port = suite->session_port; buf->info = (buffer_info_t)(B_DIR_DOWN + B_FROM_APP + B_TO_UDP); if (header->type != PANA_MSG_RELAY || suite->pana_session.user_server) { buffer_socket_set(buf, socket_pointer_get(pana_socket)); buf->session_ptr = suite; } else { buf->socket = socket_dereference(buf->socket); buf->session_ptr = NULL; } //tr_debug("From Pana-> Core"); buf->interface = suite->interface; tr_debug("PANA len: %d", header->payload_len); return buf; } void pana_eap_tls_up(buffer_t *buf, sec_suite_t *suite) { buf = eap_up(buf, suite); if (!buf) { return; } pana_eap_down(buf, suite); } void pana_eap_down(buffer_t *buf, sec_suite_t *suite) { buf = eap_down(buf, suite); if (!buf) { return; } //Set EAP Payload pana_eap_payload_down(buf, NULL, suite); } void pana_eap_payload_down(buffer_t *buf, const uint8_t *nonce, sec_suite_t *suite) { buf = pana_eap_payload_to_avp(buf); if (!buf) { return; } if (nonce) { if ((buf = buffer_headroom(buf, 24)) == 0) { return; } buffer_data_reserve_header(buf, 24); uint8_t *ptr = buffer_data_pointer(buf); ptr = pana_avp_write_n_bytes(AVP_NONCE_CODE, 16, nonce, ptr); } pana_down(buf, suite); } void pana_handshake_copy(uint8_t *ptr, uint16_t len, bool request, sec_suite_t *suite) { if (suite->pana_session.pana_heap) { uint8_t *dptr = 0; pana_heap_t *pheap = suite->pana_session.pana_heap; dptr = pheap->pana_handshake; if (!request) { dptr += pheap->handshake_req_offset; pheap->handshake_len = len + pheap->handshake_req_offset; } else { pheap->handshake_req_offset = len; pheap->handshake_len = len; } memcpy(dptr, ptr, len); } } void pana_down(buffer_t *buf, sec_suite_t *suite) { //Check Request Or Response pana_header_t header; header.type = PANA_MSG_PA; if (suite->pana_session.user_server) { if (suite->state == PANA_REQUEST_TX) { header.flags = PANA_FLAGS_START | PANA_FLAGS_REQUEST; } else if (suite->state == EAP_PANA_FINISH || suite->state == PANA_FAILURE) { header.flags = (PANA_FLAGS_REQUEST | PANA_FLAGS_COMPLETE); } else if (suite->state == PANA_FAILURE_RESPONSE) { header.flags = (PANA_FLAGS_RESPONSE | PANA_FLAGS_COMPLETE); } else { header.flags = PANA_FLAGS_REQUEST; } } else { if (suite->state == PANA_FAILURE) { header.flags = PANA_FLAGS_COMPLETE; } else if (suite->state == PANA_START_RESPONSE) { header.flags = PANA_FLAGS_START; } else { header.flags = 0; } } if (header.flags & PANA_FLAGS_REQUEST) { header.seq = suite->pana_session.req_seq; } else { header.seq = suite->pana_session.res_seq; } header.session_id = suite->pana_session.session_id; pana_set_agend_address(buf, false, suite); buf = build_pana_base(buf, &header, suite); if (buf) { /** * Copy Authentication start message */ if (header.flags & PANA_FLAGS_START) { uint16_t len = buffer_data_length(buf); uint8_t *ptr = buffer_data_pointer(buf); if (header.flags & PANA_FLAGS_REQUEST) { pana_handshake_copy(ptr, len, true, suite); } else { pana_handshake_copy(ptr, len, false, suite); } } if (suite->pana_session.address_status & 1) { tr_debug("Build Relay"); buf = pana_relay_avp_build(buf, suite); if (buf) { header.flags = 0; header.type = PANA_MSG_RELAY; header.session_id = 0; header.seq = 0; buf = build_pana_base(buf, &header, suite); } } protocol_push(buf); } } buffer_t *pana_relay_avp_build(buffer_t *buf, sec_suite_t *suite) { uint8_t *ptr, *adr_ptr; uint16_t relay_len, padding; relay_len = buffer_data_length(buf); padding = relay_len; buf->socket = socket_dereference(buf->socket); buf->session_ptr = NULL; if ((buf = buffer_headroom(buf, 36)) == 0) { return buf; } else { buffer_data_reserve_header(buf, 36); ptr = buffer_data_pointer(buf); ptr = pana_avp_base_write(AVP_PAC_INFO_CODE, 18, ptr, 0, 0); //SET Relay IPV6 address if (suite->pana_session.user_server) { memcpy(ptr, suite->session_address, 16); ptr += 16; ptr = common_write_16_bit(suite->session_port, ptr); adr_ptr = protocol_6lowpan_nd_border_router_address_get(buf->interface->nwk_id); if (adr_ptr) { memcpy(buf->src_sa.address, adr_ptr, 16); memcpy(buf->dst_sa.address, suite->pana_session.session_relay_address, 16); buf->dst_sa.port = suite->pana_session.relay_port; } } else { memcpy(ptr, buf->src_sa.address, 16); ptr += 16; ptr = common_write_16_bit(buf->src_sa.port, ptr); } //PADDING for PAC ptr = common_write_16_bit(0, ptr); //PANA Relay AVP header Write data is already there ptr = pana_avp_base_write(AVP_RELAY_MSG_CODE, relay_len, ptr, 0, 0); } //Enable security for relay allways by Default buf->options.ll_security_bypass_tx = false; padding %= 4; if (padding) { padding = 4 - padding; //tr_debug("Add Pad: %02x", padding); if ((buf = buffer_headroom(buf, padding)) != 0) { uint8_t *ptr2; buffer_data_reserve_header(buf, padding); ptr = buffer_data_pointer(buf); ptr2 = ptr; ptr += padding; memmove(ptr2, ptr, relay_len + 36); } } return buf; } bool pana_auth_check(uint8_t *ptr, uint16_t length, uint8_t *authency, uint8_t *key) { if (!authency) { return false; } uint8_t hasn_buf_temp[16]; uint8_t compare_hash_temp[16]; //tr_debug("AV SUCCESS. Hash RX: %s", trace_array(ptr, 16)); memcpy(compare_hash_temp, authency, 16); memset(authency, 0, 16); length += 16; ptr -= 16;//Shift Pana Headers back //tr_debug("Calc: %s", trace_array(key, 32) ); SHALIB_init_HMAC(key, 32); SHALIB_push_data_HMAC(ptr, length); //tr_debug("%s", trace_array(ptr,length)); SHALIB_finish_HMAC(hasn_buf_temp, 4); if (memcmp(hasn_buf_temp, compare_hash_temp, 16) != 0) { tr_debug("HASH AUTH Fail. RX: %s", trace_array(compare_hash_temp, 16)); tr_debug("Cal: %s", trace_array(hasn_buf_temp, 16)); return false; } return true; } int8_t pana_ccm_data_crypt(uint8_t *ptr, uint16_t len, uint8_t operation_type, uint32_t message_seq, sec_suite_t *suite) { uint8_t *explict_ptr; uint8_t *key_ptr = 0; ccm_globals_t ccm_ptr; key_ptr = suite->pana_session.pana_PAA_enc_key; //Here Comes AES Decrypt if (!ccm_sec_init(&ccm_ptr, AES_SECURITY_LEVEL_ENC, key_ptr, operation_type, 3)) { return -1; } explict_ptr = ccm_ptr.exp_nonce; //Set IV explict_ptr = common_write_32_bit(suite->pana_session.pana_key_id, explict_ptr); //SET EXP 4 octest Session ID, 4 Octet Pana SQN number explict_ptr = common_write_32_bit(suite->pana_session.session_id, explict_ptr); explict_ptr = common_write_32_bit(message_seq, explict_ptr); ccm_ptr.data_len = len; ccm_ptr.data_ptr = ptr; return ccm_process_run(&ccm_ptr); } buffer_t *pana_relay_parse(buffer_t *buf) { uint8_t *ptr; buf->options.ll_security_bypass_tx = true; //tr_debug("Relay RX"); ptr = buffer_data_pointer(buf); uint16_t length = buffer_data_length(buf); pana_avp_t pac_info; pac_info.code = AVP_PAC_INFO_CODE; if (!pana_avp_discover(ptr, length, &pac_info) || pac_info.len != 18) { tr_debug("No Pac info"); return buffer_free(buf); } pana_avp_t relay_msg; relay_msg.code = AVP_RELAY_MSG_CODE; if (!pana_avp_discover(ptr, length, &relay_msg)) { tr_debug("No Relay MSG"); return buffer_free(buf); } //Set Message data to relay msg buffer_data_pointer_set(buf, relay_msg.avp_ptr); buffer_data_length_set(buf, relay_msg.len); //Set Destination to Pac Info ptr = pac_info.avp_ptr; memcpy(buf->dst_sa.address, ptr, 16); //buf->dst_sa.addr_type = ADDR_IPV6; ptr += 16; buf->dst_sa.port = common_read_16_bit(ptr); ptr += 2; //tr_debug("%s", trace_array(buf->dst_sa.address, 16) ); return buf; } void pana_session_startms_parse(buffer_t *buf, pana_header_t *header, sec_suite_t *suite) { uint32_t prf_algorythm = 0; uint32_t integrity_algorythm = 12; uint32_t key_wrap = 0; bool key_wrap_parsed = false; uint16_t len = buffer_data_length(buf); uint8_t *ptr = buffer_data_pointer(buf); pana_avp_t avp_temp; //Read Resul and Key id if they are coming avp_temp.code = AVP_PRF_ALGORYTHM_CODE; avp_temp.len = 0; if (pana_avp_discover(ptr, len, &avp_temp) && avp_temp.len == 4) { prf_algorythm = common_read_32_bit(avp_temp.avp_ptr); } avp_temp.code = AVP_INTEGRIRTY_ALGORYTHM_CODE; avp_temp.len = 0; if (pana_avp_discover(ptr, len, &avp_temp) && avp_temp.len == 4) { integrity_algorythm = common_read_32_bit(avp_temp.avp_ptr); } avp_temp.code = AVP_KEY_WRAP_ALG_CODE; avp_temp.len = 0; if (pana_avp_discover(ptr, len, &avp_temp) && avp_temp.len == 4) { key_wrap = common_read_32_bit(avp_temp.avp_ptr); key_wrap_parsed = true; } bool drop_message = false; if ((header->flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { if (prf_algorythm != suite->pana_session.prf_algorythm) { tr_debug("PRF!!"); drop_message = true; } else if (integrity_algorythm != suite->pana_session.integrity_algorythm) { tr_debug("int!!"); drop_message = true; } if (key_wrap_parsed && key_wrap != suite->pana_session.key_wrap) { tr_debug("key!!"); drop_message = true; } } else { if (prf_algorythm != 5) { drop_message = true; } else if (integrity_algorythm != 12) { drop_message = true; } } if (!drop_message) { if (key_wrap_parsed) { suite->pana_session.key_warp = true; suite->pana_session.key_wrap = key_wrap; } len += 16; ptr -= 16; //Shift Pana Headers back if ((header->flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { sec_lib_state_machine_trig(suite, EAP_IDENTITY_REQ); pana_handshake_copy(ptr, len, false, suite); } else { suite->pana_session.integrity_algorythm = integrity_algorythm; suite->pana_session.prf_algorythm = prf_algorythm; sec_lib_state_machine_trig(suite, PANA_START_RESPONSE); pana_handshake_copy(ptr, len, true, suite); } suite->retry_counter = 0; } buffer_free(buf); } buffer_t *pana_auth_message_handler(buffer_t *buf, pana_header_t *header, sec_suite_t *suite) { if (!buf) { return NULL; } protocol_interface_info_entry_t *cur = buf->interface; if (!cur) { return buffer_free(buf); } uint16_t length = buffer_data_length(buf); uint8_t *ptr = buffer_data_pointer(buf); pana_avp_t avp_temp; if (suite->pana_session.session_ready) { return buffer_free(buf); } if (sec_check_suite_ptrs(suite) == 0) { tr_warn("SEC Lib Fail"); return buffer_free(buf); } avp_temp.code = AVP_NONCE_CODE; if (pana_avp_discover(ptr, length, &avp_temp)) { if (avp_temp.len == 16) { if ((header->flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { memcpy(suite->pana_session.pana_heap->client_nonce, avp_temp.avp_ptr, 16); } else { memcpy(suite->pana_session.pana_heap->agent_nonce, avp_temp.avp_ptr, 16); } //tr_debug("Pana:A_NONCE OK"); } else { tr_debug("A_NONCE length fail, Len: %x", avp_temp.len); } } avp_temp.code = AVP_EAP_PAYLOAD_CODE; if (pana_avp_discover(ptr, length, &avp_temp)) { ptr = avp_temp.avp_ptr; if (avp_temp.len > 4) { buf->buf_ptr = 0; buf->buf_end = avp_temp.len; memmove(buf->buf, ptr, avp_temp.len); return buf; } } return buffer_free(buf); } void pana_start_message_build(buffer_t *buf, sec_suite_t *suite) { uint8_t *ptr; //tr_debug("TX Pana Start Response"); buf->buf_ptr = PANA_HEADER_LENGTH; ptr = buffer_data_pointer(buf); ptr = pana_avp_32_bit_write(AVP_PRF_ALGORYTHM_CODE, suite->pana_session.prf_algorythm, ptr); ptr = pana_avp_32_bit_write(AVP_INTEGRIRTY_ALGORYTHM_CODE, suite->pana_session.integrity_algorythm, ptr); if (suite->pana_session.key_warp) { ptr = pana_avp_32_bit_write(AVP_KEY_WRAP_ALG_CODE, suite->pana_session.key_wrap, ptr); } buffer_data_end_set(buf, ptr); pana_down(buf, suite); } void eap_tls_payload_push(buffer_t *buf) { arm_event_s event = { .receiver = pana_tasklet_id, .sender = 0, .data_ptr = buf, .event_type = ARM_PANA_TLS_CB, .priority = ARM_LIB_HIGH_PRIORITY_EVENT, }; if (eventOS_event_send(&event) != 0) { tr_warn("Free Buffer if fail"); buf->session_ptr = NULL; buffer_free(buf); } } void pana_free_dynamic_ram(sec_suite_t *suite) { if (suite->pana_session.pana_heap) { tr_debug("Free Pana Heap"); ns_dyn_mem_free(suite->pana_session.pana_heap); suite->pana_session.pana_heap = NULL; } eap_fragmentation_init(suite); } static void pana_key_calc(bool enc_key, sec_suite_t *suite) { pana_heap_t *pheap = suite->pana_session.pana_heap; //tr_debug("Pana Auth verify. MSK: %s", trace_array(suite->pana_session.MSK, 64) ); SHALIB_init_HMAC(pheap->MSK, 64); if (enc_key) { //tr_debug("Cal Pana En Key start"); SHALIB_push_data_HMAC(PANA_PAA_ENC_KEY_STRING, 18); } else { SHALIB_push_data_HMAC(PANA_AUTH_STRING, 9); } //tr_debug("Handshake data: %s", trace_array(pheap->pana_handshake, pheap->handshake_len)); SHALIB_push_data_HMAC(pheap->pana_handshake, pheap->handshake_len); // tr_debug("Handshake data"); // tr_debug("C Nonce: %s", trace_array(pheap->client_nonce, 16) ); SHALIB_push_data_HMAC(pheap->client_nonce, 16); // tr_debug("A Nonce: %s", trace_array(pheap->agent_nonce, 16) ); SHALIB_push_data_HMAC(pheap->agent_nonce, 16); uint8_t temp32_buf[4]; // tr_debug("Key ID: %s", trace_array(temp32_buf, 4) ); common_write_32_bit(suite->pana_session.pana_key_id, temp32_buf); SHALIB_push_data_HMAC(temp32_buf, 4); SHALIB_push_data_HMAC(&(const uint8_t) { 1 }, 1); if (enc_key) { uint8_t *key_ptr = suite->pana_session.pana_PAA_enc_key; SHALIB_finish_HMAC(key_ptr, 4); } else { SHALIB_finish_HMAC(suite->pana_session.pana_auth_key, 8); } } void pana_key_calculation(sec_suite_t *suite) { pana_key_calc(false, suite); pana_key_calc(true, suite); } void pana_auth_hash_calc(uint8_t *data_ptr, uint16_t data_length, uint8_t *key) { SHALIB_init_HMAC(key, 32); SHALIB_push_data_HMAC(data_ptr, data_length); data_ptr += (data_length - 16); SHALIB_finish_HMAC(data_ptr, 4); } #ifdef ECC static void certificate_copy_block(const arm_certificate_chain_entry_s *rx_chain_info, certificate_chain_internal_t *cert) { uint8_t i; cert->chain_length = rx_chain_info->chain_length; for (i = 0; i < cert->chain_length; i++) { //Copy Certi cert->certi_chain[i] = rx_chain_info->cert_chain[i]; cert->certi_len[i] = rx_chain_info->cert_len[i]; //Copy Cur Key cert->key_chain[i] = rx_chain_info->key_chain[i]; } } #endif int8_t pana_interface_certificate_chain_set(const arm_certificate_chain_entry_s *chain_info) { #ifdef ECC if (!chain_info) { return -1; } certificate_chain_internal_t temp_certi; certificate_copy_block(chain_info, &temp_certi); return x509_cetificate_chain_push(SEC_NWK_AUTHENTICATION_CERTI_CHAIN, &temp_certi); #else (void) chain_info; return -1; #endif } #endif /*PANA*/ //************************ECC Certificates end /* end of file */