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_gkh_sec_prot.c Source File

auth_gkh_sec_prot.c

00001 /*
00002  * Copyright (c) 2018-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/gkh_sec_prot/auth_gkh_sec_prot.h"
00037 
00038 #ifdef HAVE_WS
00039 
00040 #define TRACE_GROUP "agkh"
00041 
00042 typedef enum {
00043     GKH_STATE_INIT = SEC_STATE_INIT,
00044     GKH_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
00045     GKH_STATE_MESSAGE_2 = SEC_STATE_FIRST,
00046     GKH_STATE_FINISH = SEC_STATE_FINISH,
00047     GKH_STATE_FINISHED = SEC_STATE_FINISHED
00048 } gkh_sec_prot_state_e;
00049 
00050 typedef enum {
00051     GKH_MESSAGE_UNKNOWN = 0,
00052     GKH_MESSAGE_1,
00053     GKH_MESSAGE_2
00054 } gkh_sec_prot_msg_e;
00055 
00056 typedef struct {
00057     sec_prot_common_t             common;           /**< Common data */
00058     eapol_pdu_t                   recv_eapol_pdu;   /**< Received EAPOL PDU */
00059     void                          *recv_pdu;        /**< Received pdu */
00060     uint16_t                      recv_size;        /**< Received pdu size */
00061 } gkh_sec_prot_int_t;
00062 
00063 /*Small network setup*/
00064 #define GKH_SMALL_IMIN 300 // retries done in 30 seconds
00065 #define GKH_SMALL_IMAX 900 // Largest value 90 seconds
00066 
00067 /* Large network setup*/
00068 #define GKH_LARGE_IMIN 600 // retries done in 60 seconds
00069 #define GKH_LARGE_IMAX 2400 // Largest value 240 seconds
00070 
00071 static trickle_params_t gkh_trickle_params = {
00072     .Imin = GKH_SMALL_IMIN,            /* ticks are 100ms */
00073     .Imax = GKH_SMALL_IMAX,            /* ticks are 100ms */
00074     .k = 0,                /* infinity - no consistency checking */
00075     .TimerExpirations = 2
00076 };
00077 
00078 static uint16_t auth_gkh_sec_prot_size(void);
00079 static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot);
00080 
00081 static void auth_gkh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
00082 static void auth_gkh_sec_prot_delete(sec_prot_t *prot);
00083 static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
00084 static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys);
00085 static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot);
00086 
00087 static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg);
00088 static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
00089 static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot);
00090 
00091 #define gkh_sec_prot_get(prot) (gkh_sec_prot_int_t *) &prot->data
00092 
00093 int8_t auth_gkh_sec_prot_register(kmp_service_t *service)
00094 {
00095     if (!service) {
00096         return -1;
00097     }
00098 
00099     if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH, auth_gkh_sec_prot_size, auth_gkh_sec_prot_init) < 0) {
00100         return -1;
00101     }
00102 
00103     return 0;
00104 }
00105 
00106 int8_t auth_gkh_sec_prot_timing_adjust(uint8_t timing)
00107 {
00108     if (timing < 16) {
00109         gkh_trickle_params.Imin = GKH_SMALL_IMIN;
00110         gkh_trickle_params.Imax = GKH_SMALL_IMAX;
00111     } else {
00112         gkh_trickle_params.Imin = GKH_LARGE_IMIN;
00113         gkh_trickle_params.Imax = GKH_LARGE_IMAX;
00114     }
00115     return 0;
00116 }
00117 
00118 static uint16_t auth_gkh_sec_prot_size(void)
00119 {
00120     return sizeof(gkh_sec_prot_int_t);
00121 }
00122 
00123 static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot)
00124 {
00125     prot->create_req = auth_gkh_sec_prot_create_request;
00126     prot->create_resp = 0;
00127     prot->receive = auth_gkh_sec_prot_receive;
00128     prot->delete = auth_gkh_sec_prot_delete;
00129     prot->state_machine = auth_gkh_sec_prot_state_machine;
00130     prot->timer_timeout = auth_gkh_sec_prot_timer_timeout;
00131 
00132     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00133     sec_prot_init(&data->common);
00134     sec_prot_state_set(prot, &data->common, GKH_STATE_INIT);
00135 
00136     return 0;
00137 }
00138 
00139 static void auth_gkh_sec_prot_delete(sec_prot_t *prot)
00140 {
00141     // No op at the moment
00142     (void) prot;
00143 }
00144 
00145 static void auth_gkh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
00146 {
00147     prot->sec_keys = sec_keys;
00148 
00149     // Call state machine
00150     prot->state_machine_call(prot);
00151 }
00152 
00153 static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
00154 {
00155     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00156     int8_t ret_val = -1;
00157 
00158     // Decoding is successful
00159     if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
00160         // Get message
00161         if (auth_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) {
00162             tr_info("GKH: recv Message 2, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00163 
00164             // Call state machine
00165             data->recv_pdu = pdu;
00166             data->recv_size = size;
00167             prot->state_machine(prot);
00168         } else {
00169             tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00170         }
00171         ret_val = 0;
00172     } else {
00173         tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00174     }
00175 
00176     memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
00177     data->recv_pdu = 0;
00178     data->recv_size = 0;
00179 
00180     return ret_val;
00181 }
00182 
00183 static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys)
00184 {
00185     gkh_sec_prot_msg_e msg = GKH_MESSAGE_UNKNOWN;
00186 
00187     if (eapol_pdu->msg.key.key_information.pairwise_key) {
00188         // This is mismatch between KMP ID indicating 802.11/GKH and key type
00189         return GKH_MESSAGE_UNKNOWN;
00190     }
00191 
00192     uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
00193 
00194     switch (key_mask) {
00195         case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
00196             // Only accept message from supplicant with expected replay counter
00197             if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
00198                 msg = GKH_MESSAGE_2;
00199             }
00200             break;
00201         default:
00202             break;
00203     }
00204 
00205     return msg;
00206 }
00207 
00208 static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg)
00209 {
00210     uint16_t kde_len = 0;
00211 
00212     switch (msg) {
00213         case GKH_MESSAGE_1:
00214             kde_len = KDE_GTK_LEN + KDE_LIFETIME_LEN + KDE_GTKL_LEN;
00215             kde_len = kde_len + 8; // One 64 bit block for AES Key Wrap
00216             kde_len = kde_padded_length_calc(kde_len);
00217             break;
00218         default:
00219             break;
00220     }
00221 
00222     uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len);
00223 
00224     if (!kde_start) {
00225         return -1;
00226     }
00227 
00228     uint8_t *kde_end = kde_start;
00229 
00230     switch (msg) {
00231         case GKH_MESSAGE_1: {
00232             uint8_t gtk_index;
00233             uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, &gtk_index);
00234             if (gtk) {
00235                 kde_end = kde_gtk_write(kde_end, gtk_index, gtk);
00236 
00237                 uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index);
00238                 kde_end = kde_lifetime_write(kde_end, gtk_lifetime);
00239             }
00240             uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks);
00241             kde_end = kde_gtkl_write(kde_end, gtkl);
00242             kde_padding_write(kde_end, kde_start + kde_len);
00243         }
00244         break;
00245         default:
00246             break;
00247     }
00248 
00249     eapol_pdu_t eapol_pdu;
00250     uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, NULL);
00251 
00252     switch (msg) {
00253         case GKH_MESSAGE_1:
00254             sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys);
00255             eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys);
00256             eapol_pdu.msg.key.key_information.key_ack = true;
00257             eapol_pdu.msg.key.key_information.key_mic = true;
00258             eapol_pdu.msg.key.key_information.secured_key_frame = true;
00259             eapol_pdu.msg.key.key_information.encrypted_key_data = true;
00260             eapol_pdu.msg.key.key_length = 0;
00261             break;
00262         default:
00263             break;
00264     }
00265 
00266     uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(prot->sec_keys->ptk, kde_start, kde_len, &eapol_pdu, eapol_pdu_size, prot->header_size);
00267 
00268     ns_dyn_mem_free(kde_start);
00269 
00270     if (eapol_pdu_frame == NULL) {
00271         return -1;
00272     }
00273 
00274     tr_info("GKH: send Message 1, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00275 
00276     if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
00277         return -1;
00278     }
00279 
00280     return 0;
00281 }
00282 
00283 static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
00284 {
00285     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00286     sec_prot_timer_timeout_handle(prot, &data->common, &gkh_trickle_params, ticks);
00287 }
00288 
00289 static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
00290 {
00291     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00292 
00293     // GKH authenticator state machine
00294     switch (sec_prot_state_get(&data->common)) {
00295         case GKH_STATE_INIT:
00296             tr_info("GKH init");
00297             sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_REQ);
00298             prot->timer_start(prot);
00299             break;
00300 
00301         // Wait KMP-CREATE.request
00302         case GKH_STATE_CREATE_REQ:
00303             tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00304 
00305             // Set default timeout for the total maximum length of the negotiation
00306             sec_prot_default_timeout_set(&data->common);
00307 
00308             // KMP-CREATE.confirm
00309             prot->create_conf(prot, SEC_RESULT_OK);
00310 
00311             // Sends 4WH Message 1
00312             auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1);
00313 
00314             // Start trickle timer to re-send if no response
00315             sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params);
00316 
00317             sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2);
00318             break;
00319 
00320         // Wait GKH message 2
00321         case GKH_STATE_MESSAGE_2:
00322 
00323             if (sec_prot_result_timeout_check(&data->common)) {
00324                 // Re-sends GKH Message 1
00325                 auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1);
00326             } else {
00327                 if (auth_gkh_sec_prot_mic_validate(prot) < 0) {
00328                     return;
00329                 }
00330                 // Set inserted GTK valid
00331                 sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
00332 
00333                 sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH);
00334             }
00335             break;
00336 
00337         case GKH_STATE_FINISH:
00338             tr_info("GKH finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
00339 
00340             // KMP-FINISHED.indication,
00341             prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
00342 
00343             sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED);
00344             break;
00345 
00346         case GKH_STATE_FINISHED: {
00347             uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot);
00348             tr_info("GKH finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set");
00349             prot->timer_stop(prot);
00350             prot->finished(prot);
00351             break;
00352         }
00353 
00354         default:
00355             break;
00356     }
00357 }
00358 
00359 static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot)
00360 {
00361     gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
00362     return sec_prot_lib_mic_validate(prot->sec_keys->ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size);
00363 }
00364 
00365 #endif /* HAVE_WS */
00366