Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers supp_gkh_sec_prot.c Source File

supp_gkh_sec_prot.c

00001 /*
00002  * Copyright (c) 2018-2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "nsconfig.h"
00019 #include <string.h>
00020 #include "ns_types.h"
00021 #include "ns_list.h"
00022 #include "ns_trace.h"
00023 #include "nsdynmemLIB.h"
00024 #include "fhss_config.h "
00025 #include "NWK_INTERFACE/Include/protocol.h"
00026 #include "6LoWPAN/ws/ws_config.h"
00027 #include "Security/kmp/kmp_addr.h"
00028 #include "Security/kmp/kmp_api.h"
00029 #include "Security/PANA/pana_eap_header.h"
00030 #include "Security/eapol/eapol_helper.h"
00031 #include "Security/protocols/sec_prot_certs.h"
00032 #include "Security/protocols/sec_prot_keys.h"
00033 #include "Security/protocols/sec_prot.h"
00034 #include "Security/protocols/sec_prot_lib.h"
00035 #include "Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h"
00036 
00037 #ifdef HAVE_WS
00038 
00039 #define TRACE_GROUP "sgkh"
00040 
00041 typedef enum {
00042     GKH_STATE_INIT = SEC_STATE_INIT,
00043     GKH_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
00044     GKH_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
00045     GKH_STATE_MESSAGE_1 = SEC_STATE_FIRST,
00046     GKH_STATE_FINISH = SEC_STATE_FINISH,
00047     GKH_STATE_FINISHED = SEC_STATE_FINISHED
00048 } gkh_sec_prot_state_e;
00049 
00050 typedef enum {
00051     GKH_MESSAGE_UNKNOWN = 0,
00052     GKH_MESSAGE_1,
00053     GKH_MESSAGE_2
00054 } gkh_sec_prot_msg_e;
00055 
00056 typedef struct {
00057     sec_prot_common_t             common;           /**< Common data */
00058     eapol_pdu_t                   recv_eapol_pdu;   /**< Received EAPOL PDU */
00059     void                          *recv_pdu;        /**< Received pdu */
00060     uint16_t                      recv_size;        /**< Received pdu size */
00061 } gkh_sec_prot_int_t;
00062 
00063 static uint16_t supp_gkh_sec_prot_size(void);
00064 static int8_t supp_gkh_sec_prot_init(sec_prot_t *prot);
00065 
00066 static void supp_gkh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
00067 static void supp_gkh_sec_prot_delete(sec_prot_t *prot);
00068 static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
00069 static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys);
00070 static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot);
00071 
00072 static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg);
00073 static void supp_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
00074 static int8_t supp_gkh_sec_prot_mic_validate(sec_prot_t *prot);
00075 static void supp_gkh_sec_prot_security_replay_counter_update(sec_prot_t *prot);
00076 static int8_t supp_gkh_kde_handle(sec_prot_t *prot);
00077 
00078 #define gkh_sec_prot_get(prot) (gkh_sec_prot_int_t *) &prot->data
00079 
00080 int8_t supp_gkh_sec_prot_register(kmp_service_t *service)
00081 {
00082     if (!service) {
00083         return -1;
00084     }
00085 
00086     if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH, supp_gkh_sec_prot_size, supp_gkh_sec_prot_init) < 0) {
00087         return -1;
00088     }
00089 
00090     return 0;
00091 }
00092 
00093 static uint16_t supp_gkh_sec_prot_size(void)
00094 {
00095     return sizeof(gkh_sec_prot_int_t);
00096 }
00097 
00098 static int8_t supp_gkh_sec_prot_init(sec_prot_t *prot)
00099 {
00100     prot->create_req = 0;
00101     prot->create_resp = supp_gkh_sec_prot_create_response;
00102     prot->receive = supp_gkh_sec_prot_receive;
00103     prot->delete = supp_gkh_sec_prot_delete;
00104     prot->state_machine = supp_gkh_sec_prot_state_machine;
00105     prot->timer_timeout = supp_gkh_sec_prot_timer_timeout;
00106 
00107     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00108     sec_prot_init(&data->common);
00109     sec_prot_state_set(prot, &data->common, GKH_STATE_INIT);
00110 
00111     return 0;
00112 }
00113 
00114 static void supp_gkh_sec_prot_delete(sec_prot_t *prot)
00115 {
00116     // No op at the moment
00117     (void) prot;
00118 }
00119 
00120 static void supp_gkh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
00121 {
00122     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00123 
00124     // Call state machine
00125     sec_prot_result_set(&data->common, result);
00126     prot->state_machine_call(prot);
00127 }
00128 
00129 static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
00130 {
00131     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00132     int8_t ret_val = -1;
00133 
00134     // Decoding is successful
00135     if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
00136         // Get message
00137         if (supp_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) {
00138             tr_info("GKH: recv Message 1");
00139 
00140             // Call state machine
00141             data->recv_pdu = pdu;
00142             data->recv_size = size;
00143             prot->state_machine(prot);
00144         } else {
00145             tr_error("GKH: recv error");
00146         }
00147         ret_val = 0;
00148     } else {
00149         tr_error("GKH: recv error");
00150     }
00151 
00152     memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
00153     data->recv_pdu = 0;
00154     data->recv_size = 0;
00155 
00156     return ret_val;
00157 }
00158 
00159 static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys)
00160 {
00161     gkh_sec_prot_msg_e msg = GKH_MESSAGE_UNKNOWN;
00162 
00163     if (eapol_pdu->msg.key.key_information.pairwise_key) {
00164         // This is mismatch between KMP ID indicating 802.11/GKH and key type
00165         return GKH_MESSAGE_UNKNOWN;
00166     }
00167 
00168     uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
00169 
00170     switch (key_mask) {
00171         case KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
00172             // Must have valid replay counter
00173             if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, sec_keys)) {
00174                 if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
00175                     // This should include the GTK KDE, Lifetime KDE and GTKL KDE.
00176                     msg = GKH_MESSAGE_1;
00177                 }
00178             } else {
00179                 tr_error("GKH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
00180             }
00181             break;
00182         default:
00183             break;
00184     }
00185 
00186     return msg;
00187 }
00188 
00189 static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg)
00190 {
00191     eapol_pdu_t eapol_pdu;
00192     uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, 0, NULL);
00193 
00194     switch (msg) {
00195         case GKH_MESSAGE_2:
00196             eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys);
00197             eapol_pdu.msg.key.key_information.key_mic = true;
00198             eapol_pdu.msg.key.key_information.secured_key_frame = true;
00199             eapol_pdu.msg.key.key_length = 0;
00200             break;
00201         default:
00202             break;
00203     }
00204 
00205     uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(prot->sec_keys->ptk, NULL, 0, &eapol_pdu, eapol_pdu_size, prot->header_size);
00206 
00207     if (eapol_pdu_frame == NULL) {
00208         return -1;
00209     }
00210 
00211     tr_info("GKH: send Message 2");
00212 
00213     if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
00214         return -1;
00215     }
00216 
00217     return 0;
00218 }
00219 
00220 static void supp_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
00221 {
00222     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00223     sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
00224 }
00225 
00226 static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot)
00227 {
00228     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00229 
00230     // GKH supplicant state machine
00231     switch (sec_prot_state_get(&data->common)) {
00232         case GKH_STATE_INIT:
00233             tr_info("GKH init");
00234             sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_1);
00235             prot->timer_start(prot);
00236             break;
00237 
00238         // Wait GKH message 1 (starts handshake on supplicant)
00239         case GKH_STATE_MESSAGE_1:
00240             if (supp_gkh_sec_prot_mic_validate(prot) < 0) {
00241                 return;
00242             }
00243 
00244             if (supp_gkh_kde_handle(prot) < 0) {
00245                 return;
00246             }
00247 
00248             // Set default timeout for the total maximum length of the negotiation
00249             sec_prot_default_timeout_set(&data->common);
00250 
00251             supp_gkh_sec_prot_security_replay_counter_update(prot);
00252 
00253             tr_info("GKH start");
00254 
00255             // Send KMP-CREATE.indication
00256             prot->create_ind(prot);
00257             sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_RESP);
00258             break;
00259 
00260         // Wait KMP-CREATE.response
00261         case GKH_STATE_CREATE_RESP:
00262             if (sec_prot_result_ok_check(&data->common)) {
00263                 // Send GKH message 2
00264                 supp_gkh_sec_prot_message_send(prot, GKH_MESSAGE_2);
00265                 sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH);
00266             } else {
00267                 // Ready to be deleted
00268                 sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED);
00269             }
00270             break;
00271 
00272         case GKH_STATE_FINISH:
00273             tr_info("GKH finish");
00274 
00275             // KMP-FINISHED.indication,
00276             prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
00277             sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED);
00278             break;
00279 
00280         case GKH_STATE_FINISHED:
00281             tr_info("GKH finished");
00282             prot->timer_stop(prot);
00283             prot->finished(prot);
00284             break;
00285 
00286         default:
00287             break;
00288     }
00289 }
00290 
00291 static int8_t supp_gkh_sec_prot_mic_validate(sec_prot_t *prot)
00292 {
00293     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00294     return sec_prot_lib_mic_validate(prot->sec_keys->ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size);
00295 }
00296 
00297 static void supp_gkh_sec_prot_security_replay_counter_update(sec_prot_t *prot)
00298 {
00299     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00300     sec_prot_keys_pmk_replay_cnt_set(prot->sec_keys, data->recv_eapol_pdu.msg.key.replay_counter);
00301 }
00302 
00303 static int8_t supp_gkh_kde_handle(sec_prot_t *prot)
00304 {
00305     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00306 
00307     uint16_t kde_len;
00308     uint8_t *kde = sec_prot_lib_message_handle(prot->sec_keys->ptk, &kde_len, &data->recv_eapol_pdu);
00309     if (!kde) {
00310         return -1;
00311     }
00312 
00313     // If a valid new GTK value present, insert it
00314     int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys);
00315 
00316     ns_dyn_mem_free(kde);
00317 
00318     return ret;
00319 }
00320 
00321 #endif /* HAVE_WS */
00322