Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sec_prot_lib.c Source File

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, &gtkl) >= 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 */