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
sec_prot_lib.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 <randLIB.h> 00021 #include "ns_types.h" 00022 #include "ns_list.h" 00023 #include "ns_trace.h" 00024 #include "nsdynmemLIB.h" 00025 #include "fhss_config.h " 00026 #include "NWK_INTERFACE/Include/protocol.h" 00027 #include "6LoWPAN/ws/ws_config.h" 00028 #include "Service_Libs/Trickle/trickle.h" 00029 #include "Security/kmp/kmp_addr.h" 00030 #include "Security/kmp/kmp_api.h" 00031 #include "Security/PANA/pana_eap_header.h" 00032 #include "Security/eapol/eapol_helper.h" 00033 #include "Security/eapol/kde_helper.h" 00034 #include "Security/protocols/sec_prot_certs.h" 00035 #include "Security/protocols/sec_prot_keys.h" 00036 #include "Security/protocols/sec_prot.h" 00037 #include "Security/protocols/sec_prot_lib.h" 00038 #include "Service_Libs/ieee_802_11/ieee_802_11.h" 00039 #include "Service_Libs/hmac/hmac_sha1.h" 00040 #include "Service_Libs/nist_aes_kw/nist_aes_kw.h" 00041 #include "mbedtls/sha256.h" 00042 00043 #ifdef HAVE_WS 00044 00045 #define TRACE_GROUP "secl" 00046 00047 void sec_prot_init(sec_prot_common_t *data) 00048 { 00049 data->state = SEC_STATE_INIT; 00050 data->result = SEC_RESULT_OK; 00051 data->ticks = SEC_INIT_TIMEOUT; 00052 data->trickle_running = false; 00053 } 00054 00055 void sec_prot_timer_timeout_handle(sec_prot_t *prot, sec_prot_common_t *data, const trickle_params_t *trickle_params, uint16_t ticks) 00056 { 00057 if (data->trickle_running && trickle_params) { 00058 bool running = trickle_running(&data->trickle_timer, trickle_params); 00059 00060 // Checks for trickle timer expiration */ 00061 if (trickle_timer(&data->trickle_timer, trickle_params, ticks)) { 00062 sec_prot_result_set(data, SEC_RESULT_TIMEOUT); 00063 prot->state_machine(prot); 00064 } 00065 00066 // Checks if maximum number of trickle timer expirations has happened 00067 if (running && !trickle_running(&data->trickle_timer, trickle_params)) { 00068 sec_prot_result_set(data, SEC_RESULT_TIMEOUT); 00069 sec_prot_state_set(prot, data, SEC_STATE_FINISH); 00070 } 00071 } 00072 00073 if (data->ticks > ticks) { 00074 data->ticks -= ticks; 00075 } else { 00076 tr_debug("prot timeout, state: %i", data->state); 00077 data->ticks = 0; 00078 sec_prot_result_set(data, SEC_RESULT_TIMEOUT); 00079 if (data->state == SEC_STATE_INIT) { 00080 sec_prot_state_set(prot, data, SEC_STATE_FINISHED); 00081 } else { 00082 sec_prot_state_set(prot, data, SEC_STATE_FINISH); 00083 } 00084 } 00085 } 00086 00087 void sec_prot_timer_trickle_start(sec_prot_common_t *data, const trickle_params_t *trickle_params) 00088 { 00089 trickle_start(&data->trickle_timer, trickle_params); 00090 data->trickle_running = true; 00091 } 00092 00093 void sec_prot_timer_trickle_stop(sec_prot_common_t *data) 00094 { 00095 trickle_stop(&data->trickle_timer); 00096 data->trickle_running = false; 00097 } 00098 00099 void sec_prot_state_set(sec_prot_t *prot, sec_prot_common_t *data, uint8_t state) 00100 { 00101 switch (state) { 00102 case SEC_STATE_FINISH: 00103 if (data->state == SEC_STATE_FINISHED) { 00104 // Already, do not update state; 00105 } else { 00106 data->state = SEC_STATE_FINISH; 00107 } 00108 data->trickle_running = false; 00109 data->ticks = SEC_FINISHED_TIMEOUT; 00110 00111 // Go to SEC_STATE_FINISH or SEC_STATE_FINISHED 00112 prot->state_machine(prot); 00113 return; 00114 00115 case SEC_STATE_FINISHED: 00116 // If not already on finished state 00117 if (data->state != SEC_STATE_FINISHED) { 00118 // Wait for timeout 00119 data->ticks = SEC_FINISHED_TIMEOUT; 00120 } 00121 data->trickle_running = false; 00122 00123 // Disables receiving of messages when state machine sets SEC_STATE_FINISHED 00124 prot->receive_disable(prot); 00125 00126 // Clear result 00127 sec_prot_result_set(data, SEC_RESULT_OK); 00128 break; 00129 00130 case SEC_STATE_INIT: 00131 data->state = SEC_STATE_INIT; 00132 prot->state_machine(prot); 00133 return; 00134 00135 default: 00136 break; 00137 } 00138 00139 data->state = state; 00140 } 00141 00142 uint8_t sec_prot_state_get(sec_prot_common_t *data) 00143 { 00144 return data->state; 00145 } 00146 00147 void sec_prot_result_set(sec_prot_common_t *data, sec_prot_result_e result) 00148 { 00149 data->result = result; 00150 } 00151 00152 sec_prot_result_e sec_prot_result_get(sec_prot_common_t *data) 00153 { 00154 return data->result; 00155 } 00156 00157 bool sec_prot_result_timeout_check(sec_prot_common_t *data) 00158 { 00159 if (data->result == SEC_RESULT_TIMEOUT) { 00160 data->result = SEC_RESULT_OK; 00161 return true; 00162 } 00163 return false; 00164 } 00165 00166 bool sec_prot_result_ok_check(sec_prot_common_t *data) 00167 { 00168 if (data->result == SEC_RESULT_OK) { 00169 return true; 00170 } 00171 return false; 00172 } 00173 00174 void sec_prot_default_timeout_set(sec_prot_common_t *data) 00175 { 00176 data->ticks = SEC_TOTAL_TIMEOUT; 00177 } 00178 00179 void sec_prot_lib_nonce_generate(uint8_t *nonce) 00180 { 00181 // Use randlib 00182 randLIB_get_n_bytes_random(nonce, EAPOL_KEY_NONCE_LEN); 00183 } 00184 00185 /* 00186 * From IEEE 802.11 how to init nonce calculation by using non-secure random 00187 * 00188 * PRF-256(Random number, “Init Counter”, Local MAC Address || Time) 00189 */ 00190 void sec_prot_lib_nonce_init(uint8_t *nonce, uint8_t *eui64, uint64_t time) 00191 { 00192 // For now, use randlib 00193 uint8_t random[EAPOL_KEY_NONCE_LEN]; 00194 randLIB_get_n_bytes_random(random, EAPOL_KEY_NONCE_LEN); 00195 00196 const uint8_t a_string_val[] = {"Init Counter"}; 00197 const uint8_t a_string_val_len = sizeof(a_string_val) - 1; 00198 00199 ieee_802_11_prf_t prf; 00200 00201 uint16_t string_len = ieee_802_11_prf_setup(&prf, EAPOL_KEY_NONCE_LEN * 8, a_string_val_len, EUI64_LEN + EUI64_LEN); 00202 uint8_t string[string_len]; 00203 00204 uint8_t *a_string = ieee_802_11_prf_get_a_string(&prf, string); 00205 memcpy(a_string, a_string_val, a_string_val_len); 00206 00207 uint8_t *b_string = ieee_802_11_prf_get_b_string(&prf, string); 00208 memcpy(b_string, eui64, EUI64_LEN); 00209 b_string += EUI64_LEN; 00210 memcpy(b_string, &time, sizeof(uint64_t)); 00211 00212 uint16_t result_len = ieee_802_11_prf_starts(&prf, random, EAPOL_KEY_NONCE_LEN); 00213 00214 ieee_802_11_prf_update(&prf, string); 00215 00216 uint8_t result[result_len]; 00217 00218 ieee_802_11_prf_finish(&prf, result); 00219 00220 memcpy(nonce, result, EAPOL_KEY_NONCE_LEN); 00221 } 00222 00223 /* 00224 * PTK = PRF-384(PMK, “Pairwise key expansion”, Min(AUTH EUI-64, SUP EUI-64) || 00225 * Max(AUTH EUI-64, SUP EUI-64) || Min (Anonce, Snonce) || Max(Anonce, Snonce)) 00226 * 00227 * PMK is 256 bits, PTK is 382 bits 00228 */ 00229 int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const uint8_t *eui64_2, const uint8_t *nonce1, const uint8_t *nonce2, uint8_t *ptk) 00230 { 00231 const uint8_t a_string_val[] = {"Pairwise key expansion"}; 00232 const uint8_t a_string_val_len = sizeof(a_string_val) - 1; 00233 00234 const uint8_t *min_eui64 = eui64_1; 00235 const uint8_t *max_eui64 = eui64_2; 00236 if (memcmp(eui64_1, eui64_2, EUI64_LEN) > 0) { 00237 min_eui64 = eui64_2; 00238 max_eui64 = eui64_1; 00239 } 00240 00241 const uint8_t *min_nonce = nonce1; 00242 const uint8_t *max_nonce = nonce2; 00243 if (memcmp(nonce1, nonce2, EAPOL_KEY_NONCE_LEN) > 0) { 00244 min_nonce = nonce2; 00245 max_nonce = nonce1; 00246 } 00247 00248 ieee_802_11_prf_t prf; 00249 00250 uint16_t string_len = ieee_802_11_prf_setup(&prf, 384, a_string_val_len, EUI64_LEN + EUI64_LEN + EAPOL_KEY_NONCE_LEN + EAPOL_KEY_NONCE_LEN); 00251 uint8_t string[string_len]; 00252 00253 uint8_t *a_string = ieee_802_11_prf_get_a_string(&prf, string); 00254 memcpy(a_string, a_string_val, a_string_val_len); 00255 00256 uint8_t *b_string = ieee_802_11_prf_get_b_string(&prf, string); 00257 memcpy(b_string, min_eui64, EUI64_LEN); 00258 b_string += EUI64_LEN; 00259 memcpy(b_string, max_eui64, EUI64_LEN); 00260 b_string += EUI64_LEN; 00261 00262 memcpy(b_string, min_nonce, EAPOL_KEY_NONCE_LEN); 00263 b_string += EAPOL_KEY_NONCE_LEN; 00264 memcpy(b_string, max_nonce, EAPOL_KEY_NONCE_LEN); 00265 00266 uint16_t result_len = ieee_802_11_prf_starts(&prf, pmk, PMK_LEN); 00267 00268 ieee_802_11_prf_update(&prf, string); 00269 00270 uint8_t result[result_len]; 00271 00272 ieee_802_11_prf_finish(&prf, result); 00273 00274 memcpy(ptk, result, PTK_LEN); 00275 00276 return 0; 00277 } 00278 00279 int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *pmkid) 00280 { 00281 const uint8_t pmk_string_val[] = {"PMK Name"}; 00282 const uint8_t pmk_string_val_len = sizeof(pmk_string_val) - 1; 00283 00284 uint8_t data_len = pmk_string_val_len + EUI64_LEN + EUI64_LEN; 00285 uint8_t data[data_len]; 00286 uint8_t *ptr = data; 00287 memcpy(ptr, pmk_string_val, pmk_string_val_len); 00288 ptr += pmk_string_val_len; 00289 memcpy(ptr, auth_eui64, EUI64_LEN); 00290 ptr += EUI64_LEN; 00291 memcpy(ptr, supp_eui64, EUI64_LEN); 00292 00293 if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) { 00294 return -1; 00295 } 00296 00297 tr_info("PMKID %s EUI-64 %s %s", trace_array(pmkid, PMKID_LEN), trace_array(auth_eui64, 8), trace_array(supp_eui64, 8)); 00298 return 0; 00299 } 00300 00301 int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *ptkid) 00302 { 00303 const uint8_t ptk_string_val[] = {"PTK Name"}; 00304 const uint8_t ptk_string_val_len = sizeof(ptk_string_val) - 1; 00305 00306 uint8_t data_len = ptk_string_val_len + EUI64_LEN + EUI64_LEN; 00307 uint8_t data[data_len]; 00308 uint8_t *ptr = data; 00309 memcpy(ptr, ptk_string_val, ptk_string_val_len); 00310 ptr += ptk_string_val_len; 00311 memcpy(ptr, auth_eui64, EUI64_LEN); 00312 ptr += EUI64_LEN; 00313 memcpy(ptr, supp_eui64, EUI64_LEN); 00314 00315 if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) { 00316 return -1; 00317 } 00318 00319 tr_info("PTKID %s EUI-64 %s %s", trace_array(ptkid, PTKID_LEN), trace_array(auth_eui64, 8), trace_array(supp_eui64, 8)); 00320 return 0; 00321 } 00322 00323 uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len, eapol_pdu_t *eapol_pdu, uint16_t eapol_pdu_size, uint8_t header_size) 00324 { 00325 uint8_t *eapol_pdu_frame = ns_dyn_mem_temporary_alloc(header_size + eapol_pdu_size); 00326 00327 if (!eapol_pdu_frame) { 00328 return NULL; 00329 } 00330 00331 uint8_t *eapol_kde = eapol_write_pdu_frame(eapol_pdu_frame + header_size, eapol_pdu); 00332 00333 if (kde) { 00334 if (eapol_pdu->msg.key.key_information.encrypted_key_data) { 00335 size_t output_len = kde_len; 00336 if (nist_aes_key_wrap(1, &ptk[KEK_INDEX], 128, kde, kde_len - 8, eapol_kde, &output_len) < 0 || output_len != kde_len) { 00337 ns_dyn_mem_free(eapol_pdu_frame); 00338 return NULL; 00339 } 00340 } else { 00341 memcpy(eapol_kde, kde, kde_len); 00342 } 00343 } 00344 00345 if (eapol_pdu->msg.key.key_information.key_mic) { 00346 uint8_t mic[EAPOL_KEY_MIC_LEN]; 00347 if (hmac_sha1_calc(ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) { 00348 ns_dyn_mem_free(eapol_pdu_frame); 00349 return NULL; 00350 } 00351 eapol_write_key_packet_mic(eapol_pdu_frame + header_size, mic); 00352 } 00353 00354 return eapol_pdu_frame; 00355 } 00356 00357 uint8_t *sec_prot_lib_message_handle(uint8_t *ptk, uint16_t *kde_len, eapol_pdu_t *eapol_pdu) 00358 { 00359 if (eapol_pdu->msg.key.key_data_length == 0 || eapol_pdu->msg.key.key_data == NULL) { 00360 return NULL; 00361 } 00362 00363 uint8_t *key_data = eapol_pdu->msg.key.key_data; 00364 uint16_t key_data_len = eapol_pdu->msg.key.key_data_length; 00365 00366 uint8_t *kde = ns_dyn_mem_temporary_alloc(key_data_len); 00367 *kde_len = key_data_len; 00368 00369 if (eapol_pdu->msg.key.key_information.encrypted_key_data) { 00370 size_t output_len = eapol_pdu->msg.key.key_data_length; 00371 if (nist_aes_key_wrap(0, &ptk[KEK_INDEX], 128, key_data, key_data_len, kde, &output_len) < 0 || output_len != (size_t) key_data_len - 8) { 00372 tr_error("Decrypt failed"); 00373 ns_dyn_mem_free(kde); 00374 return NULL; 00375 } 00376 *kde_len = output_len; 00377 } else { 00378 memcpy(kde, key_data, *kde_len); 00379 } 00380 00381 return kde; 00382 } 00383 00384 int8_t sec_prot_lib_gtk_read(uint8_t *kde, uint16_t kde_len, sec_prot_keys_t *sec_keys) 00385 { 00386 int8_t gtk_index = -1; 00387 00388 uint8_t key_id; 00389 uint8_t gtk[GTK_LEN]; 00390 00391 if (kde_gtk_read(kde, kde_len, &key_id, gtk) >= 0) { 00392 uint32_t lifetime = 0; 00393 if (kde_lifetime_read(kde, kde_len, &lifetime) >= 0) { 00394 00395 } 00396 00397 // A new GTK value 00398 if (sec_prot_keys_gtk_set(sec_keys->gtks, key_id, gtk, lifetime) >= 0) { 00399 gtk_index = (int8_t) key_id; // Insert 00400 } 00401 } 00402 uint8_t gtkl; 00403 if (kde_gtkl_read(kde, kde_len, >kl) >= 0) { 00404 sec_prot_keys_gtkl_set(sec_keys, gtkl); 00405 } else { 00406 tr_error("No GTKL"); 00407 return -1; 00408 } 00409 00410 // Sanity checks 00411 if (gtk_index >= 0) { 00412 if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, gtk_index)) { 00413 tr_error("mismatch between GTK and GTKL"); 00414 } 00415 } 00416 00417 tr_info("GTK recv index %i lifetime %"PRIu32"", gtk_index, sec_prot_keys_gtk_lifetime_get(sec_keys->gtks, gtk_index)); 00418 00419 return 0; 00420 } 00421 00422 int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8_t pdu_size) 00423 { 00424 uint8_t recv_mic[EAPOL_KEY_MIC_LEN]; 00425 memcpy(recv_mic, mic, EAPOL_KEY_MIC_LEN); 00426 00427 eapol_write_key_packet_mic(pdu, 0); 00428 00429 uint8_t calc_mic[EAPOL_KEY_MIC_LEN]; 00430 if (hmac_sha1_calc(ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) { 00431 tr_error("MIC invalid"); 00432 return -1; 00433 } 00434 if (memcmp(recv_mic, calc_mic, EAPOL_KEY_MIC_LEN) != 0) { 00435 tr_error("MIC invalid"); 00436 return -1; 00437 } 00438 return 0; 00439 } 00440 00441 int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth) 00442 { 00443 uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); 00444 if (!pmk) { 00445 return -1; 00446 } 00447 00448 uint8_t local_eui64[8]; 00449 uint8_t remote_eui64[8]; 00450 // Tries to get the EUI-64 that is validated by PTK procedure or bound to supplicant entry 00451 uint8_t *remote_eui64_ptr = sec_prot_keys_ptk_eui_64_get(prot->sec_keys); 00452 if (remote_eui64_ptr) { 00453 memcpy(remote_eui64, remote_eui64_ptr, 8); 00454 prot->addr_get(prot, local_eui64, NULL); 00455 } else { 00456 // If validated EUI-64 is not present, use the remote EUI-64 00457 prot->addr_get(prot, local_eui64, remote_eui64); 00458 } 00459 00460 if (is_auth) { 00461 return sec_prot_lib_pmkid_calc(pmk, local_eui64, remote_eui64, pmkid); 00462 } else { 00463 return sec_prot_lib_pmkid_calc(pmk, remote_eui64, local_eui64, pmkid); 00464 } 00465 } 00466 00467 int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_auth) 00468 { 00469 uint8_t local_eui64[8]; 00470 prot->addr_get(prot, local_eui64, NULL); 00471 uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys); 00472 if (!ptk) { 00473 return -1; 00474 } 00475 // Uses always the EUI-64 that is validated by PTK procedure or bound to supplicant entry 00476 uint8_t *remote_eui64 = sec_prot_keys_ptk_eui_64_get(prot->sec_keys); 00477 if (!remote_eui64) { 00478 return -1; 00479 } 00480 00481 if (is_auth) { 00482 return sec_prot_lib_ptkid_calc(ptk, local_eui64, remote_eui64, ptkid); 00483 } else { 00484 return sec_prot_lib_ptkid_calc(ptk, remote_eui64, local_eui64, ptkid); 00485 } 00486 } 00487 00488 int8_t sec_prot_lib_gtkhash_generate(uint8_t *gtk, uint8_t *gtk_hash) 00489 { 00490 int8_t ret_val = 0; 00491 00492 mbedtls_sha256_context ctx; 00493 00494 mbedtls_sha256_init(&ctx); 00495 00496 if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { 00497 ret_val = -1; 00498 goto error; 00499 } 00500 00501 if (mbedtls_sha256_update_ret(&ctx, gtk, 16) != 0) { 00502 ret_val = -1; 00503 goto error; 00504 } 00505 00506 uint8_t output[32]; 00507 00508 if (mbedtls_sha256_finish_ret(&ctx, output) != 0) { 00509 ret_val = -1; 00510 goto error; 00511 } 00512 00513 memcpy(gtk_hash, &output[24], 8); 00514 00515 error: 00516 mbedtls_sha256_free(&ctx); 00517 00518 return ret_val; 00519 } 00520 00521 uint8_t *sec_prot_remote_eui_64_addr_get(sec_prot_t *prot) 00522 { 00523 if (prot->sec_keys && prot->sec_keys->ptk_eui_64_set) { 00524 return prot->sec_keys->ptk_eui_64; 00525 } else { 00526 return NULL; 00527 } 00528 } 00529 00530 #endif /* HAVE_WS */
Generated on Tue Jul 12 2022 13:54:49 by
