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_fwh_sec_prot.c
00001 /* 00002 * Copyright (c) 2016-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/fwh_sec_prot/auth_fwh_sec_prot.h" 00037 #include "Service_Libs/hmac/hmac_sha1.h" 00038 #include "Service_Libs/nist_aes_kw/nist_aes_kw.h" 00039 00040 #ifdef HAVE_WS 00041 00042 #define TRACE_GROUP "afwh" 00043 00044 typedef enum { 00045 FWH_STATE_INIT = SEC_STATE_INIT, 00046 FWH_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, 00047 FWH_STATE_MESSAGE_2 = SEC_STATE_FIRST, 00048 FWH_STATE_MESSAGE_4, 00049 FWH_STATE_FINISH = SEC_STATE_FINISH, 00050 FWH_STATE_FINISHED = SEC_STATE_FINISHED 00051 } fwh_sec_prot_state_e; 00052 00053 typedef enum { 00054 FWH_MESSAGE_UNKNOWN = 0, 00055 FWH_MESSAGE_1, 00056 FWH_MESSAGE_2, 00057 FWH_MESSAGE_3, 00058 FWH_MESSAGE_4 00059 } fwh_sec_prot_msg_e; 00060 00061 typedef struct { 00062 sec_prot_common_t common; /**< Common data */ 00063 eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ 00064 fwh_sec_prot_msg_e recv_msg; /**< Received message */ 00065 uint8_t nonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */ 00066 uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */ 00067 void *recv_pdu; /**< received pdu */ 00068 uint16_t recv_size; /**< received pdu size */ 00069 } fwh_sec_prot_int_t; 00070 00071 /*Small network setup*/ 00072 #define FWH_SMALL_IMIN 300 // retries done in 30 seconds 00073 #define FWH_SMALL_IMAX 900 // Largest value 90 seconds 00074 00075 /* Large network setup*/ 00076 #define FWH_LARGE_IMIN 600 // retries done in 60 seconds 00077 #define FWH_LARGE_IMAX 2400 // Largest value 240 seconds 00078 00079 static trickle_params_t fwh_trickle_params = { 00080 .Imin = FWH_SMALL_IMIN, /* ticks are 100ms */ 00081 .Imax = FWH_SMALL_IMAX, /* ticks are 100ms */ 00082 .k = 0, /* infinity - no consistency checking */ 00083 .TimerExpirations = 2 00084 }; 00085 00086 static uint16_t auth_fwh_sec_prot_size(void); 00087 static int8_t auth_fwh_sec_prot_init(sec_prot_t *prot); 00088 00089 static void auth_fwh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); 00090 static void auth_fwh_sec_prot_delete(sec_prot_t *prot); 00091 static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); 00092 static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); 00093 static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot); 00094 00095 static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg); 00096 static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); 00097 00098 static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys); 00099 static int8_t auth_fwh_sec_prot_mic_validate(sec_prot_t *prot); 00100 00101 #define fwh_sec_prot_get(prot) (fwh_sec_prot_int_t *) &prot->data 00102 00103 int8_t auth_fwh_sec_prot_register(kmp_service_t *service) 00104 { 00105 if (!service) { 00106 return -1; 00107 } 00108 00109 if (kmp_service_sec_protocol_register(service, IEEE_802_11_4WH, auth_fwh_sec_prot_size, auth_fwh_sec_prot_init) < 0) { 00110 return -1; 00111 } 00112 00113 return 0; 00114 } 00115 00116 int8_t auth_fwh_sec_prot_timing_adjust(uint8_t timing) 00117 { 00118 if (timing < 16) { 00119 fwh_trickle_params.Imin = FWH_SMALL_IMIN; 00120 fwh_trickle_params.Imax = FWH_SMALL_IMAX; 00121 } else { 00122 fwh_trickle_params.Imin = FWH_LARGE_IMIN; 00123 fwh_trickle_params.Imax = FWH_LARGE_IMAX; 00124 } 00125 return 0; 00126 } 00127 00128 static uint16_t auth_fwh_sec_prot_size(void) 00129 { 00130 return sizeof(fwh_sec_prot_int_t); 00131 } 00132 00133 static int8_t auth_fwh_sec_prot_init(sec_prot_t *prot) 00134 { 00135 prot->create_req = auth_fwh_sec_prot_create_request; 00136 prot->create_resp = 0; 00137 prot->receive = auth_fwh_sec_prot_receive; 00138 prot->delete = auth_fwh_sec_prot_delete; 00139 prot->state_machine = auth_fwh_sec_prot_state_machine; 00140 prot->timer_timeout = auth_fwh_sec_prot_timer_timeout; 00141 00142 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00143 sec_prot_init(&data->common); 00144 sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); 00145 00146 data->common.ticks = 15 * 10; // 15 seconds 00147 00148 uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; 00149 sec_prot_lib_nonce_init(data->nonce, eui64, 1000); 00150 00151 return 0; 00152 } 00153 00154 static void auth_fwh_sec_prot_delete(sec_prot_t *prot) 00155 { 00156 // No op at the moment 00157 (void) prot; 00158 } 00159 00160 static void auth_fwh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) 00161 { 00162 prot->sec_keys = sec_keys; 00163 00164 // Call state machine 00165 prot->state_machine_call(prot); 00166 } 00167 00168 static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) 00169 { 00170 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00171 int8_t ret_val = -1; 00172 00173 // Decoding is successful 00174 if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { 00175 // Get message 00176 data->recv_msg = auth_fwh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys); 00177 if (data->recv_msg != FWH_MESSAGE_UNKNOWN) { 00178 tr_info("4WH: recv %s, eui-64: %s", data->recv_msg == FWH_MESSAGE_2 ? "Message 2" : "Message 4", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00179 00180 // Call state machine 00181 data->recv_pdu = pdu; 00182 data->recv_size = size; 00183 prot->state_machine(prot); 00184 } else { 00185 tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00186 } 00187 ret_val = 0; 00188 } else { 00189 tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00190 } 00191 00192 memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); 00193 data->recv_msg = FWH_MESSAGE_UNKNOWN; 00194 data->recv_pdu = 0; 00195 data->recv_size = 0; 00196 00197 return ret_val; 00198 } 00199 00200 static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) 00201 { 00202 fwh_sec_prot_msg_e msg = FWH_MESSAGE_UNKNOWN; 00203 00204 if (!eapol_pdu->msg.key.key_information.pairwise_key) { 00205 // This is mismatch between KMP ID indicating 802.11/4WH and key type 00206 return FWH_MESSAGE_UNKNOWN; 00207 } 00208 00209 uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu); 00210 00211 switch (key_mask) { 00212 case KEY_INFO_KEY_MIC: 00213 // Only accept message from supplicant with expected replay counter 00214 if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { 00215 msg = FWH_MESSAGE_2; 00216 } 00217 break; 00218 case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: 00219 // Only accept message from supplicant with expected replay counter 00220 if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { 00221 msg = FWH_MESSAGE_4; 00222 } 00223 break; 00224 default: 00225 break; 00226 } 00227 00228 return msg; 00229 } 00230 00231 static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg) 00232 { 00233 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00234 00235 uint16_t kde_len = 0; 00236 00237 switch (msg) { 00238 case FWH_MESSAGE_1: 00239 kde_len = KDE_PMKID_LEN; 00240 break; 00241 case FWH_MESSAGE_3: 00242 kde_len = KDE_GTK_LEN + KDE_LIFETIME_LEN + KDE_GTKL_LEN; 00243 kde_len = kde_len + 8; // One 64 bit block for AES Key Wrap 00244 kde_len = kde_padded_length_calc(kde_len); 00245 break; 00246 default: 00247 break; 00248 } 00249 00250 uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len); 00251 00252 if (!kde_start) { 00253 return -1; 00254 } 00255 00256 uint8_t *kde_end = kde_start; 00257 00258 switch (msg) { 00259 case FWH_MESSAGE_1: { 00260 uint8_t pmkid[PMKID_LEN]; 00261 if (sec_prot_lib_pmkid_generate(prot, pmkid, true) < 0) { 00262 ns_dyn_mem_free(kde_start); 00263 return -1; 00264 } 00265 kde_end = kde_pmkid_write(kde_end, pmkid); 00266 } 00267 break; 00268 case FWH_MESSAGE_3: { 00269 uint8_t gtk_index; 00270 uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, >k_index); 00271 if (gtk) { 00272 kde_end = kde_gtk_write(kde_end, gtk_index, gtk); 00273 00274 uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index); 00275 kde_end = kde_lifetime_write(kde_end, gtk_lifetime); 00276 } 00277 uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks); 00278 kde_end = kde_gtkl_write(kde_end, gtkl); 00279 kde_padding_write(kde_end, kde_start + kde_len); 00280 } 00281 break; 00282 default: 00283 break; 00284 } 00285 00286 eapol_pdu_t eapol_pdu; 00287 uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, NULL); 00288 00289 eapol_pdu.msg.key.key_information.pairwise_key = true; 00290 00291 switch (msg) { 00292 case FWH_MESSAGE_1: 00293 sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); 00294 eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); 00295 eapol_pdu.msg.key.key_information.key_ack = true; 00296 eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN; 00297 eapol_pdu.msg.key.key_nonce = data->nonce; 00298 break; 00299 case FWH_MESSAGE_3: 00300 sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); 00301 eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); 00302 eapol_pdu.msg.key.key_information.install = true; 00303 eapol_pdu.msg.key.key_information.key_ack = true; 00304 eapol_pdu.msg.key.key_information.key_mic = true; 00305 eapol_pdu.msg.key.key_information.secured_key_frame = true; 00306 eapol_pdu.msg.key.key_information.encrypted_key_data = true; 00307 eapol_pdu.msg.key.key_nonce = data->nonce; 00308 eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN; 00309 break; 00310 default: 00311 break; 00312 } 00313 00314 uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(data->new_ptk, kde_start, kde_len, &eapol_pdu, eapol_pdu_size, prot->header_size); 00315 00316 ns_dyn_mem_free(kde_start); 00317 00318 if (eapol_pdu_frame == NULL) { 00319 return -1; 00320 } 00321 00322 tr_info("4WH: send %s, eui-64: %s", msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00323 00324 if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { 00325 return -1; 00326 } 00327 00328 return 0; 00329 } 00330 00331 static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) 00332 { 00333 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00334 sec_prot_timer_timeout_handle(prot, &data->common, &fwh_trickle_params, ticks); 00335 } 00336 00337 static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) 00338 { 00339 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00340 00341 // 4WH authenticator state machine 00342 switch (sec_prot_state_get(&data->common)) { 00343 case FWH_STATE_INIT: 00344 tr_info("4WH: init"); 00345 prot->timer_start(prot); 00346 sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_REQ); 00347 break; 00348 00349 // Wait KMP-CREATE.request 00350 case FWH_STATE_CREATE_REQ: 00351 tr_info("4WH: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00352 00353 // Set default timeout for the total maximum length of the negotiation 00354 sec_prot_default_timeout_set(&data->common); 00355 00356 uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); 00357 if (!pmk) { // If PMK is not set fails 00358 prot->create_conf(prot, SEC_RESULT_ERROR); 00359 sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); 00360 return; 00361 } 00362 00363 // KMP-CREATE.confirm 00364 prot->create_conf(prot, SEC_RESULT_OK); 00365 00366 // Sends 4WH Message 1 00367 sec_prot_lib_nonce_generate(data->nonce); 00368 auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); 00369 00370 // Start trickle timer to re-send if no response 00371 sec_prot_timer_trickle_start(&data->common, &fwh_trickle_params); 00372 00373 sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2); 00374 break; 00375 00376 // Wait 4WH message 2 00377 case FWH_STATE_MESSAGE_2: 00378 if (sec_prot_result_timeout_check(&data->common)) { 00379 // Re-sends 4WH Message 1 00380 sec_prot_lib_nonce_generate(data->nonce); 00381 auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); 00382 } else { 00383 if (data->recv_msg != FWH_MESSAGE_2) { 00384 return; 00385 } 00386 00387 if (auth_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) { 00388 return; 00389 } 00390 if (auth_fwh_sec_prot_mic_validate(prot) < 0) { 00391 memset(data->new_ptk, 0, PTK_LEN); 00392 return; 00393 } 00394 00395 // Sends 4WH Message 3 00396 auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); 00397 00398 // Start trickle timer to re-send if no response 00399 sec_prot_timer_trickle_start(&data->common, &fwh_trickle_params); 00400 00401 sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4); 00402 } 00403 break; 00404 00405 // Wait 4WH message 4 00406 case FWH_STATE_MESSAGE_4: 00407 if (sec_prot_result_timeout_check(&data->common)) { 00408 // Re-sends 4WH Message 3 00409 auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); 00410 } else { 00411 if (data->recv_msg != FWH_MESSAGE_4) { 00412 return; 00413 } 00414 if (auth_fwh_sec_prot_mic_validate(prot) < 0) { 00415 return; 00416 } 00417 00418 // If GTK was inserted set it valid 00419 sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys); 00420 // Reset PTK mismatch 00421 sec_prot_keys_ptk_mismatch_reset(prot->sec_keys); 00422 // Update PTK 00423 sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); 00424 sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); 00425 } 00426 break; 00427 00428 case FWH_STATE_FINISH: 00429 tr_info("4WH: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); 00430 00431 // KMP-FINISHED.indication, 00432 prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); 00433 sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); 00434 break; 00435 00436 case FWH_STATE_FINISHED: { 00437 uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); 00438 tr_info("4WH: finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); 00439 prot->timer_stop(prot); 00440 prot->finished(prot); 00441 break; 00442 } 00443 00444 default: 00445 break; 00446 } 00447 } 00448 00449 static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys) 00450 { 00451 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00452 00453 uint8_t local_eui64[8]; 00454 uint8_t remote_eui64[8]; 00455 00456 prot->addr_get(prot, local_eui64, remote_eui64); 00457 00458 uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; 00459 if (!remote_nonce) { 00460 tr_error("SNonce invalid"); 00461 return 1; 00462 } 00463 00464 uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); 00465 sec_prot_lib_ptk_calc(pmk, local_eui64, remote_eui64, data->nonce, remote_nonce, data->new_ptk); 00466 00467 return 0; 00468 } 00469 00470 static int8_t auth_fwh_sec_prot_mic_validate(sec_prot_t *prot) 00471 { 00472 fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); 00473 return sec_prot_lib_mic_validate(data->new_ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); 00474 } 00475 00476 #endif /* HAVE_WS */ 00477
Generated on Tue Jul 12 2022 13:54:02 by
