Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers key_sec_prot.c Source File

key_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/key_sec_prot/key_sec_prot.h"
00037 
00038 #ifdef HAVE_WS
00039 
00040 #define TRACE_GROUP "ksep"
00041 
00042 #define KEY_SEC_FINISHED_TIMEOUT                  1       // Finishes right away
00043 
00044 typedef enum {
00045     KEY_STATE_INIT = SEC_STATE_INIT,
00046     KEY_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
00047     KEY_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
00048     KEY_STATE_TX_DONE = SEC_STATE_FIRST,
00049     KEY_STATE_INITIAL_KEY_RECEIVED,
00050     KEY_STATE_FINISH = SEC_STATE_FINISH,
00051     KEY_STATE_FINISHED = SEC_STATE_FINISHED
00052 } key_sec_prot_state_e;
00053 
00054 typedef struct {
00055     sec_prot_common_t              common;       /**< Common data */
00056 } key_sec_prot_int_t;
00057 
00058 static uint16_t key_sec_prot_size(void);
00059 static int8_t supp_key_sec_prot_init(sec_prot_t *prot);
00060 static int8_t auth_key_sec_prot_init(sec_prot_t *prot);
00061 
00062 static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
00063 static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
00064 static void key_sec_prot_delete(sec_prot_t *prot);
00065 static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
00066 static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
00067 static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e tx_status);
00068 static void key_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
00069 
00070 static void supp_key_sec_prot_state_machine(sec_prot_t *prot);
00071 static void auth_key_sec_prot_state_machine(sec_prot_t *prot);
00072 
00073 #define key_sec_prot_get(prot) (key_sec_prot_int_t *) &prot->data
00074 
00075 int8_t supp_key_sec_prot_register(kmp_service_t *service)
00076 {
00077     if (!service) {
00078         return -1;
00079     }
00080 
00081     if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, supp_key_sec_prot_init) < 0) {
00082         return -1;
00083     }
00084 
00085     if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, supp_key_sec_prot_init) < 0) {
00086         return -1;
00087     }
00088 
00089     return 0;
00090 }
00091 
00092 int8_t auth_key_sec_prot_register(kmp_service_t *service)
00093 {
00094     if (!service) {
00095         return -1;
00096     }
00097 
00098     if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, auth_key_sec_prot_init) < 0) {
00099         return -1;
00100     }
00101 
00102     if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, auth_key_sec_prot_init) < 0) {
00103         return -1;
00104     }
00105 
00106     return 0;
00107 }
00108 
00109 static uint16_t key_sec_prot_size(void)
00110 {
00111     return sizeof(key_sec_prot_int_t);
00112 }
00113 
00114 static int8_t supp_key_sec_prot_init(sec_prot_t *prot)
00115 {
00116     prot->create_req = key_sec_prot_create_request;
00117     prot->tx_status_ind = key_sec_prot_tx_status_ind;
00118     prot->delete = key_sec_prot_delete;
00119     prot->state_machine = supp_key_sec_prot_state_machine;
00120     prot->timer_timeout = key_sec_prot_timer_timeout;
00121 
00122     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00123     sec_prot_init(&data->common);
00124     sec_prot_state_set(prot, &data->common, KEY_STATE_INIT);
00125 
00126     return 0;
00127 }
00128 
00129 static int8_t auth_key_sec_prot_init(sec_prot_t *prot)
00130 {
00131     prot->create_resp = key_sec_prot_create_response;
00132     prot->receive = key_sec_prot_receive;
00133     prot->delete = key_sec_prot_delete;
00134     prot->state_machine = auth_key_sec_prot_state_machine;
00135     prot->timer_timeout = key_sec_prot_timer_timeout;
00136 
00137     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00138     sec_prot_init(&data->common);
00139     sec_prot_state_set(prot, &data->common, KEY_STATE_INIT);
00140 
00141     return 0;
00142 }
00143 
00144 static void key_sec_prot_delete(sec_prot_t *prot)
00145 {
00146     (void) prot;
00147 }
00148 
00149 static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
00150 {
00151     (void) sec_keys;
00152 
00153     prot->state_machine_call(prot);
00154 }
00155 
00156 static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
00157 {
00158     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00159     sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_RESP);
00160 
00161     sec_prot_result_set(&data->common, result);
00162     prot->state_machine_call(prot);
00163 }
00164 
00165 static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
00166 {
00167     uint8_t result = 0;
00168     uint16_t kde_len = KDE_GTKL_LEN;
00169 
00170     uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
00171     uint8_t pmkid[PMKID_LEN];
00172     if (pmk) {
00173         if (sec_prot_lib_pmkid_generate(prot, pmkid, false) >= 0) {
00174             kde_len += KDE_PMKID_LEN;
00175         } else {
00176             pmk = NULL;
00177         }
00178     }
00179 
00180     uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys);
00181     uint8_t ptkid[PTKID_LEN];
00182     if (ptk) {
00183         if (sec_prot_lib_ptkid_generate(prot, ptkid, false) >= 0) {
00184             kde_len += KDE_PTKID_LEN;
00185         } else {
00186             ptk = NULL;
00187         }
00188     }
00189 
00190     uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len);
00191     if (!kde_start) {
00192         return -1;
00193     }
00194 
00195     uint8_t *kde_end = kde_start;
00196 
00197     if (pmk) {
00198         kde_end = kde_pmkid_write(kde_end, pmkid);
00199     }
00200 
00201     if (ptk) {
00202         kde_end = kde_ptkid_write(kde_end, ptkid);
00203     }
00204 
00205     uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(sec_keys->gtks);
00206     kde_end = kde_gtkl_write(kde_end, gtkl);
00207 
00208     kde_len = kde_end - kde_start;
00209 
00210     eapol_pdu_t eapol_pdu;
00211 
00212     uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, kde_start);
00213 
00214     uint8_t *eapol_decoded_data = ns_dyn_mem_temporary_alloc(eapol_pdu_size + prot->header_size); // In future fill with data that defines eapol message
00215     if (!eapol_decoded_data) {
00216         result = -1;
00217         goto initial_key_exit;
00218     }
00219 
00220     eapol_pdu.msg.key.key_information.install = false;
00221     eapol_pdu.msg.key.key_information.pairwise_key = false;
00222     eapol_pdu.msg.key.key_information.request = true;
00223     eapol_pdu.msg.key.replay_counter = 0;
00224     eapol_pdu.msg.key.key_length = 0;
00225     eapol_write_pdu_frame(eapol_decoded_data + prot->header_size, &eapol_pdu);
00226 
00227     tr_info("Initial EAPOL-Key send, PMKID %s PTKID %s GTKL %x", pmk ? "set" : "not set", ptk ? "set" : "not set", gtkl);
00228 
00229     if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
00230         result = -1;
00231     }
00232 
00233 initial_key_exit:
00234     ns_dyn_mem_free(kde_start);
00235 
00236     return result;
00237 }
00238 
00239 static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
00240 {
00241     eapol_pdu_t eapol_pdu;
00242     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00243     sec_prot_result_e result = SEC_RESULT_OK;
00244 
00245     tr_info("Initial EAPOL-Key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00246 
00247     // Decoding is successful
00248     if (eapol_parse_pdu_header(pdu, size, &eapol_pdu)) {
00249         if (eapol_pdu.packet_type != EAPOL_KEY_TYPE) {
00250             tr_info("not EAPOL-Key packet");
00251             prot->finished(prot);
00252             return -1;
00253         }
00254 
00255         uint16_t kde_len;
00256         uint8_t *kde = sec_prot_lib_message_handle(prot->sec_keys->ptk, &kde_len, &eapol_pdu);
00257         if (!kde) {
00258             tr_error("no KDEs");
00259             prot->finished(prot);
00260             return -1;
00261         }
00262 
00263         // Default assumption is that PMK and PTK are not valid
00264         prot->sec_keys->pmk_mismatch = true;
00265         prot->sec_keys->ptk_mismatch = true;
00266 
00267         // Checks if supplicant indicates that it has valid PMK
00268         uint8_t remote_keyid[KEYID_LEN];
00269         if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) {
00270             uint8_t pmkid[PMKID_LEN];
00271             if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
00272                 if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) {
00273                     prot->sec_keys->pmk_mismatch = false;
00274                 }
00275             }
00276         }
00277 
00278         // Checks if supplicant indicates that it has valid PTK
00279         if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) {
00280             uint8_t ptkid[PTKID_LEN];
00281             if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) {
00282                 if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) {
00283                     prot->sec_keys->ptk_mismatch = false;
00284                 }
00285             }
00286         }
00287 
00288         // Get the GTKL that supplicant indicates
00289         uint8_t gtkl;
00290         if (kde_gtkl_read(kde, kde_len, &gtkl) >= 0) {
00291             prot->sec_keys->gtkl = gtkl;
00292         } else {
00293             tr_error("no GTKL");
00294             return -1;
00295         }
00296 
00297         tr_info("PMK %s PTK %s GTKL %x", prot->sec_keys->pmk_mismatch ? "not live" : "live", prot->sec_keys->ptk_mismatch ? "not live" : "live", gtkl);
00298 
00299         ns_dyn_mem_free(kde);
00300     } else {
00301         tr_error("Invalid");
00302         result = SEC_RESULT_ERROR;
00303     }
00304 
00305     sec_prot_result_set(&data->common, result);
00306     prot->state_machine(prot);
00307 
00308     if (result != SEC_RESULT_OK) {
00309         return -1;
00310     }
00311 
00312     return 0;
00313 }
00314 
00315 static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e tx_status)
00316 {
00317     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00318 
00319     // Indicates TX failure
00320     if (tx_status == SEC_PROT_TX_ERR_TX_NO_ACK) {
00321         sec_prot_result_set(&data->common, KMP_RESULT_ERR_TX_NO_ACK);
00322     } else if (tx_status != SEC_PROT_TX_OK) {
00323         // Indicates other failure
00324         sec_prot_result_set(&data->common, KMP_RESULT_ERR_UNSPEC);
00325     }
00326     prot->state_machine_call(prot);
00327     return 0;
00328 }
00329 
00330 static void key_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
00331 {
00332     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00333     sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
00334 }
00335 
00336 static void supp_key_sec_prot_state_machine(sec_prot_t *prot)
00337 {
00338     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00339 
00340     switch (sec_prot_state_get(&data->common)) {
00341         case KEY_STATE_INIT:
00342             tr_info("Initial-key init");
00343             sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_REQ);
00344             prot->timer_start(prot);
00345             break;
00346 
00347         case KEY_STATE_CREATE_REQ:
00348             // KMP-CREATE.confirm
00349             prot->create_conf(prot, sec_prot_result_get(&data->common));
00350 
00351             // Send initial-key message
00352             if (key_sec_prot_initial_key_send(prot, prot->sec_keys) < 0) {
00353                 // Error on sending, ready to be deleted
00354                 sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
00355                 return;
00356             }
00357 
00358             // Waits for TX acknowledge
00359             sec_prot_state_set(prot, &data->common, KEY_STATE_TX_DONE);
00360             break;
00361 
00362         case KEY_STATE_TX_DONE:
00363             sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
00364             break;
00365 
00366         case KEY_STATE_FINISH:
00367             // KMP-FINISHED.indication,
00368             prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
00369             sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
00370             data->common.ticks = KEY_SEC_FINISHED_TIMEOUT;
00371             break;
00372 
00373         case KEY_STATE_FINISHED:
00374             tr_info("Initial-key finished");
00375             prot->timer_stop(prot);
00376             prot->finished(prot);
00377             break;
00378 
00379         default:
00380             break;
00381     }
00382 }
00383 
00384 static void auth_key_sec_prot_state_machine(sec_prot_t *prot)
00385 {
00386     key_sec_prot_int_t *data = key_sec_prot_get(prot);
00387 
00388     switch (sec_prot_state_get(&data->common)) {
00389         case KEY_STATE_INIT:
00390             tr_info("Initial-key init");
00391             sec_prot_state_set(prot, &data->common, KEY_STATE_INITIAL_KEY_RECEIVED);
00392             prot->timer_start(prot);
00393             break;
00394 
00395         case KEY_STATE_INITIAL_KEY_RECEIVED:
00396             if (!sec_prot_result_ok_check(&data->common)) {
00397                 // Goes right away to finished
00398                 sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
00399                 return;
00400             }
00401 
00402             // Send KMP-CREATE.indication
00403             prot->create_ind(prot);
00404             sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_RESP);
00405             break;
00406 
00407         case KEY_STATE_CREATE_RESP:
00408             // Goes to finish state right away
00409             sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
00410             break;
00411 
00412         case KEY_STATE_FINISH:
00413             // KMP-FINISHED.indication,
00414             prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
00415             sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
00416             data->common.ticks = KEY_SEC_FINISHED_TIMEOUT;
00417             break;
00418 
00419         case KEY_STATE_FINISHED: {
00420             tr_info("Initial-key finished, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00421             prot->finished(prot);
00422             break;
00423         }
00424 
00425         default:
00426             break;
00427     }
00428 }
00429 
00430 #endif /* HAVE_WS */
00431