Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
auth_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/eapol/kde_helper.h" 00032 #include "Security/protocols/sec_prot_certs.h" 00033 #include "Security/protocols/sec_prot_keys.h" 00034 #include "Security/protocols/sec_prot.h" 00035 #include "Security/protocols/sec_prot_lib.h" 00036 #include "Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h" 00037 00038 #ifdef HAVE_WS 00039 00040 #define TRACE_GROUP "agkh" 00041 00042 typedef enum { 00043 GKH_STATE_INIT = SEC_STATE_INIT, 00044 GKH_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, 00045 GKH_STATE_MESSAGE_2 = 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 /*Small network setup*/ 00064 #define GKH_SMALL_IMIN 300 // retries done in 30 seconds 00065 #define GKH_SMALL_IMAX 900 // Largest value 90 seconds 00066 00067 /* Large network setup*/ 00068 #define GKH_LARGE_IMIN 600 // retries done in 60 seconds 00069 #define GKH_LARGE_IMAX 2400 // Largest value 240 seconds 00070 00071 static trickle_params_t gkh_trickle_params = { 00072 .Imin = GKH_SMALL_IMIN, /* ticks are 100ms */ 00073 .Imax = GKH_SMALL_IMAX, /* ticks are 100ms */ 00074 .k = 0, /* infinity - no consistency checking */ 00075 .TimerExpirations = 2 00076 }; 00077 00078 static uint16_t auth_gkh_sec_prot_size(void); 00079 static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot); 00080 00081 static void auth_gkh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); 00082 static void auth_gkh_sec_prot_delete(sec_prot_t *prot); 00083 static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); 00084 static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); 00085 static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot); 00086 00087 static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg); 00088 static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); 00089 static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot); 00090 00091 #define gkh_sec_prot_get(prot) (gkh_sec_prot_int_t *) &prot->data 00092 00093 int8_t auth_gkh_sec_prot_register(kmp_service_t *service) 00094 { 00095 if (!service) { 00096 return -1; 00097 } 00098 00099 if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH, auth_gkh_sec_prot_size, auth_gkh_sec_prot_init) < 0) { 00100 return -1; 00101 } 00102 00103 return 0; 00104 } 00105 00106 int8_t auth_gkh_sec_prot_timing_adjust(uint8_t timing) 00107 { 00108 if (timing < 16) { 00109 gkh_trickle_params.Imin = GKH_SMALL_IMIN; 00110 gkh_trickle_params.Imax = GKH_SMALL_IMAX; 00111 } else { 00112 gkh_trickle_params.Imin = GKH_LARGE_IMIN; 00113 gkh_trickle_params.Imax = GKH_LARGE_IMAX; 00114 } 00115 return 0; 00116 } 00117 00118 static uint16_t auth_gkh_sec_prot_size(void) 00119 { 00120 return sizeof(gkh_sec_prot_int_t); 00121 } 00122 00123 static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot) 00124 { 00125 prot->create_req = auth_gkh_sec_prot_create_request; 00126 prot->create_resp = 0; 00127 prot->receive = auth_gkh_sec_prot_receive; 00128 prot->delete = auth_gkh_sec_prot_delete; 00129 prot->state_machine = auth_gkh_sec_prot_state_machine; 00130 prot->timer_timeout = auth_gkh_sec_prot_timer_timeout; 00131 00132 gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); 00133 sec_prot_init(&data->common); 00134 sec_prot_state_set(prot, &data->common, GKH_STATE_INIT); 00135 00136 return 0; 00137 } 00138 00139 static void auth_gkh_sec_prot_delete(sec_prot_t *prot) 00140 { 00141 // No op at the moment 00142 (void) prot; 00143 } 00144 00145 static void auth_gkh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) 00146 { 00147 prot->sec_keys = sec_keys; 00148 00149 // Call state machine 00150 prot->state_machine_call(prot); 00151 } 00152 00153 static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) 00154 { 00155 gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); 00156 int8_t ret_val = -1; 00157 00158 // Decoding is successful 00159 if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { 00160 // Get message 00161 if (auth_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) { 00162 tr_info("GKH: recv Message 2, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00163 00164 // Call state machine 00165 data->recv_pdu = pdu; 00166 data->recv_size = size; 00167 prot->state_machine(prot); 00168 } else { 00169 tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00170 } 00171 ret_val = 0; 00172 } else { 00173 tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00174 } 00175 00176 memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); 00177 data->recv_pdu = 0; 00178 data->recv_size = 0; 00179 00180 return ret_val; 00181 } 00182 00183 static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) 00184 { 00185 gkh_sec_prot_msg_e msg = GKH_MESSAGE_UNKNOWN; 00186 00187 if (eapol_pdu->msg.key.key_information.pairwise_key) { 00188 // This is mismatch between KMP ID indicating 802.11/GKH and key type 00189 return GKH_MESSAGE_UNKNOWN; 00190 } 00191 00192 uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu); 00193 00194 switch (key_mask) { 00195 case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: 00196 // Only accept message from supplicant with expected replay counter 00197 if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { 00198 msg = GKH_MESSAGE_2; 00199 } 00200 break; 00201 default: 00202 break; 00203 } 00204 00205 return msg; 00206 } 00207 00208 static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg) 00209 { 00210 uint16_t kde_len = 0; 00211 00212 switch (msg) { 00213 case GKH_MESSAGE_1: 00214 kde_len = KDE_GTK_LEN + KDE_LIFETIME_LEN + KDE_GTKL_LEN; 00215 kde_len = kde_len + 8; // One 64 bit block for AES Key Wrap 00216 kde_len = kde_padded_length_calc(kde_len); 00217 break; 00218 default: 00219 break; 00220 } 00221 00222 uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len); 00223 00224 if (!kde_start) { 00225 return -1; 00226 } 00227 00228 uint8_t *kde_end = kde_start; 00229 00230 switch (msg) { 00231 case GKH_MESSAGE_1: { 00232 uint8_t gtk_index; 00233 uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, >k_index); 00234 if (gtk) { 00235 kde_end = kde_gtk_write(kde_end, gtk_index, gtk); 00236 00237 uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index); 00238 kde_end = kde_lifetime_write(kde_end, gtk_lifetime); 00239 } 00240 uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks); 00241 kde_end = kde_gtkl_write(kde_end, gtkl); 00242 kde_padding_write(kde_end, kde_start + kde_len); 00243 } 00244 break; 00245 default: 00246 break; 00247 } 00248 00249 eapol_pdu_t eapol_pdu; 00250 uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, NULL); 00251 00252 switch (msg) { 00253 case GKH_MESSAGE_1: 00254 sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); 00255 eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); 00256 eapol_pdu.msg.key.key_information.key_ack = true; 00257 eapol_pdu.msg.key.key_information.key_mic = true; 00258 eapol_pdu.msg.key.key_information.secured_key_frame = true; 00259 eapol_pdu.msg.key.key_information.encrypted_key_data = true; 00260 eapol_pdu.msg.key.key_length = 0; 00261 break; 00262 default: 00263 break; 00264 } 00265 00266 uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(prot->sec_keys->ptk, kde_start, kde_len, &eapol_pdu, eapol_pdu_size, prot->header_size); 00267 00268 ns_dyn_mem_free(kde_start); 00269 00270 if (eapol_pdu_frame == NULL) { 00271 return -1; 00272 } 00273 00274 tr_info("GKH: send Message 1, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00275 00276 if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { 00277 return -1; 00278 } 00279 00280 return 0; 00281 } 00282 00283 static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) 00284 { 00285 gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); 00286 sec_prot_timer_timeout_handle(prot, &data->common, &gkh_trickle_params, ticks); 00287 } 00288 00289 static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) 00290 { 00291 gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); 00292 00293 // GKH authenticator state machine 00294 switch (sec_prot_state_get(&data->common)) { 00295 case GKH_STATE_INIT: 00296 tr_info("GKH init"); 00297 sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_REQ); 00298 prot->timer_start(prot); 00299 break; 00300 00301 // Wait KMP-CREATE.request 00302 case GKH_STATE_CREATE_REQ: 00303 tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00304 00305 // Set default timeout for the total maximum length of the negotiation 00306 sec_prot_default_timeout_set(&data->common); 00307 00308 // KMP-CREATE.confirm 00309 prot->create_conf(prot, SEC_RESULT_OK); 00310 00311 // Sends 4WH Message 1 00312 auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); 00313 00314 // Start trickle timer to re-send if no response 00315 sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params); 00316 00317 sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); 00318 break; 00319 00320 // Wait GKH message 2 00321 case GKH_STATE_MESSAGE_2: 00322 00323 if (sec_prot_result_timeout_check(&data->common)) { 00324 // Re-sends GKH Message 1 00325 auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); 00326 } else { 00327 if (auth_gkh_sec_prot_mic_validate(prot) < 0) { 00328 return; 00329 } 00330 // Set inserted GTK valid 00331 sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys); 00332 00333 sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH); 00334 } 00335 break; 00336 00337 case GKH_STATE_FINISH: 00338 tr_info("GKH finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00339 00340 // KMP-FINISHED.indication, 00341 prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); 00342 00343 sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); 00344 break; 00345 00346 case GKH_STATE_FINISHED: { 00347 uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); 00348 tr_info("GKH finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); 00349 prot->timer_stop(prot); 00350 prot->finished(prot); 00351 break; 00352 } 00353 00354 default: 00355 break; 00356 } 00357 } 00358 00359 static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot) 00360 { 00361 gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); 00362 return sec_prot_lib_mic_validate(prot->sec_keys->ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); 00363 } 00364 00365 #endif /* HAVE_WS */ 00366
Generated on Tue Jul 12 2022 13:54:02 by
