/* * Copyright (c) 2017-2019, Arm Limited 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 "6LoWPAN/NVM/nwk_nvm.h" #ifdef PANA #ifdef PANA_SERVER_API #define TRACE_GROUP "PanS" static pana_server_base_t *NS_LARGE pana_server_base = NULL; static pana_server_update_cb *pana_nvm_storage_cb = NULL; static pana_server_session_get_cb *pana_server_nvm_get = NULL; static pana_server_session_get_by_id_cb *pana_server_nvm__session_get = NULL; static void (*pana_key_update_process_ready)(void) = 0; static uint8_t *pana_nvm_buffer = 0; static void pana_server_packet_handler(buffer_t *buf); static int8_t pana_server_init(int8_t nwk_id, const uint8_t *network_key_material, uint8_t supported_chipher_suites, uint32_t key_update_delay); static pana_server_base_t *pana_server_staructure_allocate(void); static pana_key_material_t *pana_server_key_get(bool primary); static void pana_server_set_random_key_value(uint8_t *network_key_material); static void pana_server_material_read(const uint8_t *ptr); static void pana_server_material_write(uint8_t *ptr); static void pana_server_client_save_to_nvm(sec_suite_t *suite, pana_nvm_update_process_t nvm_event); static uint8_t *pana_avp_zip_key_material(uint8_t *dptr, uint8_t *key_info, uint32_t message_seq, sec_suite_t *suite); static void pana_client_session_init(sec_suite_t *suite); static bool pana_auth_msg_validate(uint8_t *ptr, uint16_t length, uint8_t *key); static void pana_pna_response_build(buffer_t *buf, uint8_t operation, pana_header_t *header, sec_suite_t *suite); static void pana_client_authentication_fail(sec_suite_t *suite); static void pana_key_update_delivery_ready(void); static void pana_server_build_key_push(buffer_t *buf, sec_suite_t *suite); static void pana_success_server_build(buffer_t *buf, sec_suite_t *suite); static void pana_server_state_machine_func(sec_suite_t *suite); static uint8_t *pana_avp_zip_key_material(uint8_t *dptr, uint8_t *key_info, uint32_t message_seq, sec_suite_t *suite) { //SET AVP BASE dptr = pana_avp_base_write(AVP_ENCRYPT_ALGORITHM_CODE, 32, dptr, 0, 0); uint8_t *ptr = dptr; dptr = pana_avp_vendor_id_write_n_bytes(PANA_EAP_KEYWRAP_TYPE, 18, key_info, dptr, ZIGBEE_VENDOR_ID); //Crypt Key Info pana_ccm_data_crypt(ptr, 32, AES_CCM_ENCRYPT, message_seq, suite); return dptr; } static pana_server_base_t *pana_server_staructure_allocate(void) { pana_server_base_t *server = ns_dyn_mem_alloc(sizeof(pana_server_base_t)); if (server) { memset(server, 0, sizeof(pana_server_base_t)); } return server; } static pana_key_material_t *pana_server_key_get(bool primary) { if (primary) { return &pana_server_base->sec_key_material[pana_server_base->primary_material]; } if (pana_server_base->primary_material) { return &pana_server_base->sec_key_material[0]; } return &pana_server_base->sec_key_material[1]; } static void pana_server_set_random_key_value(uint8_t *network_key_material) { randLIB_get_n_bytes_random(network_key_material, 16); } static void pana_server_material_write(uint8_t *ptr) { pana_key_material_t *key_ptr; ptr = common_write_32_bit(pana_server_base->pana_key_id, ptr); ptr = common_write_32_bit(pana_server_base->session_lifetime, ptr); ptr = common_write_32_bit(pana_server_base->key_wrap, ptr); ptr = common_write_32_bit(pana_server_base->prf_algorythm, ptr); ptr = common_write_32_bit(pana_server_base->integrity_algorythm, ptr); ptr = common_write_32_bit(pana_server_base->next_session_id, ptr); ptr = common_write_32_bit(pana_server_base->key_update_delay, ptr); ptr = common_write_32_bit(pana_server_base->pana_key_update_delay_used, ptr); //32 *ptr++ = pana_server_base->supported_chipher_suites; *ptr++ = pana_server_base->auth_cnt; *ptr++ = pana_server_base->primary_material; key_ptr = &pana_server_base->sec_key_material[0]; *ptr++ = key_ptr->key_id; memcpy(ptr, key_ptr->key_material, 16); ptr += 16;//52 key_ptr = &pana_server_base->sec_key_material[1]; *ptr++ = key_ptr->key_id; memcpy(ptr, key_ptr->key_material, 16); ptr += 16; //69 if (pana_server_base->pana_key_update) { pana_key_update_t *pku = pana_server_base->pana_key_update; *ptr++ = 1; *ptr++ = pku->key_id; ptr = common_write_16_bit(pku->key_delivery_cnt, ptr); //73 memcpy(ptr, pku->new_key_material, 16); // 89 } else { *ptr = 0; //70 } } static void pana_server_material_read(const uint8_t *ptr) { pana_key_material_t *key_ptr; //Set Stored setup pana_server_base->pana_key_id = common_read_32_bit(ptr); ptr += 4; pana_server_base->session_lifetime = common_read_32_bit(ptr); ptr += 4; pana_server_base->key_wrap = common_read_32_bit(ptr); ptr += 4; pana_server_base->prf_algorythm = common_read_32_bit(ptr); ptr += 4; pana_server_base->integrity_algorythm = common_read_32_bit(ptr); ptr += 4; pana_server_base->next_session_id = common_read_32_bit(ptr); ptr += 4; pana_server_base->key_update_delay = common_read_32_bit(ptr); ptr += 4; pana_server_base->pana_key_update_delay_used = common_read_32_bit(ptr); ptr += 4; pana_server_base->supported_chipher_suites = *ptr++; pana_server_base->auth_cnt = *ptr++; pana_server_base->primary_material = *ptr++; key_ptr = &pana_server_base->sec_key_material[0]; key_ptr->key_id = *ptr++; memcpy(key_ptr->key_material, ptr, 16); tr_debug("KID0: %02x, %s", key_ptr->key_id, trace_array(ptr, 16)); ptr += 16; key_ptr = &pana_server_base->sec_key_material[1]; key_ptr->key_id = *ptr++; memcpy(key_ptr->key_material, ptr, 16); tr_debug("KID1: %02x, %s", key_ptr->key_id, trace_array(ptr, 16)); ptr += 16; uint8_t key_update = *ptr++; if (key_update) { pana_key_update_t *pku = ns_dyn_mem_temporary_alloc(sizeof(pana_key_update_t)); if (pku) { pku->key_id = *ptr++; pku->key_delivery_cnt = common_read_16_bit(ptr); ptr += 2; memcpy(pku->new_key_material, ptr, 16); pana_server_base->pana_key_update = pku; tr_debug("Key Update Process active"); } } } static int8_t pana_server_init(int8_t nwk_id, const uint8_t *network_key_material, uint8_t supported_chipher_suites, uint32_t key_update_delay) { if (!pana_socket_init(pana_server_packet_handler, pana_server_state_machine_func, tls_server_up)) { return -1; } int8_t ret_val = -1; sec_suite_list_clean(); //Allocate if (pana_server_base == 0) { pana_server_base = pana_server_staructure_allocate(); } else { if (pana_server_base->network_interface_id != nwk_id) { tr_debug("UnKnow id"); return -2; } } if (pana_server_base) { pana_server_base->primary_material = 0; pana_key_material_t *key_info = pana_server_key_get(false); key_info->key_id = 0; key_info = pana_server_key_get(true); key_info->key_id = 1; if (network_key_material) { memcpy(key_info->key_material, network_key_material, 16); } else { pana_server_set_random_key_value(key_info->key_material); } pana_server_base->auth_cnt = 0; pana_server_base->pana_key_id = 1; pana_server_base->session_lifetime = 0xffffffff; pana_server_base->key_wrap = 1; pana_server_base->prf_algorythm = 5; pana_server_base->integrity_algorythm = 0x0c; pana_server_base->next_session_id = 1; pana_server_base->key_update_delay = 0; pana_server_base->supported_chipher_suites = supported_chipher_suites; pana_server_base->pana_key_update = 0; pana_server_base->open_pana_authentication_cnt = 0; pana_server_base->network_interface_id = nwk_id; pana_server_base->pana_key_update_delay_used = key_update_delay; if (pana_nvm_storage_cb) { pana_server_material_write(pana_nvm_buffer); pana_nvm_storage_cb(PANA_SERVER_MATERIAL_UPDATE); } ret_val = 0; } return ret_val; } void pana_key_update_delivery_ready(void) { if (pana_server_base && pana_server_base->pana_key_update) { if (pana_server_base->pana_key_update->key_delivery_cnt-- == 1) { if (pana_key_update_process_ready) { pana_server_base->key_update_delay = 1; } else { pana_server_base->key_update_delay = pana_server_base->pana_key_update_delay_used; if (pana_server_base->key_update_delay == 0) { tr_debug("Delivery Ready"); pana_server_base->key_update_delay = 1; } } //NVM UPDAte for timer and key material } if (pana_nvm_storage_cb) { pana_server_material_write(pana_nvm_buffer); pana_nvm_storage_cb(PANA_SERVER_MATERIAL_UPDATE); } } } /* Save and load stored settings to Pana server core */ static void pana_server_client_save_to_nvm(sec_suite_t *suite, pana_nvm_update_process_t nvm_event) { uint8_t *ptr = pana_nvm_buffer; pana_session_t *p_session = &suite->pana_session; /* static Part of every session */ ptr = common_write_16_bit(p_session->nvm_offset, ptr); memcpy(ptr, suite->session_address, 16); ptr += 16; ptr = common_write_16_bit(suite->session_port, ptr); ptr = common_write_32_bit(p_session->session_id, ptr); if (nvm_event == PANA_SERVER_CLIENT_SESSION_REMOVE_UPDATE) { tr_debug("Remove From NVM"); } else { /* First Encrypted sector start */ *ptr++ = suite->state; ptr = common_write_32_bit(suite->timer, ptr); uint8_t state = 0; if (p_session->key_warp) { state |= PANA_ST_KEY_WRAP; } if (p_session->session_ready) { state |= PANA_ST_READY; } *ptr++ = state; //6 ptr = common_write_32_bit(p_session->req_seq, ptr); ptr = common_write_32_bit(p_session->res_seq, ptr); *ptr++ = p_session->address_status; memcpy(ptr, p_session->session_relay_address, 16); ptr += 16; ptr = common_write_16_bit(p_session->relay_port, ptr); //37 bytes sector *ptr++ = p_session->auth_cnt; *ptr++ = p_session->nwk_key_id; memcpy(ptr, p_session->pana_auth_key, 32); ptr += 32; memcpy(ptr, p_session->pana_PAA_enc_key, 16); ptr += 16; ptr = common_write_32_bit(p_session->pana_key_id, ptr); ptr = common_write_32_bit(p_session->session_lifetime, ptr); *ptr++ = p_session->eap_id_seq; } } static void pana_server_client_restore_from_nvm(sec_suite_t *suite, const uint8_t *ptr) { pana_session_t *p_session = &suite->pana_session; p_session->nvm_offset = common_read_16_bit(ptr); ptr += 2; memcpy(suite->session_address, ptr, 16); ptr += 16; suite->session_port = common_read_16_bit(ptr); ptr += 2; p_session->session_id = common_read_32_bit(ptr); ptr += 4; //24 suite->state = (sec_state_machine_t) * ptr++; suite->timer = common_read_32_bit(ptr); ptr += 4; uint8_t state = *ptr++; p_session->user_server = true; if (state & PANA_ST_KEY_WRAP) { p_session->key_warp = true; } else { p_session->key_warp = false; } if (state & PANA_ST_READY) { p_session->session_ready = true; } else { p_session->session_ready = false; } p_session->req_seq = common_read_32_bit(ptr); ptr += 4; p_session->res_seq = common_read_32_bit(ptr); ptr += 4; p_session->address_status = *ptr++; memcpy(p_session->session_relay_address, ptr, 16); ptr += 16; p_session->relay_port = common_read_16_bit(ptr); ptr += 2; p_session->auth_cnt = *ptr++; p_session->nwk_key_id = *ptr++; memcpy(p_session->pana_auth_key, ptr, 32); ptr += 32; memcpy(p_session->pana_PAA_enc_key, ptr, 16); ptr += 16; p_session->pana_key_id = common_read_32_bit(ptr); ptr += 4; p_session->session_lifetime = common_read_32_bit(ptr); ptr += 4; p_session->eap_id_seq = *ptr++; } void pana_session_nvm_udate(sec_suite_t *suite, pana_nvm_update_process_t update_event) { if (pana_nvm_storage_cb) { if (pana_server_base) { pana_server_client_save_to_nvm(suite, update_event); suite->pana_session.nvm_offset = pana_nvm_storage_cb(update_event); } } } static void pana_client_session_init(sec_suite_t *suite) { suite->pana_session.session_ready = false; suite->pana_session.key_warp = true; suite->pana_session.user_server = true; suite->pana_session.session_id = pana_server_base->next_session_id; // Take Random Number pana_server_base->next_session_id++; suite->pana_session.req_seq = randLIB_get_32bit(); suite->pana_session.res_seq = 0; suite->pana_session.eap_id_seq = randLIB_get_8bit(); suite->pana_session.eap_id_seq &= 63; suite->pana_session.eap_id_seq++; suite->pana_session.prf_algorythm = pana_server_base->prf_algorythm; suite->pana_session.integrity_algorythm = pana_server_base->integrity_algorythm; suite->pana_session.key_wrap = pana_server_base->key_wrap; //init eap fragmentation suite->pana_session.pana_key_id = pana_server_base->pana_key_id; suite->pana_session.session_lifetime = pana_server_base->session_lifetime; suite->supported_chipher_suites = pana_server_base->supported_chipher_suites; //suite->setups &= ~TLS_HANSHAKE_HASH; suite->setups = TLS_SERVER_MODE; suite->timer = 1; suite->state = PANA_REQUEST_TX; suite->retry_counter = 0; eap_fragmentation_init(suite); suite->pana_session.pana_heap->handshake_len = 0; suite->pana_session.pana_heap->handshake_req_offset = 0; randLIB_get_n_bytes_random(suite->pana_session.pana_heap->agent_nonce, 16); if (pana_nvm_storage_cb) { pana_server_material_write(pana_nvm_buffer); pana_nvm_storage_cb(PANA_SERVER_MATERIAL_UPDATE); } } static bool pana_auth_msg_validate(uint8_t *ptr, uint16_t length, uint8_t *key) { pana_avp_t authency; authency.code = AVP_AUTHENCY_CODE; if (!pana_avp_discover(ptr, length, &authency)) { return false; } if (!pana_auth_check(ptr, length, authency.avp_ptr, key)) { tr_debug("Auth Fail"); return false; } return true; } static void pana_server_set_key_material(uint8_t *key_material, bool new_key, uint8_t auth_cnt) { if (new_key) { memcpy(key_material, pana_server_base->pana_key_update->new_key_material, 16); key_material += 16; *key_material++ = pana_server_base->pana_key_update->key_id; } else { pana_key_material_t *primary_key = pana_server_key_get(true); memcpy(key_material, primary_key->key_material, 16); key_material += 16; *key_material++ = primary_key->key_id; } *key_material = auth_cnt; } static void pana_pna_response_build(buffer_t *buf, uint8_t operation, pana_header_t *header, sec_suite_t *suite) { uint8_t *ptr; header->type = PANA_MSG_PNA; header->flags &= ~PANA_FLAGS_REQUEST; buf->buf_ptr = PANA_HEADER_LENGTH; ptr = buffer_data_pointer(buf); if (operation == 4) { //Leave emtpy } else { uint8_t key_material[18]; if (operation == 3) { pana_server_set_key_material(key_material, true, suite->pana_session.auth_cnt); } else { pana_server_set_key_material(key_material, false, suite->pana_session.auth_cnt); } ptr = pana_avp_zip_key_material(ptr, key_material, header->seq, suite); } ptr = pana_avp_write_n_bytes(AVP_AUTHENCY_CODE, 16, NULL, ptr); buffer_data_end_set(buf, ptr); buf = build_pana_base(buf, header, suite); if (!buf) { return; } pana_auth_hash_calc(buffer_data_pointer(buf), buffer_data_length(buf), suite->pana_session.pana_auth_key); //Encode Pana Auth if (buf->src_sa.address[0] == 0xfe) { pana_set_agend_address(buf, false, suite); } else { //Check IF need Relay pana_set_agend_address(buf, true, suite); } if (suite->pana_session.address_status & 1) { 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); } static void pana_complete_msg_parse(buffer_t *buf, pana_header_t *header, sec_suite_t *suite) { uint16_t length = buffer_data_length(buf); uint8_t *ptr = buffer_data_pointer(buf); if (sec_check_suite_ptrs(suite) == 0) { buffer_free(buf); return; } if (header->flags & PANA_FLAGS_REQUEST) { buffer_free(buf); return; } uint32_t key_id = 0xffffffff; bool key_id_parsed = false; pana_avp_t avp_temp; //Read Key id if they are coming avp_temp.code = AVP_KEY_ID_CODE; if (pana_avp_discover(ptr, length, &avp_temp) && avp_temp.len == 4) { key_id = common_read_32_bit(avp_temp.avp_ptr); key_id_parsed = true; } if (key_id_parsed) { if (!pana_auth_msg_validate(ptr, length, suite->pana_session.pana_auth_key)) { goto pana_failure; } if (suite->pana_session.pana_key_id != key_id) { goto pana_failure; } tr_debug("Client AUTH_OK"); sec_lib_state_machine_trig(suite, PANA_READY); if (pana_server_base) { if (pana_server_base->open_pana_authentication_cnt) { pana_server_base->open_pana_authentication_cnt--; } } } else { sec_lib_state_machine_trig(suite, PANA_ERROR); } buffer_free(buf); return; pana_failure: tr_debug("Drop Key MSG"); sec_lib_state_machine_trig(suite, PANA_FAILURE); //shuold be calc buffer_free(buf); return; } static void pana_server_finnish_error_build(buffer_t *buf, sec_suite_t *suite) { buf->buf_ptr = PANA_HEADER_LENGTH; uint8_t *ptr = buffer_data_pointer(buf); //tr_debug("End Pana and EAP"); uint8_t eap_status[4]; eap_header_build(eap_status, 4, EAP_FAILURE, suite->pana_session.eap_id_seq, 0); ptr = pana_avp_32_bit_write(AVP_RESULT_CODE, 2, ptr); ptr = pana_avp_write_n_bytes(AVP_EAP_PAYLOAD_CODE, 4, eap_status, ptr); buffer_data_end_set(buf, ptr); } static void sec_auth_ready(sec_suite_t *suite) { suite->timer = 0; tr_debug("Pana:OK"); suite->pana_session.session_ready = true; if (suite->state == PANA_READY) { pana_session_nvm_udate(suite, PANA_SERVER_CLIENT_SESSION_UPDATE); } //Reset pointer suite->pana_session.auth_info = NULL; pana_free_dynamic_ram(suite); sec_suite_tls_free(suite, true); } #ifdef ECC static uint32_t tls_backoff_random_timer_start(void) { return randLIB_get_random_in_range(2, 16); } #endif static void pana_server_pana_error_handler(sec_suite_t *suite) { sec_lib_state_machine_lock(suite, PANA_ERROR); pana_client_authentication_fail(suite); seclib_session_clean(suite); } static void pana_server_state_machine_func(sec_suite_t *suite) { if (!suite) { return; } uint8_t general_tx = 0; switch (suite->state) { case PANA_ERROR: pana_server_pana_error_handler(suite); return; case PANA_READY: case PANA_RE_VALID: case PANA_PULL_DONE: sec_auth_ready(suite); break; case PRF_CALC: case PRF_CALC2: case TLS_ECC_CERTIFICATE_VERIFY_SIGNATURE: case TLS_ECC_MESSAGE_VERIFY: case TLS_ECC_CERTIFICATE_SIGNATURE_CHECK: case TLS_ECC_GENERATE_PUBLIC_KEY: case TLS_ECC_GENERATE_PREMASTER_SECRET: case TLS_ECC_SIGNATURE_MESSAGE: break; case TLS_HELLO_RX: case TLS_SERVER_KEY_EXCHANGE_RX: case TLS_SERVER_WAIT_CHANGE_CHIPHERSUITE: case TLS_CLIENT_KEY_EXCHANGE_RX: case TLS_CHANGE_CHIPHER: tr_debug("%02x", suite->state); tr_debug("Timeout"); sec_lib_state_machine_trig(suite, TLS_ALERT_INTERNAL); general_tx = 1; break; #ifdef ECC case TLS_ECC_GENERATE_PUBLIC_KEY_START: sec_ecc_gen_public_key_start(suite); break; case TLS_ECC_MESSAGE_SERVER_VERIFY_START: case TLS_ECC_MESSAGE_VERIFY_START: if (suite->tls_session) { if (suite->tls_session->tls_heap) { int start = 0; tls_heap_t *theap = suite->tls_session->tls_heap; if (theap->cert_temp_buf) { if (suite->state == TLS_ECC_MESSAGE_SERVER_VERIFY_START) { if (theap->signature_temp_buf == 0) { start = 1; } } } else { start = 1; } if (start) { tls_server_finnish_handle_start(suite); } else { tr_debug("Start Certi Check"); tls_certificate_signature_verify(suite); } } } break; case TLS_ECC_MESSAGE_VERIFY_START2: tls_ecc_verfify_start(suite); break; case TLS_SERVER_ECC_PUB_KEY_GEN: if (sec_auth_re_check(suite)) { if (tls_server_certi_hash_copy(suite) == 0) { suite->timer = tls_backoff_random_timer_start(); } else { suite->setups &= ~TLS_HANSHAKE_HASH; //PUBLIC key cal sec_lib_state_machine_trig(suite, TLS_ECC_GENERATE_PUBLIC_KEY_START); } } else { tr_debug("TLS_SERVER_ECC_PUB_KEY_GEN timeout"); sec_lib_state_machine_trig(suite, TLS_ALERT_INTERNAL); general_tx = 1; //Alert Shuold send Here } break; case TLS_ECC_CLIENT_SIGNATURE_START: sec_ecc_client_signature_start(suite); break; #endif case TLS_UPDATE_HAS_WITH_CERTIFICATE: #ifdef ECC if (sec_auth_re_check(suite)) { if (tls_certi_hash_copy(suite) == 0) { tr_warn("Server Certficate Alloc fail"); suite->timer = 4; } else { sec_lib_state_machine_trig(suite, TLS_ECC_CLIENT_SIGNATURE_START); } } else #endif { sec_lib_state_machine_trig(suite, TLS_ALERT_INTERNAL); general_tx = 1; } break; case TLS_TX_SERVER_KEY_EXCHANGE: #ifdef ECC if (sec_auth_re_check(suite)) { bool tx_start_OK = false; if (suite->pana_session.assy_length || suite->pana_session.frag_length || suite->pana_session.packet_delivered) { //Build next EAP Packet //tr_debug("TX same again fragment piece"); tx_start_OK = pana_eap_frag_re_tx(suite); } else { if (tls_pana_server_exchange_build(suite)) { suite->pana_session.packet_delivered = false; tx_start_OK = true; } } if (tx_start_OK) { pana_timeout_timer_set(suite, suite->state); } else { suite->timer = tls_backoff_random_timer_start(); } } else #endif { if (suite->pana_session.assy_length) { buffer_free(suite->pana_session.eap_assy_buf); suite->pana_session.eap_assy_buf = 0; suite->pana_session.assy_length = 0; suite->pana_session.assy_off_set = 0; } tr_debug("TLS_TX_SERVER_KEY_EXCHANGE timeout"); sec_lib_state_machine_trig(suite, TLS_ALERT_INTERNAL); general_tx = 1; } break; default: general_tx = 1; break; } if (general_tx) { if (sec_auth_re_check(suite)) { buffer_t *buf = buffer_get(140); if (buf) { buf->interface = suite->interface; suite->timer = 600; switch (suite->state) { case PANA_REQUEST_TX: pana_start_message_build(buf, suite); break; case EAP_IDENTITY_REQ: pana_eap_identity_build(buf, suite); break; case TLS_START: pana_eap_tls_start_build(buf, suite); break; case TLS_SERVER_TX_SERVER_HELLO: tls_server_hello_build(buf, suite); pana_eap_down(buf, suite); break; case TLS_KEY_CHANGE: //Print Handshake message tls_prepare_change_chipher_spec(suite); tls_build_client_change_chipher_suite_finnish(buf, suite); tls_nonce_update(suite->tls_session->tls_nonce_explit); tr_debug("Set Keys"); pana_eap_down(buf, suite); break; case TLS_EAP_END_PANA_VERIFY: pana_success_server_build(buf, suite); break; case PANA_KEY_UPDATE: pana_server_build_key_push(buf, suite); break; case PANA_FAILURE: pana_server_finnish_error_build(buf, suite); pana_down(buf, suite); break; case TLS_FINISH: case TLS_ALERT: eap_fragmentation_init(suite); pana_eap_tls_finnish_build(buf, suite); break; case TLS_ALERT_CLOSE_FATAL: case TLS_ALERT_INTERNAL: case TLS_ALERT_CHIPHER_SUITE: case TLS_ALERT_DECRYPT: case TLS_ALERT_BAD_CERTIFICATE: eap_fragmentation_init(suite); suite->setups &= ~(TLS_ECC_CERTIFICATE_REQUESTED | TLS_ECC_CERTIFICATE_RECEIVED | TLS_ECC_CERTIFICATE_VERIFY); #ifdef ECC { tls_heap_t *tls_heap = suite->tls_session->tls_heap; if (tls_heap) { tls_ecc_heap_free(tls_heap); } } #endif if (suite->state == TLS_ALERT_DECRYPT) { tls_alert_build(buf, ALERT_BAD_RECORD); } else if (suite->state == TLS_ALERT_CLOSE_FATAL) { tls_alert_build(buf, ALERT_INTERNAL_ERR); } else if (suite->state == TLS_ALERT_BAD_CERTIFICATE) { tls_alert_build(buf, ALERT_BAD_CERTIFICATE); } else { tls_alert_build(buf, ALERT_INTERNAL_ERR); } pana_eap_down(buf, suite); break; default: tr_debug("Unknown Packet. State: %x", suite->state); buf = buffer_free(buf); break; } } else { suite->timer = 2; } } else { tr_debug("Tls Auth Re TX limit Reached. State: %x", suite->state); switch (suite->state) { case TLS_SERVER_TX_SERVER_HELLO: case TLS_KEY_CHANGE: sec_lib_state_machine_trig(suite, TLS_ALERT_INTERNAL); break; default: if (suite->state == PANA_KEY_UPDATE) { tr_warn("Key Delivery Fail"); pana_key_update_delivery_ready(); } pana_server_pana_error_handler(suite); break; } } } } static void pana_server_tls_session_init(sec_suite_t *suite) { //Generate TLS SESSION tls_session_id_genrate(suite->tls_session->tls_session_id, 4); suite->tls_session->id_length = 4; memset(suite->tls_session->tls_nonce_explit, 0, 8); } static void pana_server_session_address_set_for_relay(sec_suite_t *suite, buffer_t *buf) { memcpy(suite->session_address, buf->dst_sa.address, 16); suite->session_port = buf->dst_sa.port; suite->pana_session.address_status = 1; //Copy Relay Address memcpy(suite->pana_session.session_relay_address, buf->src_sa.address, 16); suite->pana_session.relay_port = buf->src_sa.port; memcpy(&(buf->src_sa), &(buf->dst_sa), sizeof(sockaddr_t)); } static sec_suite_t *pana_server_session_restore(uint8_t *nvm_data, protocol_interface_info_entry_t *interface) { sec_suite_t *suite = sec_lib_security_session_allocate(false); if (!suite) { return NULL; } //Restore pana_server_client_restore_from_nvm(suite, nvm_data); //Init Satic Information At ZIP suite->setups = TLS_SERVER_MODE; suite->interface = interface; suite->pana_session.key_wrap = pana_server_base->key_wrap; suite->pana_session.prf_algorythm = pana_server_base->prf_algorythm; suite->pana_session.integrity_algorythm = pana_server_base->integrity_algorythm; return suite; } static sec_suite_t *pana_server_get_session_by_session_id(uint32_t session_id, protocol_interface_info_entry_t *interface) { sec_suite_t *suite = sec_suite_selected_pana_session(session_id); if (!suite && pana_server_nvm__session_get) { if (!pana_server_nvm__session_get(session_id)) { return NULL; } suite = pana_server_session_restore(pana_nvm_buffer, interface); } return suite; } static sec_suite_t *pana_server_get_session_by_address(uint8_t *ll_address, protocol_interface_info_entry_t *interface) { sec_suite_t *suite = sec_suite_selected_address(ll_address); if (!suite && pana_server_nvm_get) { if (!pana_server_nvm_get(ll_address)) { return NULL; } suite = pana_server_session_restore(pana_nvm_buffer, interface); } return suite; } static void pana_server_packet_handler(buffer_t *buf) { bool relay_pack = false; sec_suite_t *suite = NULL; pana_header_t header; if (!pana_header_parse(buffer_data_pointer(buf), buffer_data_length(buf), &header)) { buffer_free(buf); return; } buffer_data_strip_header(buf, PANA_HEADER_LENGTH); if (header.type == PANA_MSG_RELAY) { /** Parse Relay */ buf = pana_relay_parse(buf); if (buf) { /** Parse Relayed Packet */ if (!pana_header_parse(buffer_data_pointer(buf), buffer_data_length(buf), &header)) { buffer_free(buf); return; } buffer_data_strip_header(buf, PANA_HEADER_LENGTH); relay_pack = true; } if (buf == 0) { tr_debug("Drop Pana Relay Pack"); return; } } //Server will use address and session when address is LL and GP use only ID //SERVER: if type is relay parse relay address and save if (header.type == PANA_MSG_PNA) { //tr_debug("PNA"); suite = pana_server_get_session_by_session_id(header.session_id, buf->interface); if (!suite || !(header.flags & PANA_FLAGS_PING)) { buffer_free(buf); return; } if (!pana_auth_msg_validate(buffer_data_pointer(buf), buffer_data_length(buf), suite->pana_session.pana_auth_key)) { buffer_free(buf); return; } if ((header.flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { if (suite->pana_session.req_seq != header.seq) { tr_debug("PNA RES:Drop Old seq"); buffer_free(buf); return; } suite->pana_session.req_seq++; if (suite->pana_session.session_ready) { tr_debug("Key push OK"); if (suite->state == PANA_KEY_UPDATE) { sec_lib_state_machine_lock(suite, PANA_READY); tr_debug("Key Delivery OK"); //Call SEC KEY UPDATE //tr_debug("NVM SEQ Update by Key Pull Ready"); pana_session_nvm_udate(suite, PANA_SERVER_CLIENT_SESSION_UPDATE); pana_key_update_delivery_ready(); } } buffer_free(buf); return; } else { if (suite->pana_session.res_seq == 0) { suite->pana_session.res_seq = header.seq; } else { if ((suite->pana_session.res_seq + 1) == header.seq) { suite->pana_session.res_seq = header.seq; } else if (suite->pana_session.res_seq != header.seq) { tr_debug("PNA REQ:Drop unknow Request"); buffer_free(buf); return; } } } if (relay_pack) { pana_server_session_address_set_for_relay(suite, buf); } else { if ((buf->src_sa.address[0] != 0xfe)) { //tr_debug("SET GP & SEQ"); suite->pana_session.address_status = 0; memcpy(suite->pana_session.session_relay_address, buf->src_sa.address, 16); suite->pana_session.relay_port = buf->src_sa.port; suite->session_port = buf->src_sa.port; } else { if (memcmp(suite->session_address, buf->src_sa.address, 16) != 0) { tr_debug("PNA REQ:Drop By Address"); buffer_free(buf); return; } //Shuold Update Relay Information suite->pana_session.address_status = 2; suite->session_port = buf->src_sa.port; lowpan_neighbour_data_clean(suite->interface->id, buf->src_sa.address); } } if (!suite->pana_session.session_ready) { buffer_free(buf); return; } //KEY PULL pana_avp_t avp_temp; //Read Resul and Key id if they are coming avp_temp.code = PANA_EAP_KEYREQ_TYPE; avp_temp.len = 0; uint8_t key_delivery; if (!pana_avp_discover(buffer_data_pointer(buf), buffer_data_length(buf), &avp_temp)) { key_delivery = 2; avp_temp.avp_ptr = NULL; } else { if (avp_temp.len != 2) { buffer_free(buf); return; } uint8_t *ptr = avp_temp.avp_ptr; pana_key_material_t *primary_key = pana_server_key_get(true); tr_debug("Network KEY Request: %s", trace_array(ptr, 2)); if (*ptr++ & 1) { tr_debug("REQ bit, 1"); //if(*ptr == pana_server_base->network_key_id) if (*ptr == primary_key->key_id) { if (pana_server_base->pana_key_update) { key_delivery = 3; } else { key_delivery = 4; } } else { key_delivery = 2; } } else { //if(*ptr == pana_server_base->network_key_id) if (*ptr == primary_key->key_id) { key_delivery = 2; } else { key_delivery = 4; } } } tr_debug("NVM SEQ update BY Client key Pull"); pana_pna_response_build(buf, key_delivery, &header, suite); pana_session_nvm_udate(suite, PANA_SERVER_CLIENT_SESSION_UPDATE); return; } else if (header.type == PANA_MSG_PCI) { if (relay_pack) { suite = pana_server_get_session_by_address(buf->dst_sa.address, buf->interface); } else { suite = pana_server_get_session_by_address(buf->src_sa.address, buf->interface); } if (suite) { //Check State //if state ready create new session if (!suite->pana_session.session_ready) { tr_debug("PCI received; Discard unfinished session and start a new one"); if (pana_server_base->open_pana_authentication_cnt) { pana_server_base->open_pana_authentication_cnt--; } sec_suite_remove(suite); suite = 0; } else { tr_debug("Accept new session"); } } if (suite) { if (suite->pana_session.pana_heap == NULL) { suite->pana_session.pana_heap = pana_heap_structure_allocate(); } if (suite->tls_session == NULL) { suite->tls_session = amr_tls_session_allocate(); if (suite->tls_session == NULL) { if (suite->pana_session.pana_heap) { ns_dyn_mem_free(suite->pana_session.pana_heap); suite->pana_session.pana_heap = NULL; } } } if (suite->pana_session.pana_heap) { arm_tls_session_clear(suite->tls_session); suite->tls_session->tls_heap = tls_heap_allocate(); if (suite->tls_session->tls_heap) { //Generate TLS SESSION pana_server_tls_session_init(suite); pana_client_session_init(suite); tr_debug("UPdate Auth Counter"); if (relay_pack) { pana_server_session_address_set_for_relay(suite, buf); } else { suite->pana_session.address_status = 2; memcpy(suite->session_address, buf->src_sa.address, 16); suite->session_port = buf->src_sa.port; } pana_server_base->open_pana_authentication_cnt++; } else { tr_debug("TLS heap allocate"); } } } else { //Generate session suite = sec_suite_create(); if (suite) { tr_debug("Create new Pana Session"); pana_server_tls_session_init(suite); pana_server_base->open_pana_authentication_cnt++; pana_client_session_init(suite); suite->interface = buf->interface; if (relay_pack) { pana_server_session_address_set_for_relay(suite, buf); } else { suite->pana_session.address_status = 2; memcpy(suite->session_address, buf->src_sa.address, 16); suite->session_port = buf->src_sa.port; } } } buffer_free(buf); return; } else if (header.type == PANA_MSG_PA) { if (buf->src_sa.address[0] == 0xfe || relay_pack) { //accept only now session suite = sec_suite_selected_pana_session(header.session_id); if (!suite) { tr_debug("Drop Packet by session ID"); buffer_free(buf); return; } if ((header.flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { if (suite->pana_session.req_seq == header.seq) { suite->pana_session.req_seq++; //ADD Check for EAP fragmentation!!!!!!!!!!!!!!! if ((header.flags & PANA_FLAGS_COMPLETE) == PANA_FLAGS_COMPLETE) { if (suite->state != TLS_EAP_END_PANA_VERIFY && suite->state != PANA_READY) { if (pana_server_base->open_pana_authentication_cnt) { pana_server_base->open_pana_authentication_cnt--; } tr_debug("Remove Current session by 'Comp bit'"); sec_suite_remove(suite); buffer_free(buf); return; } } } else { tr_debug("Pana RES:Drop Old seq"); buffer_free(buf); return; } } else { suite->pana_session.res_seq = header.seq; } if (relay_pack) { buf->src_sa = buf->dst_sa; } if (header.flags & PANA_FLAGS_START) { pana_session_startms_parse(buf, &header, suite); } else if (header.flags & PANA_FLAGS_COMPLETE) { pana_complete_msg_parse(buf, &header, suite); } else { buf = pana_auth_message_handler(buf, &header, suite); if (buf) { pana_eap_tls_up(buf, suite); } } return; } buffer_free(buf); } else { buffer_free(buf); } } int8_t pana_server_interface_init(int8_t interface_id, net_tls_cipher_e cipher_mode, const uint8_t *key_material, uint32_t time_period_before_activate_key) { int8_t ret_val; uint8_t supported_chipher_suites; protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!cur->if_lowpan_security_params) { return -1; } if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { return -4; } else if (cur->if_lowpan_security_params->pana_params == 0) { return -3; } else if (cur->if_lowpan_security_params->nwk_security_mode != NET_SEC_MODE_PANA_LINK_SECURITY) { return -5; } switch (cipher_mode) { case NET_TLS_PSK_CIPHER: /**< Network Authentication support only PSK */ supported_chipher_suites = SEC_CIPHERSUITE_PSK; break; case NET_TLS_ECC_CIPHER: /**< Network Authentication support only ECC */ case NET_TLS_PSK_AND_ECC_CIPHER: /**< Network Authentication support PSK & ECC */ #ifdef ECC //Verify Certficate if (sec_cetificate_chain_get(SEC_NWK_AUTHENTICATION_CERTI_CHAIN) == NULL) { return -1; } if (cipher_mode == NET_TLS_PSK_AND_ECC_CIPHER) { supported_chipher_suites = (SEC_CIPHERSUITE_PSK | SEC_CIPHERSUITE_ECC); } else { supported_chipher_suites = SEC_CIPHERSUITE_ECC; } break; #endif // if ECC is not supported, flow into default => nothing is supported. default: supported_chipher_suites = 0; break; } ret_val = pana_server_init(interface_id, key_material, supported_chipher_suites, time_period_before_activate_key); if (ret_val == 0) { cur->if_lowpan_security_params->pana_params->nwk_chipher_mode = cipher_mode; cur->if_lowpan_security_params->pana_params->psk_key_id = 0; cur->if_lowpan_security_params->pana_params->pana_client = 0; cur->lowpan_info |= (INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION); cur->configure_flags |= INTERFACE_SECURITY_DEFINED; } return ret_val; } int8_t pana_server_key_update(int8_t interface_id, const uint8_t *network_key_material) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!pana_server_base || pana_server_base->network_interface_id != interface_id || pana_server_base->pana_key_update) { return -2; } if (!cur->if_lowpan_security_params || !cur->if_lowpan_security_params->pana_params) { return -3; } if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) == 0) { return -4; } else if (cur->if_lowpan_security_params->nwk_security_mode != NET_SEC_MODE_PANA_LINK_SECURITY) { return -5; } pana_server_base->pana_key_update = ns_dyn_mem_temporary_alloc(sizeof(pana_key_update_t)); if (!pana_server_base->pana_key_update) { return -3; } pana_key_material_t *primary_key = pana_server_key_get(true); if (network_key_material) { memcpy(pana_server_base->pana_key_update->new_key_material, network_key_material, 16); } else { pana_server_set_random_key_value(pana_server_base->pana_key_update->new_key_material); network_key_material = pana_server_base->pana_key_update->new_key_material; } pana_lib_parameters_s *parameters = pana_parameters_get(); /* Update Key ID */ pana_server_base->pana_key_update->key_id = primary_key->key_id; if (pana_server_base->pana_key_update->key_id == parameters->KEY_ID_MAX_VALUE) { /* Start Lollipop Sechema from 1 again */ pana_server_base->pana_key_update->key_id = 0; } pana_server_base->pana_key_update->key_id++; //Set New Key to secondary key primary_key = pana_server_key_get(false); primary_key->key_id = pana_server_base->pana_key_update->key_id; memcpy(primary_key->key_material, pana_server_base->pana_key_update->new_key_material, 16); //TRIG Timers pana_server_base->pana_key_update->key_delivery_cnt = sec_pana_key_update_trig(parameters->KEY_UPDATE_THRESHOLD); uint8_t *key_ptr = pana_key_get(network_key_material); if (key_ptr) { //pana_server_base->auth_cnt++; tr_debug("SET Secondary Key ready"); mac_helper_security_next_key_set(cur, (key_ptr + 16), pana_server_base->pana_key_update->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, pana_server_base->pana_key_update->key_id, false); } tr_debug("KEY Delivery CNT: %02x", pana_server_base->pana_key_update->key_delivery_cnt); if (pana_server_base->pana_key_update->key_delivery_cnt == 0) { tr_debug("TRIG NEW Key"); pana_server_base->pana_key_update->key_delivery_cnt = 1; pana_key_update_delivery_ready(); } if (pana_nvm_storage_cb) { pana_server_material_write(pana_nvm_buffer); pana_nvm_storage_cb(PANA_SERVER_MATERIAL_UPDATE); } return 0; } void pana_key_update_delay_timer(void) { if (pana_server_base && pana_server_base->key_update_delay) { if (pana_server_base->key_update_delay <= 100) { protocol_interface_info_entry_t *cur; pana_server_base->key_update_delay = 0; cur = protocol_stack_interface_info_get_by_id(pana_server_base->network_interface_id); //SWAP new KEY if (cur) { tr_debug("Trig New Key ID"); uint8_t keyId = mle_service_security_next_key_id_get(cur->id); mac_helper_security_key_swap_next_to_default(cur); mle_service_security_key_trig(cur->id, keyId); if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } if (pana_key_update_process_ready) { pana_key_update_process_ready(); } } if (pana_server_base->primary_material) { pana_server_base->primary_material = 0; } else { pana_server_base->primary_material = 1; } pana_key_material_t *primary_key = pana_server_key_get(true); primary_key->key_id = pana_server_base->pana_key_update->key_id; memcpy(primary_key->key_material, pana_server_base->pana_key_update->new_key_material, 16); if (pana_server_base->pana_key_update) { ns_dyn_mem_free(pana_server_base->pana_key_update); pana_server_base->pana_key_update = 0; } if (pana_nvm_storage_cb) { tr_debug("PS:NVM Cover"); pana_server_material_write(pana_nvm_buffer); pana_nvm_storage_cb(PANA_SERVER_MATERIAL_UPDATE); } } else { pana_server_base->key_update_delay -= 100; } } } int8_t pana_server_nvm_callback_set(pana_server_update_cb *update_cb, pana_server_session_get_cb *nvm_get, pana_server_session_get_by_id_cb *nvm_session_get, uint8_t *nvm_static_buffer) { if (!update_cb || !nvm_static_buffer || !nvm_get || !nvm_session_get) { return -1; } pana_nvm_storage_cb = update_cb; pana_server_nvm_get = nvm_get; pana_server_nvm__session_get = nvm_session_get; pana_nvm_buffer = nvm_static_buffer; return 0; } int8_t pana_server_process_ready_cb_set(void (*cb_fptr)(void)) { if (cb_fptr) { pana_key_update_process_ready = cb_fptr; return 0; } return -1; } /* Pana Client session load from NVM API */ int8_t pana_server_nvm_client_session_load(uint8_t *nvm_pointer) { if (!pana_server_base) { return -1; } protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(pana_server_base->network_interface_id); if (!cur) { return -1; } if (pana_socket_id_get() == -1) { return -2; } if (pana_server_session_restore(nvm_pointer, cur)) { return -3; } return 0; } static void pana_success_server_build(buffer_t *buf, sec_suite_t *suite) { uint8_t *ptr; pana_header_t header; header.type = PANA_MSG_PA; header.flags = PANA_FLAGS_COMPLETE | PANA_FLAGS_REQUEST; //REQUEST header.seq = suite->pana_session.req_seq; header.session_id = suite->pana_session.session_id; buf->buf_ptr = PANA_HEADER_LENGTH; ptr = buffer_data_pointer(buf); uint8_t eap_status[4]; eap_header_build(eap_status, 4, EAP_SUCCESS, suite->pana_session.eap_id_seq, 0); ptr = pana_avp_32_bit_write(AVP_RESULT_CODE, 0, ptr); ptr = pana_avp_write_n_bytes(AVP_EAP_PAYLOAD_CODE, 4, eap_status, ptr); ptr = pana_avp_32_bit_write(AVP_KEY_ID_CODE, suite->pana_session.pana_key_id, ptr); ptr = pana_avp_32_bit_write(AVP_SESSION_LIFETIME_CODE, suite->pana_session.session_lifetime, ptr); //ENC uint8_t key_material[18]; pana_server_set_key_material(key_material, false, suite->pana_session.auth_cnt); ptr = pana_avp_zip_key_material(ptr, key_material, header.seq, suite); ptr = pana_avp_write_n_bytes(AVP_AUTHENCY_CODE, 16, NULL, ptr); buffer_data_end_set(buf, ptr); buf = build_pana_base(buf, &header, suite); if (!buf) { return; } pana_auth_hash_calc(buffer_data_pointer(buf), buffer_data_length(buf), suite->pana_session.pana_auth_key); //Encode Pana Auth pana_set_agend_address(buf, false, suite); if (suite->pana_session.address_status & 1) { 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); } static void pana_server_build_key_push(buffer_t *buf, sec_suite_t *suite) { uint8_t *ptr; pana_header_t header; header.type = PANA_MSG_PNA; header.flags = PANA_FLAGS_REQUEST | PANA_FLAGS_PING; //REQUEST header.seq = suite->pana_session.req_seq; header.session_id = suite->pana_session.session_id; buf->buf_ptr = PANA_HEADER_LENGTH; ptr = buffer_data_pointer(buf); //ENC uint8_t key_material[18]; pana_server_set_key_material(key_material, true, suite->pana_session.auth_cnt); ptr = pana_avp_zip_key_material(ptr, key_material, header.seq, suite); ptr = pana_avp_write_n_bytes(AVP_AUTHENCY_CODE, 16, NULL, ptr); buffer_data_end_set(buf, ptr); buf = build_pana_base(buf, &header, suite); if (!buf) { return; } pana_auth_hash_calc(buffer_data_pointer(buf), buffer_data_length(buf), suite->pana_session.pana_auth_key); pana_set_agend_address(buf, true, suite); protocol_push(buf); } int8_t pana_network_key_get(int8_t interface_id, ns_keys_t *key) { (void)interface_id; if (pana_server_base && key) { pana_key_material_t *primary_key = pana_server_key_get(true); pana_key_material_t *prev_key = pana_server_key_get(false); if (prev_key->key_id == 0) { prev_key = 0; } key->current_active_key_index = primary_key->key_id; memcpy(key->current_active_network_key, primary_key->key_material, 16); if (prev_key) { key->previous_active_key_index = prev_key->key_id; memcpy(key->previous_active_network_key, prev_key->key_material, 16); } else { memset(key->previous_active_network_key, 0, 16); } return 0; } return -1; } int8_t pana_server_trig_new_key(int8_t interface_id) { if (!pana_server_base) { return -1; } if (pana_server_base->network_interface_id != interface_id) { return -2; } if (pana_server_base->key_update_delay) { tr_debug("TRIG faster"); pana_server_base->key_update_delay = 1; return 0; } return -1; } int8_t pana_server_restore_from_nvm(uint8_t *nvm_data, int8_t interface_id) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!pana_socket_init(pana_server_packet_handler, pana_server_state_machine_func, tls_server_up)) { return -1; } sec_suite_list_clean(); //Allocate if (pana_server_base == 0) { pana_server_base = pana_server_staructure_allocate(); } if (!pana_server_base || !cur->if_lowpan_security_params || !cur->if_lowpan_security_params->pana_params) { return -1; } net_tls_cipher_e cipher_mode; pana_server_base->open_pana_authentication_cnt = 0; pana_server_base->network_interface_id = interface_id; pana_server_base->pana_key_update = 0; pana_server_base->key_update_delay = 0; pana_server_material_read(nvm_data); if (pana_server_base->supported_chipher_suites == SEC_CIPHERSUITE_PSK) { cipher_mode = NET_TLS_PSK_CIPHER; } else if (pana_server_base->supported_chipher_suites == SEC_CIPHERSUITE_ECC) { cipher_mode = NET_TLS_ECC_CIPHER; } else { cipher_mode = NET_TLS_PSK_AND_ECC_CIPHER; } cur->if_lowpan_security_params->pana_params->nwk_chipher_mode = cipher_mode; cur->if_lowpan_security_params->pana_params->psk_key_id = 0;//TODO????? cur->if_lowpan_security_params->pana_params->pana_client = 0; cur->lowpan_info |= (INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION); cur->configure_flags |= INTERFACE_SECURITY_DEFINED; return 0; } int8_t pana_server_key_material_load(int8_t interface_id) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } else if (!pana_server_base) { return -1; } uint8_t *key_ptr; pana_key_material_t *key_mat; if (pana_server_base->pana_key_update) { pana_server_base->auth_cnt++; //Load First Primary to master key_mat = pana_server_key_get(true); key_ptr = pana_key_get(key_mat->key_material); mac_helper_security_default_key_set(cur, (key_ptr + 16), key_mat->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, key_mat->key_id, true); if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } //Set Secondary to coming key key_mat = pana_server_key_get(false); key_ptr = pana_key_get(key_mat->key_material); mac_helper_security_next_key_set(cur, (key_ptr + 16), key_mat->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, key_mat->key_id, false); } else { bool secondary_active = false; //Load first Secondary and then Primary key_mat = pana_server_key_get(false); if (key_mat->key_id) { key_ptr = pana_key_get(key_mat->key_material); secondary_active = true; mac_helper_security_default_key_set(cur, (key_ptr + 16), key_mat->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, key_mat->key_id, true); if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } } key_mat = pana_server_key_get(true); key_ptr = pana_key_get(key_mat->key_material); if (secondary_active) { mac_helper_security_next_key_set(cur, (key_ptr + 16), key_mat->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, key_mat->key_id, false); mac_helper_security_key_swap_next_to_default(cur); mle_service_security_key_trig(cur->id, key_mat->key_id); } else { mac_helper_security_default_key_set(cur, (key_ptr + 16), key_mat->key_id, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_ptr, key_mat->key_id, true); } if (cur->nwk_wpan_nvm_api) { cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, true); } } return 0; } static void pana_client_authentication_fail(sec_suite_t *suite) { if (suite->pana_session.nvm_offset) { //tr_debug("NVM Session Remove"); pana_session_nvm_udate(suite, PANA_SERVER_CLIENT_SESSION_REMOVE_UPDATE); } if (pana_server_base && pana_server_base->open_pana_authentication_cnt) { pana_server_base->open_pana_authentication_cnt--; } } #else int8_t pana_server_nvm_callback_set(pana_server_update_cb *update_cb, pana_server_session_get_cb *nvm_get, pana_server_session_get_by_id_cb *nvm_session_get, uint8_t *nvm_static_buffer) { (void)update_cb; (void)nvm_get; (void)nvm_session_get; (void)nvm_static_buffer; return -1; } int8_t pana_server_nvm_client_session_load(uint8_t *nvm_pointer) { (void) nvm_pointer; return -1; } int8_t pana_server_restore_from_nvm(uint8_t *nvm_data, int8_t interface_id) { (void) nvm_data; (void)interface_id; return -1; } #endif #else int8_t pana_server_nvm_callback_set(pana_server_update_cb *update_cb, pana_server_session_get_cb *nvm_get, pana_server_session_get_by_id_cb *nvm_session_get, uint8_t *nvm_static_buffer) { (void)update_cb; (void)nvm_get; (void)nvm_session_get; (void)nvm_static_buffer; return -1; } int8_t pana_server_nvm_client_session_load(uint8_t *nvm_pointer) { (void) nvm_pointer; return -1; } int8_t pana_server_restore_from_nvm(uint8_t *nvm_data, int8_t interface_id) { (void) nvm_data; (void)interface_id; return -1; } #endif