Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers auth_fwh_sec_prot.c Source File

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, &gtk_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