station: Don't call network_rank_update with NULL network
PATCH 1/10 station: Don't call network_rank_update with NULL network
Move the update of station->networks_sorted order to before we set station->connected_network NULL to avoid a crash when we attempt to use the NULL pointer.
--- src/station.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
src/station.c +3 -3
@@ -1298,15 +1298,15 @@ static void station_reset_connection_state(struct station *station)station_roam_state_clear (station); - station->connected_bss =NULL ; - station->connected_network =NULL ; -/* Refresh the ordered network list */ network_rank_update (station->connected_network, false);l_queue_remove (station->networks_sorted, station->connected_network);l_queue_insert (station->networks_sorted, station->connected_network, network_rank_compare,NULL ); + station->connected_bss =NULL ; + station->connected_network =NULL ; +l_dbus_property_changed (dbus,netdev_get_path (station->netdev),IWD_STATION_INTERFACE ,"ConnectedNetwork" ); l_dbus_property_changed(dbus, network_get_path(network),
Signature · 1 line
2.25.1
PATCH 2/10 eapol: Use eapol_start in authenticator mode too
On the supplicant side eapol_register would only register the eapol_sm on a given netdev to start receiving frames and an eapol_start call is required for the state machine to start executing. On the authenticator side we shouldn't have the "early frame" problem but there's no reason for the semantics of the two methods to be different. Somehow we were doing everything in eapol_register and not using eapol_start if hs->authenticator was true, so bring this in line with the supplicant side and require eapol_start to be called also from ap.c.
--- src/ap.c | 1 + src/eapol.c | 37 +++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 20 deletions(-)
src/ap.c +1 -0
@@ -469,6 +469,7 @@ static void ap_start_rsna(struct sta_state *sta, const uint8_t *gtk_rsc)eapol_sm_set_listen_interval (sta->sm, sta->listen_interval);eapol_register (sta->sm); +eapol_start (sta->sm);return ;
src/eapol.c +17 -20
@@ -2338,28 +2338,14 @@ void __eapol_set_rekey_offload_func(eapol_rekey_offload_func_t func)void eapol_register (struct eapol_sm *sm) { -l_queue_push_head (state_machines, sm); - -if (sm->handshake->authenticator) { - sm->watch_id =eapol_frame_watch_add (sm->handshake->ifindex, - eapol_rx_auth_packet, sm); - -if (!sm->handshake->proto_version) - sm->protocol_version =EAPOL_PROTOCOL_VERSION_2004 ; -else - sm->protocol_version = sm->handshake->proto_version; +eapol_frame_watch_func_t rx_handler = sm->handshake->authenticator ? + eapol_rx_auth_packet : eapol_rx_packet; - sm->started = true; -/* Since AP/AdHoc only support AKM PSK we can hard code this */ - sm->mic_len =16 ; +l_queue_push_head (state_machines, sm); -/* kick off handshake */ -eapol_ptk_1_of_4_retry (NULL , sm); - }else { - sm->watch_id =eapol_frame_watch_add (sm->handshake->ifindex, - eapol_rx_packet, sm); - sm->protocol_version = sm->handshake->proto_version; - } + sm->watch_id =eapol_frame_watch_add (sm->handshake->ifindex, + rx_handler, sm); + sm->protocol_version = sm->handshake->proto_version; }bool eapol_start (struct eapol_sm *sm)
@@ -2409,6 +2395,17 @@ bool eapol_start(struct eapol_sm *sm) sm->early_frame =NULL ; } +if (sm->handshake->authenticator) { +if (L_WARN_ON (!sm->handshake->have_pmk)) +return false; + +if (!sm->protocol_version) + sm->protocol_version =EAPOL_PROTOCOL_VERSION_2004 ; + +/* Kick off handshake */ +eapol_ptk_1_of_4_retry (NULL , sm); + } +return true; eap_error:
Signature · 1 line
2.25.1
PATCH 3/10 eap: Add authenticator method logic and API
In reply to Andrew ZaborowskiThe goal is to add specifically EAP-WSC registrar side and it looks like extending our EAP and EAPoL code to support both supplicant and authenticator-side methods is simpler than adding just EAP-WSC as a special case.
Since EAP-WSC always ends in an EAP failure, I haven't actually tested the success path.
---
v2: Added an eap_start to send the Request/Identity from there instead
of doing it directly at the end of eap_load_settings.
--- src/eap-private.h | 5 ++ src/eap.c | 211 +++++++++++++++++++++++++++++++++++++++++++++- src/eap.h | 1 + 3 files changed, 214 insertions(+), 3 deletions(-)
src/eap-private.h +5 -0
@@ -81,6 +81,10 @@ struct eap_method {void (*handle_retransmit)(struct eap_state *eap,const uint8_t *pkt,size_t len);const char *(*get_identity)(struct eap_state *eap); + +bool (*validate_identity)(struct eap_state *eap,const char *identity); +void (*handle_response)(struct eap_state *eap, +const uint8_t *pkt,size_t len); };struct eap_method_desc {
@@ -123,6 +127,7 @@ void eap_set_key_material(struct eap_state *eap,void eap_start_complete_timeout (struct eap_state *eap);void eap_method_respond (struct eap_state *eap,uint8_t *buf,size_t len); +void eap_method_new_request (struct eap_state *eap,uint8_t *buf,size_t len);bool eap_method_is_success (struct eap_state *eap);void eap_method_success (struct eap_state *eap);void eap_method_error (struct eap_state *eap);
src/eap.c +208 -3
288 lines not on this page · raw message
src/eap.h +1 -0
@@ -81,6 +81,7 @@ int eap_check_settings(struct l_settings *settings, struct l_queue *secrets,bool eap_load_settings (struct eap_state *eap,struct l_settings *settings,const char *prefix);bool eap_reset (struct eap_state *eap); +void eap_start (struct eap_state *eap);void eap_set_key_material_func (struct eap_state *eap,eap_key_material_func_t func);
Signature · 1 line
2.25.1
PATCH 4/10 eapol: Basic EAP support in authenticator mode
In reply to Andrew ZaborowskiHandle EAPoL-EAP frames using our eap.c methods in authenticator mode same as we do on the supplicant side. The user (ap.c) will only need to set a valid 8021x_settings in the handshake object, same as on the supplicant side.
--- src/eapol.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 6 deletions(-)
src/eapol.c +49 -6
@@ -876,7 +876,7 @@ struct eapol_sm *eapol_sm_new(struct handshake_state *hs) sm->handshake = hs; -if (hs->settings_8021x) +if (hs->settings_8021x && !hs->authenticator) sm->use_eapol_start = true; sm->require_handshake = true;
@@ -2074,6 +2074,18 @@ static void eapol_eap_complete_cb(enum eap_result result, void *user_data) }eap_reset (sm->eap); + +if (sm->handshake->authenticator) { +if (L_WARN_ON (!sm->handshake->have_pmk)) { +handshake_failed (sm,MMPDU_REASON_CODE_UNSPECIFIED ); +return ; + } + +/* sm->mic_len will have been set in eapol_eap_results_cb */ + +/* Kick off 4-Way Handshake */ +eapol_ptk_1_of_4_retry (NULL , sm); + } }/* This respresentes the eapResults message */
@@ -2209,7 +2221,34 @@ static void eapol_rx_auth_packet(uint16_t proto, const uint8_t *from, {struct eapol_sm *sm = user_data; +if (proto !=ETH_P_PAE ||memcmp (from, sm->handshake->spa,6 )) +return ; +switch (frame->header.packet_type) { +case 0 :/* EAPOL-EAP */ +if (!sm->eap) { +l_error ("Authenticator received an unexpected " +"EAPOL-EAP frame from %s" , +util_address_to_string (from)); +return ; + } + +eap_rx_packet (sm->eap, frame->data, +L_BE16_TO_CPU (frame->header.packet_len)); +break ; + +case 1 :/* EAPOL-Start */ +/* +* The supplicant might have sent an EAPoL-Start even before +* we queued our EAP Identity Request, so this should happen +* mostly while we wait for the EAP Identity Response or before. +* It's safe to ignore this frame in either case. +* +* TODO: if we're already past the full handshake, send a +* new msg 1/4. +*/ +break ; +case 3 :/* EAPOL-Key */ eapol_auth_key_handle (sm, frame);break ;
@@ -2396,14 +2435,18 @@ bool eapol_start(struct eapol_sm *sm) }if (sm->handshake->authenticator) { -if (L_WARN_ON (!sm->handshake->have_pmk)) -return false; -if (!sm->protocol_version) sm->protocol_version =EAPOL_PROTOCOL_VERSION_2004 ; -/* Kick off handshake */ -eapol_ptk_1_of_4_retry (NULL , sm); +if (sm->handshake->settings_8021x) +eap_start (sm->eap); +else { +if (L_WARN_ON (!sm->handshake->have_pmk)) +return false; + +/* Kick off handshake */ +eapol_ptk_1_of_4_retry (NULL , sm); + } }return true;
Signature · 1 line
2.25.1
PATCH 5/10 eap-wsc: Registrar mode settings loading
In reply to Andrew ZaborowskiAlongside the current EAP-WSC enrollee side support, add the initial part of registrar side. In the same file, register a new method with the name string of "WSC-R". In this patch only the load_settings method is added. validate_identity and handle_response are added in later patches.
--- src/eap-wsc.c | 438 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 319 insertions(+), 119 deletions(-)
src/eap-wsc.c +319 -119
@@ -57,28 +57,40 @@ enum wsc_flag { };enum state { +/* Enrollee states */ STATE_EXPECT_START =0 ,STATE_EXPECT_M2 ,STATE_EXPECT_M4 ,STATE_EXPECT_M6 ,STATE_EXPECT_M8 ,STATE_FINISHED , +/* Registrar states */ +STATE_EXPECT_IDENTITY , +STATE_EXPECT_M1 , +STATE_EXPECT_M3 , +STATE_EXPECT_M5 , +STATE_EXPECT_M7 , +STATE_EXPECT_DONE , };static struct l_key *dh5_generator;static struct l_key *dh5_prime;struct eap_wsc_state { +bool registrar;struct wsc_m1 *m1;struct wsc_m2 *m2; +struct wsc_credential wpa2_cred; +struct wsc_credential open_cred;uint8_t *sent_pdu;size_t sent_len;struct l_key *private;char *device_password; -uint8_t e_snonce1[16 ]; -uint8_t e_snonce2[16 ]; +uint8_t local_snonce1[16 ]; +uint8_t local_snonce2[16 ];uint8_t iv1[16 ];uint8_t iv2[16 ]; +uint8_t iv3[16 ];uint8_t psk1[16 ];uint8_t psk2[16 ];uint8_t r_hash2[32 ];
@@ -274,12 +286,8 @@ static bool encrypted_settings_encrypt(struct eap_wsc_state *wsc,return true; } -static void eap_wsc_free (struct eap_state *eap) +static void eap_wsc_state_free (struct eap_wsc_state *wsc) { -struct eap_wsc_state *wsc =eap_get_data (eap); - -eap_set_data (eap,NULL ); -if (wsc->device_password) {explicit_bzero (wsc->device_password,strlen (wsc->device_password));
@@ -305,14 +313,24 @@ static void eap_wsc_free(struct eap_state *eap)l_free (wsc->m1);l_free (wsc->m2); -explicit_bzero (wsc->e_snonce1,16 ); -explicit_bzero (wsc->e_snonce2,16 ); +explicit_bzero (wsc->local_snonce1,16 ); +explicit_bzero (wsc->local_snonce2,16 );explicit_bzero (wsc->psk1,16 );explicit_bzero (wsc->psk2,16 ); +explicit_bzero (&wsc->wpa2_cred,sizeof (struct wsc_credential )); +explicit_bzero (&wsc->open_cred,sizeof (struct wsc_credential ));l_free (wsc); } +static void eap_wsc_free (struct eap_state *eap) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); + +eap_set_data (eap,NULL ); +eap_wsc_state_free (wsc); +} +static void eap_wsc_send_fragment (struct eap_state *eap) {struct eap_wsc_state *wsc =eap_get_data (eap);
@@ -541,9 +559,9 @@ static void eap_wsc_send_m7(struct eap_state *eap,size_t encrypted_len;bool r; -memcpy (m7es.e_snonce2, wsc->e_snonce2,sizeof (wsc->e_snonce2)); +memcpy (m7es.e_snonce2, wsc->local_snonce2,sizeof (wsc->local_snonce2)); pdu =wsc_build_m7_encrypted_settings (&m7es, &pdu_len); -explicit_bzero (m7es.e_snonce2,sizeof (wsc->e_snonce2)); +explicit_bzero (m7es.e_snonce2,sizeof (wsc->local_snonce2));if (!pdu)return ;
@@ -642,9 +660,9 @@ static void eap_wsc_send_m5(struct eap_state *eap,size_t encrypted_len;bool r; -memcpy (m5es.e_snonce1, wsc->e_snonce1,sizeof (wsc->e_snonce1)); +memcpy (m5es.e_snonce1, wsc->local_snonce1,sizeof (wsc->local_snonce1)); pdu =wsc_build_m5_encrypted_settings (&m5es, &pdu_len); -explicit_bzero (m5es.e_snonce1,sizeof (wsc->e_snonce1)); +explicit_bzero (m5es.e_snonce1,sizeof (wsc->local_snonce1));if (!pdu)return ;
@@ -773,8 +791,8 @@ static void eap_wsc_send_m3(struct eap_state *eap,* E-Hash1 = HMACAuthKey(E-S1 || PSK1 || PKE || PKR) * E-Hash2 = HMACAuthKey(E-S2 || PSK2 || PKE || PKR) */ - iov[0 ].iov_base = wsc->e_snonce1; - iov[0 ].iov_len =sizeof (wsc->e_snonce1); + iov[0 ].iov_base = wsc->local_snonce1; + iov[0 ].iov_len =sizeof (wsc->local_snonce1); iov[1 ].iov_base = wsc->psk1; iov[1 ].iov_len =sizeof (wsc->psk1); iov[2 ].iov_base = wsc->m1->public_key;
@@ -785,8 +803,8 @@ static void eap_wsc_send_m3(struct eap_state *eap,l_checksum_get_digest (wsc->hmac_auth_key, m3.e_hash1,sizeof (m3.e_hash1)); - iov[0 ].iov_base = wsc->e_snonce2; - iov[0 ].iov_len =sizeof (wsc->e_snonce2); + iov[0 ].iov_base = wsc->local_snonce2; + iov[0 ].iov_len =sizeof (wsc->local_snonce2); iov[1 ].iov_base = wsc->psk2; iov[1 ].iov_len =sizeof (wsc->psk2);l_checksum_updatev (wsc->hmac_auth_key, iov,4 );
@@ -1211,9 +1229,70 @@ static bool load_constrained_string(struct l_settings *settings,return true; } -static bool eap_wsc_load_settings (struct eap_state *eap, -struct l_settings *settings, -const char *prefix) +static bool load_device_data (struct l_settings *settings, +char *manufacturer, +char *model_name, +char *model_number, +char *serial_number, +struct wsc_primary_device_type *dev_type, +char *device_name, +uint8_t *rf_bands, +uint32_t *os_version) +{ +struct wsc_m1 *m1; +unsigned int u32; + +if (!load_constrained_string (settings,"Manufacturer" , + manufacturer,sizeof (m1->manufacturer))) +strcpy (manufacturer," " ); + +if (!load_constrained_string (settings,"ModelName" , + model_name,sizeof (m1->model_name))) +strcpy (model_name," " ); + +if (!load_constrained_string (settings,"ModelNumber" , + model_number,sizeof (m1->model_number))) +strcpy (model_number," " ); + +if (!load_constrained_string (settings,"SerialNumber" , + serial_number,sizeof (m1->serial_number))) +strcpy (serial_number," " ); + +if (!load_primary_device_type (settings, dev_type)) { +/* Make ourselves a WFA standard PC by default */ + dev_type->category =1 ; +memcpy (dev_type->oui, wsc_wfa_oui,3 ); + dev_type->oui_type =0x04 ; + dev_type->subcategory =1 ; + } + +if (!load_constrained_string (settings,"DeviceName" , + device_name,sizeof (m1->device_name))) +strcpy (device_name," " ); + +if (!l_settings_get_uint (settings,"WSC" ,"RFBand" , &u32)) +return false; + +switch (u32) { +case WSC_RF_BAND_2_4_GHZ : +case WSC_RF_BAND_5_0_GHZ : +case WSC_RF_BAND_60_GHZ : + *rf_bands = u32; +break ; +default : +return false; + } + +if (!l_settings_get_uint (settings,"WSC" ,"OSVersion" , &u32)) + u32 =0 ; + + *os_version = u32 &0x7fffffff ; + +return true; +} + +static struct eap_wsc_state *eap_wsc_new_common (struct l_settings *settings, +bool registrar) {struct eap_wsc_state *wsc;const char *v;
@@ -1222,9 +1301,12 @@ static bool eap_wsc_load_settings(struct eap_state *eap,unsigned int u32; wsc = l_new(struct eap_wsc_state, 1); + wsc->registrar = registrar; wsc->m1 = l_new(struct wsc_m1, 1); - wsc->m1->version2 = true; + +if (registrar) + wsc->m2 = l_new(struct wsc_m2, 1); v =l_settings_get_value (settings,"WSC" ,"EnrolleeMAC" );if (!v)
@@ -1236,10 +1318,52 @@ static bool eap_wsc_load_settings(struct eap_state *eap,if (!wsc_uuid_from_addr (wsc->m1->addr, wsc->m1->uuid_e)) goto err; -if (!load_hexencoded (settings,"EnrolleeNonce" , - wsc->m1->enrollee_nonce,16 )) -l_getrandom (wsc->m1->enrollee_nonce,16 ); +if (!l_settings_get_uint (settings,"WSC" ,"ConfigurationMethods" , &u32)) + u32 =WSC_CONFIGURATION_METHOD_VIRTUAL_DISPLAY_PIN ; +if (!registrar) + wsc->m1->config_methods = u32; +else + wsc->m2->config_methods = u32; + +if (!l_settings_get_uint (settings,"WSC" ,"DevicePasswordId" , &u32)) + u32 =WSC_DEVICE_PASSWORD_ID_PUSH_BUTTON ; + +if (!registrar) + wsc->m1->device_password_id = u32; +else + wsc->m2->device_password_id = u32; + + wsc->device_password =l_settings_get_string (settings,"WSC" , +"DevicePassword" ); +if (wsc->device_password) { +int i; + +for (i =0 ; wsc->device_password[i]; i++) { +if (!l_ascii_isxdigit (wsc->device_password[i])) + goto err; + } + +/* +* WSC 2.0.5: Section 7.4: +* If an out-of-band mechanism is used as the configuration +* method, the device password is expressed in hexadecimal +* using ASCII character (two characters per octet, uppercase +* letters only). +*/ +for (i =0 ; wsc->device_password[i]; i++) { +if (wsc->device_password[i] >='a' && + wsc->device_password[i] <='f' ) + wsc->device_password[i] = +'A' + wsc->device_password[i] -'a' ; + } + }else + wsc->device_password =l_strdup ("00000000" ); + +/* +* The settings we read below probably shouldn't be used except to +* eliminate randomness in debugging/tests. +*/ if (load_hexencoded(settings, "PrivateKey", private_key, 192)) { if (!l_key_validate_dh_payload(private_key, 192, crypto_dh5_prime,
@@ -1259,12 +1383,48 @@ static bool eap_wsc_load_settings(struct eap_state *eap, len =sizeof (wsc->m1->public_key);if (!l_key_compute_dh_public (dh5_generator, wsc->private, dh5_prime, - wsc->m1->public_key, &len)) + registrar ? wsc->m2->public_key : + wsc->m1->public_key, &len)) goto err;if (len !=sizeof (wsc->m1->public_key)) goto err; +if (!load_hexencoded (settings, registrar ?"R-SNonce1" :"E-SNonce1" , + wsc->local_snonce1,16 )) +l_getrandom (wsc->local_snonce1,16 ); + +if (!load_hexencoded (settings, registrar ?"R-SNonce2" :"E-SNonce2" , + wsc->local_snonce2,16 )) +l_getrandom (wsc->local_snonce2,16 ); + +if (!load_hexencoded (settings,"IV1" , wsc->iv1,16 )) +l_getrandom (wsc->iv1,16 ); + +if (!load_hexencoded (settings,"IV2" , wsc->iv2,16 )) +l_getrandom (wsc->iv2,16 ); + +return wsc; + +err: +eap_wsc_state_free (wsc); +return NULL ; +} + +static bool eap_wsc_load_settings (struct eap_state *eap, +struct l_settings *settings, +const char *prefix) +{ +struct eap_wsc_state *wsc =eap_wsc_new_common (settings, false); + +if (!wsc) +return false; + + wsc->m1->version2 = true; + wsc->m1->state =WSC_STATE_NOT_CONFIGURED ; + wsc->m1->association_state =WSC_ASSOCIATION_STATE_NOT_ASSOCIATED ; + wsc->m1->configuration_error =WSC_CONFIGURATION_ERROR_NO_ERROR ; + wsc->m1->auth_type_flags =WSC_AUTHENTICATION_TYPE_WPA2_PERSONAL |WSC_AUTHENTICATION_TYPE_WPA_PERSONAL |WSC_AUTHENTICATION_TYPE_OPEN ;
@@ -1272,137 +1432,170 @@ static bool eap_wsc_load_settings(struct eap_state *eap,WSC_ENCRYPTION_TYPE_AES_TKIP ; wsc->m1->connection_type_flags =WSC_CONNECTION_TYPE_ESS ; -if (!l_settings_get_uint (settings,"WSC" , -"ConfigurationMethods" , &u32)) - u32 =WSC_CONFIGURATION_METHOD_VIRTUAL_DISPLAY_PIN ; +if (!load_device_data (settings, + wsc->m1->manufacturer, + wsc->m1->model_name, + wsc->m1->model_number, + wsc->m1->serial_number, + &wsc->m1->primary_device_type, + wsc->m1->device_name, + &wsc->m1->rf_bands, + &wsc->m1->os_version)) + goto err; - wsc->m1->config_methods = u32; - wsc->m1->state =WSC_STATE_NOT_CONFIGURED ; +/* Debug settings */ +if (!load_hexencoded (settings,"EnrolleeNonce" , + wsc->m1->enrollee_nonce,16 )) +l_getrandom (wsc->m1->enrollee_nonce,16 ); -if (!load_constrained_string (settings,"Manufacturer" , - wsc->m1->manufacturer,sizeof (wsc->m1->manufacturer))) -strcpy (wsc->m1->manufacturer," " ); + wsc->state =STATE_EXPECT_START ; +eap_set_data (eap, wsc); -if (!load_constrained_string (settings,"ModelName" , - wsc->m1->model_name,sizeof (wsc->m1->model_name))) -strcpy (wsc->m1->model_name," " ); +return true; -if (!load_constrained_string (settings,"ModelNumber" , - wsc->m1->model_number,sizeof (wsc->m1->model_number))) -strcpy (wsc->m1->model_number," " ); +err: +eap_wsc_state_free (wsc); +return false; +} -if (!load_constrained_string (settings,"SerialNumber" , - wsc->m1->serial_number,sizeof (wsc->m1->serial_number))) -strcpy (wsc->m1->serial_number," " ); +static struct eap_method eap_wsc = { + .vendor_id = {0x00 ,0x37 ,0x2a }, + .vendor_type =0x00000001 , + .request_type =EAP_TYPE_EXPANDED , + .exports_msk = true, + .name ="WSC" , + .free = eap_wsc_free, + .handle_request = eap_wsc_handle_request, + .handle_retransmit = eap_wsc_handle_retransmit, + .load_settings = eap_wsc_load_settings, +}; -if (!load_primary_device_type (settings, - &wsc->m1->primary_device_type)) { -/* Make ourselves a WFA standard PC by default */ - wsc->m1->primary_device_type.category =1 ; -memcpy (wsc->m1->primary_device_type.oui, wsc_wfa_oui,3 ); - wsc->m1->primary_device_type.oui_type =0x04 ; - wsc->m1->primary_device_type.subcategory =1 ; - } +static bool eap_wsc_r_load_settings (struct eap_state *eap, +struct l_settings *settings, +const char *prefix) +{ +/* +* On the Registrar we store some information in wsc->m1 for the +* actual M1's validation, and we fill in the elements of M2 +* that don't depend on the data received in M1. +*/ +struct eap_wsc_state *wsc =eap_wsc_new_common (settings, true); +char *str; -if (!load_constrained_string (settings,"DeviceName" , - wsc->m1->device_name,sizeof (wsc->m1->device_name))) -strcpy (wsc->m1->device_name," " ); +if (!wsc) +return false; -if (!l_settings_get_uint (settings,"WSC" ,"RFBand" , &u32)) +if (!load_hexencoded (settings,"UUID-R" , wsc->m2->uuid_r,16 )) goto err; -switch (u32) { -case WSC_RF_BAND_2_4_GHZ : -case WSC_RF_BAND_5_0_GHZ : -case WSC_RF_BAND_60_GHZ : - wsc->m1->rf_bands = u32; -break ; -default : +if (!load_device_data (settings, + wsc->m2->manufacturer, + wsc->m2->model_name, + wsc->m2->model_number, + wsc->m2->serial_number, + &wsc->m2->primary_device_type, + wsc->m2->device_name, + &wsc->m2->rf_bands, + &wsc->m2->os_version)) goto err; - } - wsc->m1->association_state =WSC_ASSOCIATION_STATE_NOT_ASSOCIATED ; - wsc->m1->configuration_error =WSC_CONFIGURATION_ERROR_NO_ERROR ; + wsc->m2->auth_type_flags =0 ; -if (!l_settings_get_uint (settings,"WSC" , -"OSVersion" , &u32)) - u32 =0 ; + str =l_settings_get_string (settings,"WSC" ,"WPA2-SSID" ); +if (str) { +if (strlen (str) >32 ) + goto err; - wsc->m1->os_version = u32 &0x7fffffff ; + wsc->m2->auth_type_flags |= +WSC_AUTHENTICATION_TYPE_WPA2_PERSONAL ; + wsc->m2->encryption_type_flags |=WSC_ENCRYPTION_TYPE_AES_TKIP ; + wsc->wpa2_cred.auth_type = +WSC_AUTHENTICATION_TYPE_WPA2_PERSONAL ; + wsc->wpa2_cred.encryption_type =WSC_ENCRYPTION_TYPE_AES_TKIP ; -if (!l_settings_get_uint (settings,"WSC" ,"DevicePasswordId" , &u32)) - u32 =WSC_DEVICE_PASSWORD_ID_PUSH_BUTTON ; + wsc->wpa2_cred.ssid_len =strlen (str); +memcpy (wsc->wpa2_cred.ssid, str, wsc->wpa2_cred.ssid_len); +l_free (str); - wsc->m1->device_password_id = u32; + str =l_settings_get_string (settings,"WSC" ,"WPA2-Passphrase" ); +if (str) { +size_t len =strlen (str); - wsc->device_password =l_settings_get_string (settings,"WSC" , -"DevicePassword" ); -if (wsc->device_password) { -int i; +if (len <8 || len >63 ) { +explicit_bzero (str, len); + goto err; + } -for (i =0 ; wsc->device_password[i]; i++) { -if (!l_ascii_isxdigit (wsc->device_password[i])) +memcpy (wsc->wpa2_cred.network_key, str, len); + wsc->wpa2_cred.network_key_len = len; +explicit_bzero (str, len); + }else { +uint8_t buf[32 ]; + +if (!load_hexencoded (settings,"WPA2-PSK" , buf,32 )) goto err; - } -/* -* WSC 2.0.5: Section 7.4: -* If an out-of-band mechanism is used as the configuration -* method, the device password is expressed in hexadecimal -* using ASCII character (two characters per octet, uppercase -* letters only). -*/ -for (i =0 ; wsc->device_password[i]; i++) { -if (wsc->device_password[i] >='a' && - wsc->device_password[i] <='f' ) - wsc->device_password[i] = -'A' + wsc->device_password[i] -'a' ; + str =l_util_hexstring (buf,32 ); +explicit_bzero (buf,32 ); +memcpy (wsc->wpa2_cred.network_key, str,64 ); +explicit_bzero (str,64 ); +free (str); + wsc->wpa2_cred.network_key_len =64 ; } - }else - wsc->device_password =l_strdup ("00000000" ); -if (!load_hexencoded (settings,"E-SNonce1" , wsc->e_snonce1,16 )) -l_getrandom (wsc->e_snonce1,16 ); - -if (!load_hexencoded (settings,"E-SNonce2" , wsc->e_snonce2,16 )) -l_getrandom (wsc->e_snonce2,16 ); +memcpy (wsc->wpa2_cred.addr, wsc->m1->addr,6 ); + } -if (!load_hexencoded (settings,"IV1" , wsc->iv1,16 )) -l_getrandom (wsc->iv1,16 ); + str =l_settings_get_string (settings,"WSC" ,"Open-SSID" ); +if (str) { +if (strlen (str) >32 ) + goto err; -if (!load_hexencoded (settings,"IV2" , wsc->iv2,16 )) -l_getrandom (wsc->iv2,16 ); + wsc->m2->auth_type_flags |=WSC_AUTHENTICATION_TYPE_OPEN ; + wsc->m2->encryption_type_flags |=WSC_ENCRYPTION_TYPE_NONE ; + wsc->open_cred.auth_type =WSC_AUTHENTICATION_TYPE_OPEN ; + wsc->open_cred.encryption_type =WSC_ENCRYPTION_TYPE_NONE ; -eap_set_data (eap, wsc); + wsc->open_cred.ssid_len =strlen (str); +memcpy (wsc->open_cred.ssid, str, wsc->open_cred.ssid_len); +l_free (str); -return true; + wsc->open_cred.network_key_len =0 ; -err: -if (wsc->device_password) { -explicit_bzero (wsc->device_password, -strlen (wsc->device_password)); -l_free (wsc->device_password); +memcpy (wsc->open_cred.addr, wsc->m1->addr,6 ); } -if (wsc->private) -l_key_free (wsc->private); +if (!wsc->m2->auth_type_flags) + goto err; -l_free (wsc->m1); -l_free (wsc); + wsc->m2->connection_type_flags =WSC_CONNECTION_TYPE_ESS ; + +/* Debug settings */ +if (!load_hexencoded (settings,"RegistrarNonce" , + wsc->m2->registrar_nonce,16 )) +l_getrandom (wsc->m2->registrar_nonce,16 ); + +if (!load_hexencoded (settings,"IV3" , wsc->iv3,16 )) +l_getrandom (wsc->iv3,16 ); + + wsc->state =STATE_EXPECT_IDENTITY ; +eap_set_data (eap, wsc); +return true; + +err: +eap_wsc_state_free (wsc);return false; } -static struct eap_method eap_wsc = { +static struct eap_method eap_wsc_r = { + .name ="WSC-R" , + .request_type =EAP_TYPE_EXPANDED , .vendor_id = {0x00 ,0x37 ,0x2a }, .vendor_type =0x00000001 , - .request_type =EAP_TYPE_EXPANDED , .exports_msk = true, - .name ="WSC" , .free = eap_wsc_free, - .handle_request = eap_wsc_handle_request, - .handle_retransmit = eap_wsc_handle_retransmit, - .load_settings = eap_wsc_load_settings, + .load_settings = eap_wsc_r_load_settings, };static int eap_wsc_init (void )
@@ -1422,12 +1615,18 @@ static int eap_wsc_init(void) goto fail_prime; r =eap_register_method (&eap_wsc); +if (r) + goto fail_register; + + r =eap_register_method (&eap_wsc_r);if (!r)return 0 ; +eap_unregister_method (&eap_wsc); + +fail_register:l_key_free (dh5_prime); dh5_prime =NULL ; - fail_prime:l_key_free (dh5_generator); dh5_generator =NULL ;
@@ -1440,6 +1639,7 @@ static void eap_wsc_exit(void)l_debug ("" );eap_unregister_method (&eap_wsc); +eap_unregister_method (&eap_wsc_r);l_key_free (dh5_prime);l_key_free (dh5_generator);
Signature · 1 line
2.25.1
PATCH 6/10 eap-wsc: Registrar mode message processing
In reply to Andrew ZaborowskiThis commit has all the changes to extend and generalise the current eap-wsc.c code to handle both the Enrollee and Registrar side of the protocol, reusing existing functions and structures.
--- src/eap-wsc.c | 134 +++++++++++++++++++++++++++++++++++++++----------- src/eap-wsc.h | 1 + 2 files changed, 106 insertions(+), 29 deletions(-)
src/eap-wsc.c +105 -29
@@ -93,6 +93,8 @@ struct eap_wsc_state {uint8_t iv3[16 ];uint8_t psk1[16 ];uint8_t psk2[16 ]; +uint8_t e_hash1[32 ]; +uint8_t e_hash2[32 ];uint8_t r_hash2[32 ];enum state state;struct l_checksum *hmac_auth_key;
@@ -171,22 +173,26 @@ static inline void keywrap_authenticator_put(struct eap_wsc_state *wsc,l_checksum_get_digest (wsc->hmac_auth_key, pdu + len -8 ,8 ); } -static inline bool r_hash_check (struct eap_wsc_state *wsc, -uint8_t *r_snonce, +static inline bool x_hash_check (struct eap_wsc_state *wsc, +uint8_t *x_snonce,uint8_t *psk, -uint8_t *r_hash_expected) +uint8_t *x_hash_expected) {struct iovec iov[4 ]; -uint8_t r_hash[32 ]; +uint8_t hash[32 ];/* * WSC 2.0.5, Section 7.4: +* The Enrollee creates two 128-bit secret nonces, E-S1, E-S2 and +* then computes +* E-Hash1 = HMACAuthKey(E-S1 || PSK1 || PKE || PKR) +* E-Hash2 = HMACAuthKey(E-S2 || PSK2 || PKE || PKR) * The Registrar creates two 128-bit secret nonces, R-S1, R-S2 and * then computes * R-Hash1 = HMACAuthKey(R-S1 || PSK1 || PKE || PKR) * R-Hash2 = HMACAuthKey(R-S2 || PSK2 || PKE || PKR) */ - iov[0 ].iov_base = r_snonce; + iov[0 ].iov_base = x_snonce; iov[0 ].iov_len =16 ; iov[1 ].iov_base = psk; iov[1 ].iov_len =16 ;
@@ -195,9 +201,9 @@ static inline bool r_hash_check(struct eap_wsc_state *wsc, iov[3 ].iov_base = wsc->m2->public_key; iov[3 ].iov_len =sizeof (wsc->m2->public_key);l_checksum_updatev (wsc->hmac_auth_key, iov,4 ); -l_checksum_get_digest (wsc->hmac_auth_key, r_hash,sizeof (r_hash)); +l_checksum_get_digest (wsc->hmac_auth_key, hash,sizeof (hash)); -return !memcmp (r_hash, r_hash_expected,sizeof (r_hash)); +return !memcmp (hash, x_hash_expected,sizeof (hash)); } static uint8_t *encrypted_settings_decrypt(struct eap_wsc_state *wsc,
@@ -331,6 +337,16 @@ static void eap_wsc_free(struct eap_state *eap)eap_wsc_state_free (wsc); } +static void eap_wsc_r_send_start (struct eap_state *eap) +{ +uint8_t buf[EAP_WSC_HEADER_LEN ]; + + buf[12 ] =WSC_OP_START ; + buf[13 ] =0 ; + +eap_method_new_request (eap, buf,EAP_WSC_HEADER_LEN ); +} +static void eap_wsc_send_fragment (struct eap_state *eap) {struct eap_wsc_state *wsc =eap_get_data (eap);
@@ -357,12 +373,16 @@ static void eap_wsc_send_fragment(struct eap_state *eap) }memcpy (buf + header_len, wsc->sent_pdu + wsc->tx_frag_offset, len); -eap_method_respond (eap, buf, header_len + len); + +if (wsc->registrar) +eap_method_new_request (eap, buf, header_len + len); +else +eap_method_respond (eap, buf, header_len + len); wsc->tx_last_frag_len = len; } -static void eap_wsc_send_response (struct eap_state *eap, +static void eap_wsc_send_message (struct eap_state *eap,uint8_t *pdu,size_t pdu_len) {struct eap_wsc_state *wsc =eap_get_data (eap);
@@ -377,7 +397,11 @@ static void eap_wsc_send_response(struct eap_state *eap, buf[13 ] =0 ;memcpy (buf +EAP_WSC_HEADER_LEN , pdu, pdu_len); -eap_method_respond (eap, buf, msg_len); +if (wsc->registrar) +eap_method_new_request (eap, buf, msg_len); +else +eap_method_respond (eap, buf, msg_len); +l_free (buf);return ; }
@@ -418,8 +442,11 @@ static void eap_wsc_send_nack(struct eap_state *eap,return ; nack.version2 = true; -memcpy (nack.enrollee_nonce, wsc->m1->enrollee_nonce, +if (wsc->state !=STATE_EXPECT_M1 ) +memcpy (nack.enrollee_nonce, wsc->m1->enrollee_nonce,sizeof (nack.enrollee_nonce)); +else +memset (nack.enrollee_nonce,0 ,sizeof (nack.enrollee_nonce));if (wsc->m2) memcpy(nack.registrar_nonce, wsc->m2->registrar_nonce,
@@ -437,7 +464,11 @@ static void eap_wsc_send_nack(struct eap_state *eap, buf[13 ] =0 ;memcpy (buf +EAP_WSC_HEADER_LEN , pdu, pdu_len); -eap_method_respond (eap, buf, pdu_len +EAP_WSC_HEADER_LEN ); +if (wsc->registrar) +eap_method_new_request (eap, buf, pdu_len +EAP_WSC_HEADER_LEN ); +else +eap_method_respond (eap, buf, pdu_len +EAP_WSC_HEADER_LEN ); +l_free (pdu); }
@@ -469,12 +500,16 @@ static void eap_wsc_send_done(struct eap_state *eap)static void eap_wsc_send_frag_ack (struct eap_state *eap) { +struct eap_wsc_state *wsc =eap_get_data (eap);uint8_t buf[EAP_WSC_HEADER_LEN ]; buf[12 ] =WSC_OP_FRAG_ACK ; buf[13 ] =0 ; -eap_method_respond (eap, buf,EAP_WSC_HEADER_LEN ); +if (wsc->registrar) +eap_method_new_request (eap, buf,EAP_WSC_HEADER_LEN ); +else +eap_method_respond (eap, buf,EAP_WSC_HEADER_LEN ); } static void eap_wsc_handle_m8(struct eap_state *eap,
@@ -583,7 +618,7 @@ static void eap_wsc_send_m7(struct eap_state *eap,return ;authenticator_put (wsc, m6_pdu, m6_len, pdu, pdu_len); -eap_wsc_send_response (eap, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); wsc->state =STATE_EXPECT_M8 ; }
@@ -628,7 +663,7 @@ static void eap_wsc_handle_m6(struct eap_state *eap, }/* We now have R-SNonce2, verify R-Hash2 stored in eap_wsc_handle_m4 */ -if (!r_hash_check (wsc, m6es.r_snonce2, wsc->psk2, wsc->r_hash2)) { +if (!x_hash_check (wsc, m6es.r_snonce2, wsc->psk2, wsc->r_hash2)) { error =WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE ; goto cleanup; }
@@ -684,7 +719,7 @@ static void eap_wsc_send_m5(struct eap_state *eap,return ;authenticator_put (wsc, m4_pdu, m4_len, pdu, pdu_len); -eap_wsc_send_response (eap, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); wsc->state =STATE_EXPECT_M6 ; }
@@ -729,7 +764,7 @@ static void eap_wsc_handle_m4(struct eap_state *eap, }/* Since we have obtained R-SNonce1, we can now verify R-Hash1. */ -if (!r_hash_check (wsc, m4es.r_snonce1, wsc->psk1, m4.r_hash1)) { +if (!x_hash_check (wsc, m4es.r_snonce1, wsc->psk1, m4.r_hash1)) { error =WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE ; goto cleanup; }
@@ -816,7 +851,7 @@ static void eap_wsc_send_m3(struct eap_state *eap,return ;authenticator_put (wsc, m2_pdu, m2_len, pdu, pdu_len); -eap_wsc_send_response (eap, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); wsc->state =STATE_EXPECT_M4 ; }
@@ -932,7 +967,8 @@ static void eap_wsc_handle_nack(struct eap_state *eap,if (wsc_parse_wsc_nack (pdu, len, &nack) !=0 )return ; -if (memcmp (nack.enrollee_nonce, wsc->m1->enrollee_nonce, +if (wsc->state !=STATE_EXPECT_M1 &&memcmp (nack.enrollee_nonce, + wsc->m1->enrollee_nonce,sizeof (nack.enrollee_nonce)))return ;
@@ -948,10 +984,13 @@ static void eap_wsc_handle_nack(struct eap_state *eap,* to. Our choice is to reflect back what the request error code is * in the response. */ -eap_wsc_send_nack (eap, nack.configuration_error); +if (!wsc->registrar) +eap_wsc_send_nack (eap, nack.configuration_error); + +eap_method_error (eap); } -static void eap_wsc_handle_request (struct eap_state *eap, +static void eap_wsc_handle_message (struct eap_state *eap,const uint8_t *pkt,size_t len) {struct eap_wsc_state *wsc =eap_get_data (eap);
@@ -961,6 +1000,16 @@ static void eap_wsc_handle_request(struct eap_state *eap,size_t pdu_len;size_t rx_header_offset =0 ; +/* +* pkt[0:len] is an EAP-Request packet contents if !wsc->registrar +* and an EAP-Response otherwise. Most of the parsing is going to +* be identical though. +* +* Since we have disjoint sets of enum state values between +* Enrollee and Registrar, most of the time we don't need to look +* at wsc->registrar. +*/ +if (len <2 )return ;
@@ -982,7 +1031,7 @@ static void eap_wsc_handle_request(struct eap_state *eap,if (!pdu)return ; -eap_wsc_send_response (eap, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); wsc->state =STATE_EXPECT_M2 ;return ;case WSC_OP_NACK :
@@ -992,8 +1041,21 @@ static void eap_wsc_handle_request(struct eap_state *eap,eap_wsc_handle_nack (eap, pkt, len);return ;case WSC_OP_ACK : +/* Not used in the in-band Enrollee Registration scenario */ +return ;case WSC_OP_DONE : -/* Should never receive these as Enrollee */ +if (wsc->state !=STATE_EXPECT_DONE ) +return ; + +/* +* Notify higher layers that the registration protocol has +* finished successfully as the EAP result is going to +* always be the same. May not be strictly needed as the +* higher layers get the real confirmation when the enrollee +* uses the credentials on their next connection. +*/ +eap_method_event (eap,EAP_WSC_EVENT_CREDENTIAL_SENT ,NULL ); +eap_method_error (eap);return ;case WSC_OP_FRAG_ACK : if (wsc->tx_last_frag_len &&
@@ -1050,16 +1112,14 @@ static void eap_wsc_handle_request(struct eap_state *eap, }if (flags &WSC_FLAG_MF ) { -if (!wsc->rx_pdu_buf) { -eap_method_error (eap); -return ; - } +if (!wsc->rx_pdu_buf) + goto invalid_frag;eap_wsc_send_frag_ack (eap);return ; }else if (wsc->rx_pdu_buf) {if (wsc->rx_pdu_buf_len != wsc->rx_pdu_buf_offset) { -l_error ("Request fragment pkt size mismatch" ); +l_error ("Message fragment pkt size mismatch" ); goto invalid_frag; }
@@ -1465,7 +1525,7 @@ static struct eap_method eap_wsc = { .exports_msk = true, .name = "WSC", .free = eap_wsc_free, - .handle_request = eap_wsc_handle_request, + .handle_request = eap_wsc_handle_message, .handle_retransmit = eap_wsc_handle_retransmit, .load_settings = eap_wsc_load_settings, };
@@ -1588,6 +1648,20 @@ err:return false; } +static bool eap_wsc_r_validate_identity (struct eap_state *eap, +const char *identity) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); + +if (strcmp (identity,"WFA-SimpleConfig-Enrollee-1-0" )) +return false; + +/* Identity Request/Response done, directly send the WSC_Start */ +eap_wsc_r_send_start (eap); + wsc->state =STATE_EXPECT_M1 ; +return true; +} +static struct eap_method eap_wsc_r = { .name ="WSC-R" , .request_type =EAP_TYPE_EXPANDED ,
@@ -1596,6 +1670,8 @@ static struct eap_method eap_wsc_r = { .exports_msk = true, .free = eap_wsc_free, .load_settings = eap_wsc_r_load_settings, + .validate_identity = eap_wsc_r_validate_identity, + .handle_response = eap_wsc_handle_message, };static int eap_wsc_init (void )
src/eap-wsc.h +1 -0
@@ -22,4 +22,5 @@enum EAP_WSC_EVENT {EAP_WSC_EVENT_CREDENTIAL_OBTAINED =0x0050f200 , +EAP_WSC_EVENT_CREDENTIAL_SENT =0x0050f201 , };
Signature · 1 line
2.25.1
PATCH 7/10 eap-wsc: Handle the M{1,3,5,7} messages
In reply to Andrew ZaborowskiParse, validate and respond to the M1, M3, M5 and M7 messages and send the M2, M4, M6 and M8.
--- src/eap-wsc.c | 496 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 496 insertions(+)
src/eap-wsc.c +496 -0
@@ -958,6 +958,483 @@ clear_keys:explicit_bzero (&keys,sizeof (keys)); } +static void eap_wsc_r_send_m8 (struct eap_state *eap, +const uint8_t *m7_pdu,size_t m7_len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m8_encrypted_settings m8es = {}; +struct wsc_m8 m8; +uint8_t *pdu; +size_t pdu_len; +/* At least: 2 * credential, 12 for Authenticator, 16 for IV + up to 16 pad */ +uint8_t encrypted[1024 ]; +size_t encrypted_len; +bool r; +struct wsc_credential creds[2 ]; +unsigned int creds_cnt =0 ; +unsigned int auth_types = + wsc->m1->auth_type_flags & wsc->m2->auth_type_flags; + +if (auth_types &WSC_AUTHENTICATION_TYPE_OPEN ) +memcpy (&creds[creds_cnt++], &wsc->open_cred, +sizeof (struct wsc_credential )); + +if (auth_types &WSC_AUTHENTICATION_TYPE_WPA2_PERSONAL ) +memcpy (&creds[creds_cnt++], &wsc->wpa2_cred, +sizeof (struct wsc_credential )); + + pdu =wsc_build_m8_encrypted_settings (&m8es, creds, creds_cnt, + &pdu_len); +explicit_bzero (creds, creds_cnt *sizeof (struct wsc_credential )); +if (!pdu) +return ; + +keywrap_authenticator_put (wsc, pdu, pdu_len); + r =encrypted_settings_encrypt (wsc, wsc->iv3, pdu, pdu_len, + encrypted, &encrypted_len); +explicit_bzero (pdu, pdu_len); +l_free (pdu); + +if (!r) +return ; + + m8.version2 = true; +memcpy (m8.enrollee_nonce, wsc->m1->enrollee_nonce, +sizeof (m8.enrollee_nonce)); + + pdu =wsc_build_m8 (&m8, encrypted, encrypted_len, &pdu_len); +if (!pdu) +return ; + +authenticator_put (wsc, m7_pdu, m7_len, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); + wsc->state =STATE_EXPECT_DONE ; +} + +static void eap_wsc_r_handle_m7 (struct eap_state *eap, +const uint8_t *pdu,size_t len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m7 m7; +struct iovec encrypted; +uint8_t *decrypted; +size_t decrypted_len; +struct wsc_m7_encrypted_settings m7es; +enum wsc_configuration_error error =WSC_CONFIGURATION_ERROR_NO_ERROR ; + +/* Spec unclear what to do here, see comments in eap_wsc_send_nack */ +if (wsc_parse_m7 (pdu, len, &m7, &encrypted) !=0 ) + goto send_nack; + +if (memcmp (m7.registrar_nonce, wsc->m2->registrar_nonce, +sizeof (m7.registrar_nonce))) + goto send_nack; + +if (!authenticator_check (wsc, pdu, len)) +return ; + + decrypted =encrypted_settings_decrypt (wsc, encrypted.iov_base, + encrypted.iov_len, + &decrypted_len); +if (!decrypted) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto send_nack; + } + +if (wsc_parse_m7_encrypted_settings (decrypted, decrypted_len, &m7es)) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto cleanup; + } + +if (!keywrap_authenticator_check (wsc, decrypted, decrypted_len)) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto cleanup; + } + +/* We have E-SNonce2, verify E-Hash2 stored in eap_wsc_r_handle_m3 */ +if (!x_hash_check (wsc, m7es.e_snonce2, wsc->psk2, wsc->e_hash2)) { + error =WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE ; + goto cleanup; + } + +eap_wsc_r_send_m8 (eap, pdu, len); + +cleanup: +explicit_bzero (&m7es,sizeof (m7es)); +explicit_bzero (decrypted, decrypted_len); +l_free (decrypted); + +if (!error) +return ; + +send_nack: +eap_wsc_send_nack (eap, error); +} + +static void eap_wsc_r_send_m6 (struct eap_state *eap, +const uint8_t *m5_pdu,size_t m5_len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m6_encrypted_settings m6es; +struct wsc_m6 m6; +uint8_t *pdu; +size_t pdu_len; +/* 20 for SNonce, 12 for Authenticator, 16 for IV + up to 16 pad */ +uint8_t encrypted[64 ]; +size_t encrypted_len; +bool r; + +memcpy (m6es.r_snonce2, wsc->local_snonce2,sizeof (wsc->local_snonce2)); + pdu =wsc_build_m6_encrypted_settings (&m6es, &pdu_len); +explicit_bzero (m6es.r_snonce2,sizeof (wsc->local_snonce2)); +if (!pdu) +return ; + +keywrap_authenticator_put (wsc, pdu, pdu_len); + r =encrypted_settings_encrypt (wsc, wsc->iv2, pdu, pdu_len, + encrypted, &encrypted_len); +explicit_bzero (pdu, pdu_len); +l_free (pdu); + +if (!r) +return ; + + m6.version2 = true; +memcpy (m6.enrollee_nonce, wsc->m1->enrollee_nonce, +sizeof (m6.enrollee_nonce)); + + pdu =wsc_build_m6 (&m6, encrypted, encrypted_len, &pdu_len); +if (!pdu) +return ; + +authenticator_put (wsc, m5_pdu, m5_len, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); + wsc->state =STATE_EXPECT_M7 ; +} + +static void eap_wsc_r_handle_m5 (struct eap_state *eap, +const uint8_t *pdu,size_t len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m5 m5; +struct iovec encrypted; +uint8_t *decrypted; +size_t decrypted_len; +struct wsc_m5_encrypted_settings m5es; +enum wsc_configuration_error error =WSC_CONFIGURATION_ERROR_NO_ERROR ; + +/* Spec unclear what to do here, see comments in eap_wsc_send_nack */ +if (wsc_parse_m5 (pdu, len, &m5, &encrypted) !=0 ) + goto send_nack; + +if (memcmp (m5.registrar_nonce, wsc->m2->registrar_nonce, +sizeof (m5.registrar_nonce))) + goto send_nack; + +if (!authenticator_check (wsc, pdu, len)) +return ; + + decrypted =encrypted_settings_decrypt (wsc, encrypted.iov_base, + encrypted.iov_len, + &decrypted_len); +if (!decrypted) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto send_nack; + } + +if (wsc_parse_m5_encrypted_settings (decrypted, decrypted_len, &m5es)) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto cleanup; + } + +if (!keywrap_authenticator_check (wsc, decrypted, decrypted_len)) { + error =WSC_CONFIGURATION_ERROR_DECRYPTION_CRC_FAILURE ; + goto cleanup; + } + +/* We have E-SNonce1, verify E-Hash1 stored in eap_wsc_r_handle_m3 */ +if (!x_hash_check (wsc, m5es.e_snonce1, wsc->psk1, wsc->e_hash1)) { + error =WSC_CONFIGURATION_ERROR_DEVICE_PASSWORD_AUTH_FAILURE ; + goto cleanup; + } + +eap_wsc_r_send_m6 (eap, pdu, len); + +cleanup: +explicit_bzero (&m5es,sizeof (m5es)); +explicit_bzero (decrypted, decrypted_len); +l_free (decrypted); + +if (!error) +return ; + +send_nack: +eap_wsc_send_nack (eap, error); +} + +static void eap_wsc_r_send_m4 (struct eap_state *eap, +const uint8_t *m3_pdu,size_t m3_len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m4_encrypted_settings m4es; +struct wsc_m4 m4; +uint8_t *pdu; +size_t pdu_len; +/* 20 for SNonce, 12 for Authenticator, 16 for IV + up to 16 pad */ +uint8_t encrypted[64 ]; +size_t encrypted_len; +bool r; +size_t len; +size_t len_half1; +struct iovec iov[4 ]; + +memcpy (m4es.r_snonce1, wsc->local_snonce1,sizeof (wsc->local_snonce1)); + pdu =wsc_build_m4_encrypted_settings (&m4es, &pdu_len); +explicit_bzero (m4es.r_snonce1,sizeof (wsc->local_snonce1)); +if (!pdu) +return ; + +keywrap_authenticator_put (wsc, pdu, pdu_len); + r =encrypted_settings_encrypt (wsc, wsc->iv1, pdu, pdu_len, + encrypted, &encrypted_len); +explicit_bzero (pdu, pdu_len); +l_free (pdu); + +if (!r) +return ; + + len =strlen (wsc->device_password); + +/* WSC 2.0.5, Section 7.4: +* In case the UTF8 representation of the DevicePassword length is an +* odd number (N), the first half of DevicePassword will have length +* of N/2+1 and the second half of the DevicePassword will have length +* of N/2. +*/ + len_half1 = (len +1 ) /2 ; + +l_checksum_update (wsc->hmac_auth_key, wsc->device_password, len_half1); +l_checksum_get_digest (wsc->hmac_auth_key, wsc->psk1,sizeof (wsc->psk1)); + +l_checksum_update (wsc->hmac_auth_key, wsc->device_password + len_half1, + len /2 ); +l_checksum_get_digest (wsc->hmac_auth_key, wsc->psk2,sizeof (wsc->psk2)); + + m4.version2 = true; +memcpy (m4.enrollee_nonce, wsc->m1->enrollee_nonce, +sizeof (m4.enrollee_nonce)); + +/* WSC 2.0.5, Section 7.4: +* The Registrar creates two 128-bit secret nonces, R-S1, R-S2 and then +* computes: +* R-Hash1 = HMACAuthKey(R-S1 || PSK1 || PKE || PKR) +* R-Hash2 = HMACAuthKey(R-S2 || PSK2 || PKE || PKR) +*/ + iov[0 ].iov_base = wsc->local_snonce1; + iov[0 ].iov_len =sizeof (wsc->local_snonce1); + iov[1 ].iov_base = wsc->psk1; + iov[1 ].iov_len =sizeof (wsc->psk1); + iov[2 ].iov_base = wsc->m1->public_key; + iov[2 ].iov_len =sizeof (wsc->m1->public_key); + iov[3 ].iov_base = wsc->m2->public_key; + iov[3 ].iov_len =sizeof (wsc->m2->public_key); +l_checksum_updatev (wsc->hmac_auth_key, iov,4 ); +l_checksum_get_digest (wsc->hmac_auth_key, + m4.r_hash1,sizeof (m4.r_hash1)); + + iov[0 ].iov_base = wsc->local_snonce2; + iov[0 ].iov_len =sizeof (wsc->local_snonce2); + iov[1 ].iov_base = wsc->psk2; + iov[1 ].iov_len =sizeof (wsc->psk2); +l_checksum_updatev (wsc->hmac_auth_key, iov,4 ); +l_checksum_get_digest (wsc->hmac_auth_key, + m4.r_hash2,sizeof (m4.r_hash2)); + + pdu =wsc_build_m4 (&m4, encrypted, encrypted_len, &pdu_len); +if (!pdu) +return ; + +authenticator_put (wsc, m3_pdu, m3_len, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); + wsc->state =STATE_EXPECT_M5 ; +} + +static void eap_wsc_r_handle_m3 (struct eap_state *eap, +const uint8_t *pdu,size_t len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct wsc_m3 m3; + +if (wsc_parse_m3 (pdu, len, &m3) !=0 ) + goto send_nack; + +if (memcmp (m3.registrar_nonce, wsc->m2->registrar_nonce, +sizeof (m3.registrar_nonce))) + goto send_nack; + +if (!authenticator_check (wsc, pdu, len)) +return ; + +/* We can't verify these until we receive the E-S1/E-S2 in M5/M7 */ +memcpy (wsc->e_hash1, m3.e_hash1,sizeof (m3.e_hash1)); +memcpy (wsc->e_hash2, m3.e_hash2,sizeof (m3.e_hash2)); + +eap_wsc_r_send_m4 (eap, pdu, len); +return ; + +send_nack: +/* Spec unclear what to do here, see comments in eap_wsc_send_nack */ +eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR ); +} + +static void eap_wsc_r_send_m2 (struct eap_state *eap, +const uint8_t *m1_pdu,size_t m1_len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +uint8_t *pdu; +size_t pdu_len; + + wsc->m2->version2 = true; +memcpy (wsc->m2->enrollee_nonce, wsc->m1->enrollee_nonce,16 ); + wsc->m2->association_state =WSC_ASSOCIATION_STATE_NOT_ASSOCIATED ; + wsc->m2->configuration_error =WSC_CONFIGURATION_ERROR_NO_ERROR ; + + pdu =wsc_build_m2 (wsc->m2, &pdu_len); +if (!pdu) +return ; + +authenticator_put (wsc, m1_pdu, m1_len, pdu, pdu_len); +eap_wsc_send_message (eap, pdu, pdu_len); + wsc->state =STATE_EXPECT_M3 ; +} + +static void eap_wsc_r_handle_m1 (struct eap_state *eap, +const uint8_t *pdu,size_t len) +{ +struct eap_wsc_state *wsc =eap_get_data (eap); +struct l_key *remote_public; +uint8_t shared_secret[192 ] = {0 }; +size_t shared_secret_len =sizeof (shared_secret); +struct l_checksum *sha256; +uint8_t dhkey[32 ]; +struct l_checksum *hmac_sha256; +struct iovec iov[3 ]; +uint8_t kdk[32 ]; +struct wsc_session_key keys; +bool r; +uint8_t expected_enrollee_mac[6 ]; +uint8_t expected_uuid_e[16 ]; + +memcpy (expected_enrollee_mac, wsc->m1->addr,6 ); +memcpy (expected_uuid_e, wsc->m1->uuid_e,16 ); + +/* Spec unclear what to do here, see comments in eap_wsc_send_nack */ +if (wsc_parse_m1 (pdu, len, wsc->m1) !=0 ) { +eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR ); +return ; + } + +if (memcmp (expected_enrollee_mac, wsc->m1->addr,6 ) || +memcmp (expected_uuid_e, wsc->m1->uuid_e,16 )) { +eap_wsc_send_nack (eap, +WSC_CONFIGURATION_ERROR_MULTIPLE_PBC_SESSIONS_DETECTED ); +eap_method_error (eap); +return ; + } + +if (wsc->m1->state !=WSC_STATE_NOT_CONFIGURED || + !(wsc->m1->auth_type_flags & + wsc->m2->auth_type_flags) || + !(wsc->m1->encryption_type_flags & + wsc->m2->encryption_type_flags) || + !(wsc->m1->connection_type_flags & + wsc->m2->connection_type_flags) || + !(wsc->m1->config_methods & + wsc->m2->config_methods) || + !(wsc->m1->rf_bands & wsc->m2->rf_bands)) { +eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR ); +return ; + } + +if (wsc->m1->configuration_error !=WSC_CONFIGURATION_ERROR_NO_ERROR || + wsc->m1->device_password_id != + wsc->m2->device_password_id) { +eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR ); +return ; + } + +/* m1->request_to_enroll not checked */ + +if (!l_key_validate_dh_payload (wsc->m1->public_key, +sizeof (wsc->m1->public_key), + crypto_dh5_prime, + crypto_dh5_prime_size)) +return ; + +/* +* Done validating the M1, we can now derive the keys for most of +* the rest of the registration protocol. +*/ + + remote_public =l_key_new (L_KEY_RAW , wsc->m1->public_key, +sizeof (wsc->m1->public_key)); +if (!remote_public) +return ; + + r =l_key_compute_dh_secret (remote_public, wsc->private, dh5_prime, + shared_secret, &shared_secret_len); +l_key_free (remote_public); + +if (!r) +return ; + + sha256 =l_checksum_new (L_CHECKSUM_SHA256 ); +if (!sha256) +return ; + +l_checksum_update (sha256, shared_secret, shared_secret_len); +explicit_bzero (shared_secret, shared_secret_len); +l_checksum_get_digest (sha256, dhkey,sizeof (dhkey)); +l_checksum_free (sha256); + + hmac_sha256 =l_checksum_new_hmac (L_CHECKSUM_SHA256 , + dhkey,sizeof (dhkey)); +explicit_bzero (dhkey,sizeof (dhkey)); + +if (!hmac_sha256) +return ; + + iov[0 ].iov_base = wsc->m1->enrollee_nonce; + iov[0 ].iov_len =16 ; + iov[1 ].iov_base = wsc->m1->addr; + iov[1 ].iov_len =6 ; + iov[2 ].iov_base = wsc->m2->registrar_nonce; + iov[2 ].iov_len =16 ; + +l_checksum_updatev (hmac_sha256, iov,3 ); +l_checksum_get_digest (hmac_sha256, kdk,sizeof (kdk)); +l_checksum_free (hmac_sha256); + + r =wsc_kdf (kdk, &keys,sizeof (keys)); +explicit_bzero (kdk,sizeof (kdk)); +if (!r) +return ; + + wsc->hmac_auth_key =l_checksum_new_hmac (L_CHECKSUM_SHA256 , + keys.auth_key, +sizeof (keys.auth_key)); + +/* +* AuthKey is uploaded into the kernel, once we upload KeyWrapKey, +* the keys variable is no longer useful. Make sure to wipe it +*/ + wsc->aes_cbc_128 =l_cipher_new (L_CIPHER_AES_CBC , keys.keywrap_key, +sizeof (keys.keywrap_key)); +explicit_bzero (&keys,sizeof (keys)); + +eap_wsc_r_send_m2 (eap, pdu, len); +} +static void eap_wsc_handle_nack (struct eap_state *eap,const uint8_t *pdu,size_t len) {
@@ -1134,6 +1611,7 @@ static void eap_wsc_handle_message(struct eap_state *eap,return ;switch (wsc->state) { +/* Enrollee state machine */ case STATE_EXPECT_START :return ;case STATE_EXPECT_M2 :
@@ -1151,6 +1629,24 @@ static void eap_wsc_handle_message(struct eap_state *eap,case STATE_FINISHED :eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR );return ; + +/* Registrar state machine */ +case STATE_EXPECT_M1 : +eap_wsc_r_handle_m1 (eap, pkt, len); +break ; +case STATE_EXPECT_M3 : +eap_wsc_r_handle_m3 (eap, pkt, len); +break ; +case STATE_EXPECT_M5 : +eap_wsc_r_handle_m5 (eap, pkt, len); +break ; +case STATE_EXPECT_M7 : +eap_wsc_r_handle_m7 (eap, pkt, len); +break ; +case STATE_EXPECT_IDENTITY : +case STATE_EXPECT_DONE : +eap_wsc_send_nack (eap,WSC_CONFIGURATION_ERROR_NO_ERROR ); +return ; }if (wsc->rx_pdu_buf) {
Signature · 1 line
2.25.1
PATCH 8/10 unit: Add an authenticator-side 4-Way Handshake test
In reply to Andrew ZaborowskiTest the eapol.c code responsible for the access point mode 4-way handshake with correct IEs and PSK on both sides (success scenario).
--- unit/test-eapol.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+)
unit/test-eapol.c +193 -0
@@ -3513,6 +3513,196 @@ static void eapol_ft_handshake_test(const void *data)eapol_exit (); } +struct test_ap_sta_data { +struct handshake_state *ap_hs; +struct handshake_state *sta_hs; +const uint8_t ap_address[6 ]; +const uint8_t sta_address[6 ]; + +uint8_t to_sta_data[1024 ]; +int to_sta_data_len; +uint8_t ap_tk[32 ]; +uint8_t sta_tk[32 ]; +bool ap_success; +bool sta_success; +int to_sta_msg_cnt; +int to_ap_msg_cnt; +struct eapol_sm *ap_sm; +struct eapol_sm *sta_sm; +}; + +static int test_ap_sta_eapol_tx (uint32_t ifindex, +const uint8_t *dest,uint16_t proto, +const struct eapol_frame *ef, +bool noencrypt,void *user_data) +{ +struct test_ap_sta_data *s = user_data; +size_t len =sizeof (struct eapol_header ) + +L_BE16_TO_CPU (ef->header.packet_len); + +assert (ifindex == s->ap_hs->ifindex || ifindex == s->sta_hs->ifindex); +assert (proto ==ETH_P_PAE && !noencrypt); + +if (ifindex == s->ap_hs->ifindex) {/* From AP to STA */ +assert (!memcmp (dest, s->sta_address,6 )); +assert (len <sizeof (s->to_sta_data)); +memcpy (s->to_sta_data, ef, len); + s->to_sta_data_len = len; + s->to_sta_msg_cnt++; +return 0 ; + } + +/* From STA to AP */ +assert (!memcmp (dest, s->ap_address,6 )); + s->to_ap_msg_cnt++; +__eapol_rx_packet (1 , s->sta_address, proto, (const void *) ef, len, + noencrypt); +return 0 ; +} + +static void test_ap_sta_run (struct test_ap_sta_data *s) +{ +eap_init (); +eapol_init (); +__eapol_set_tx_packet_func (test_ap_sta_eapol_tx); +__eapol_set_tx_user_data (s); + + s->ap_success = false; + s->sta_success = false; + s->to_sta_msg_cnt =0 ; + s->to_ap_msg_cnt =0 ; + s->to_sta_data_len =0 , + + s->ap_sm =eapol_sm_new (s->ap_hs); +eapol_register (s->ap_sm); + + s->sta_sm =eapol_sm_new (s->sta_hs); +eapol_register (s->sta_sm); + +eapol_start (s->sta_sm); +eapol_start (s->ap_sm); + +while (s->to_sta_data_len) { +int len = s->to_sta_data_len; + s->to_sta_data_len =0 ; +__eapol_rx_packet (s->sta_hs->ifindex, s->ap_address,ETH_P_PAE , + s->to_sta_data, len, false); + } + +if (s->ap_sm) +eapol_sm_free (s->ap_sm); + +if (s->sta_sm) +eapol_sm_free (s->sta_sm); + +eapol_exit (); +eap_exit (); +} + +struct test_ap_sta_hs { +struct handshake_state super; +struct test_ap_sta_data *s; +}; + +static struct handshake_state *test_ap_sta_hs_new (struct test_ap_sta_data *s, +uint32_t ifindex) +{ + struct test_ap_sta_hs *ths = l_new(struct test_ap_sta_hs, 1); + + ths->super.ifindex = ifindex; + ths->super.free = (void (*)(struct handshake_state *s)) l_free; + ths->s = s; + +return &ths->super; +} + +static bool random_nonce (uint8_t nonce[]) +{ +return l_getrandom (nonce,32 ); +} + +static void test_ap_sta_hs_event (struct handshake_state *hs, +enum handshake_event event, +void *user_data, ...) +{ +assert (event !=HANDSHAKE_EVENT_FAILED ); +} + +static void test_ap_sta_install_tk (struct handshake_state *hs, +const uint8_t *tk,uint32_t cipher) +{ +struct test_ap_sta_hs *ths = + l_container_of(hs, struct test_ap_sta_hs, super); +assert (hs == ths->s->ap_hs || hs == ths->s->sta_hs); +assert (cipher ==CRYPTO_CIPHER_CCMP ); + +if (hs == ths->s->ap_hs) { +assert (!ths->s->ap_success); +memcpy (ths->s->ap_tk, tk,16 ); + ths->s->ap_success = true; + }else { +assert (!ths->s->sta_success); +memcpy (ths->s->sta_tk, tk,16 ); + ths->s->sta_success = true; + } +} + +static void eapol_ap_sta_handshake_test (const void *data) +{ +static const unsigned char ap_rsne[] = { +0x30 ,0x14 ,0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 , +0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 ,0x01 ,0x00 , +0x00 ,0x0f ,0xac ,0x02 ,0x81 ,0x00 }; +static const unsigned char sta_rsne[] = { +0x30 ,0x12 ,0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 , +0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 ,0x01 ,0x00 , +0x00 ,0x0f ,0xac ,0x02 }; +static const char *ssid ="TestWPA2PSK" ; +static const uint8_t psk[32 ] = {/* secretsecret */ +0x6a ,0xa3 ,0xf0 ,0x0b ,0x68 ,0xbd ,0x8b ,0x46 , +0x69 ,0x83 ,0xa5 ,0x29 ,0xa3 ,0xfa ,0x57 ,0x1c , +0x6c ,0x7b ,0x72 ,0x41 ,0x1d ,0xce ,0x33 ,0x02 , +0xa2 ,0x2d ,0xdf ,0x77 ,0xd1 ,0x93 ,0xdb ,0x5f }; +struct test_ap_sta_data s = { + .ap_hs =test_ap_sta_hs_new (&s,1 ), + .sta_hs =test_ap_sta_hs_new (&s,2 ), + .ap_address = {0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 }, + .sta_address = {0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x08 }, + }; + +__handshake_set_get_nonce_func (random_nonce); +__handshake_set_install_tk_func (test_ap_sta_install_tk); +__handshake_set_install_gtk_func (NULL ); + +handshake_state_set_authenticator (s.ap_hs, true); +handshake_state_set_event_func (s.ap_hs, test_ap_sta_hs_event, &s); +handshake_state_set_authenticator_address (s.ap_hs, s.ap_address); +handshake_state_set_supplicant_address (s.ap_hs, s.sta_address); +handshake_state_set_supplicant_ie (s.ap_hs, sta_rsne); +handshake_state_set_authenticator_ie (s.ap_hs, ap_rsne); +handshake_state_set_ssid (s.ap_hs, (void *) ssid,strlen (ssid)); +handshake_state_set_pmk (s.ap_hs, psk,32 ); + +handshake_state_set_authenticator (s.sta_hs, false); +handshake_state_set_event_func (s.sta_hs, test_ap_sta_hs_event, &s); +handshake_state_set_authenticator_address (s.sta_hs, s.ap_address); +handshake_state_set_supplicant_address (s.sta_hs, s.sta_address); +handshake_state_set_supplicant_ie (s.sta_hs, sta_rsne); +handshake_state_set_authenticator_ie (s.sta_hs, ap_rsne); +handshake_state_set_ssid (s.sta_hs, (void *) ssid,strlen (ssid)); +handshake_state_set_pmk (s.sta_hs, psk,32 ); + +test_ap_sta_run (&s); + +handshake_state_free (s.ap_hs); +handshake_state_free (s.sta_hs); +__handshake_set_install_tk_func (NULL ); + +assert (s.ap_success && s.sta_success); +assert (s.to_ap_msg_cnt ==2 && s.to_sta_msg_cnt ==2 ); +assert (!memcmp (s.ap_tk, s.sta_tk,16 )); +} +#define IS_ENABLED (config_macro) _IS_ENABLED1(config_macro)#define _IS_ENABLED1 (config_macro) _IS_ENABLED2(_XXXX##config_macro)#define _XXXX1 _YYYY,
@@ -3653,6 +3843,9 @@ int main(int argc, char *argv[])l_test_add ("EAPoL/FT-Using-PSK 4-Way Handshake" , &eapol_ft_handshake_test,NULL ); +l_test_add ("EAPoL/Supplicant+Authenticator 4-Way Handshake" , + &eapol_ap_sta_handshake_test,NULL ); + done:return l_test_run (); }
Signature · 1 line
2.25.1
PATCH 9/10 unit: Authenticator 4-way handshake error scenario
In reply to Andrew Zaborowski--- unit/test-eapol.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
unit/test-eapol.c +68 -0
@@ -3703,6 +3703,72 @@ static void eapol_ap_sta_handshake_test(const void *data)assert (!memcmp (s.ap_tk, s.sta_tk,16 )); } +static void eapol_ap_sta_handshake_bad_psk_test (const void *data) +{ +static const unsigned char ap_rsne[] = { +0x30 ,0x14 ,0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 , +0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 ,0x01 ,0x00 , +0x00 ,0x0f ,0xac ,0x02 ,0x81 ,0x00 }; +static const unsigned char sta_rsne[] = { +0x30 ,0x12 ,0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 , +0x01 ,0x00 ,0x00 ,0x0f ,0xac ,0x04 ,0x01 ,0x00 , +0x00 ,0x0f ,0xac ,0x02 }; +static const char *ssid ="TestWPA2PSK" ; +static const uint8_t psk1[32 ] = {/* secretsecret */ +0x6a ,0xa3 ,0xf0 ,0x0b ,0x68 ,0xbd ,0x8b ,0x46 , +0x69 ,0x83 ,0xa5 ,0x29 ,0xa3 ,0xfa ,0x57 ,0x1c , +0x6c ,0x7b ,0x72 ,0x41 ,0x1d ,0xce ,0x33 ,0x02 , +0xa2 ,0x2d ,0xdf ,0x77 ,0xd1 ,0x93 ,0xdb ,0x5f }; +static const uint8_t psk2[32 ] = {/* wrongpasswd */ +0x04 ,0x86 ,0x45 ,0x37 ,0x4c ,0x95 ,0xdd ,0x1e , +0x96 ,0xbb ,0xdf ,0x12 ,0x0a ,0x1c ,0x4c ,0x5b , +0x6d ,0x22 ,0xc1 ,0x1c ,0xa2 ,0xe0 ,0x15 ,0x99 , +0xbf ,0x82 ,0x10 ,0xd3 ,0x59 ,0x2c ,0xfb ,0x2d }; +struct test_ap_sta_data s = { + .ap_hs =test_ap_sta_hs_new (&s,1 ), + .sta_hs =test_ap_sta_hs_new (&s,2 ), + .ap_address = {0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 }, + .sta_address = {0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x08 }, + }; + +__handshake_set_get_nonce_func (random_nonce); +__handshake_set_install_tk_func (test_ap_sta_install_tk); +__handshake_set_install_gtk_func (NULL ); + +handshake_state_set_authenticator (s.ap_hs, true); +handshake_state_set_event_func (s.ap_hs, test_ap_sta_hs_event, &s); +handshake_state_set_authenticator_address (s.ap_hs, s.ap_address); +handshake_state_set_supplicant_address (s.ap_hs, s.sta_address); +handshake_state_set_supplicant_ie (s.ap_hs, sta_rsne); +handshake_state_set_authenticator_ie (s.ap_hs, ap_rsne); +handshake_state_set_ssid (s.ap_hs, (void *) ssid,strlen (ssid)); +handshake_state_set_pmk (s.ap_hs, psk1,32 ); + +handshake_state_set_authenticator (s.sta_hs, false); +handshake_state_set_event_func (s.sta_hs, test_ap_sta_hs_event, &s); +handshake_state_set_authenticator_address (s.sta_hs, s.ap_address); +handshake_state_set_supplicant_address (s.sta_hs, s.sta_address); +handshake_state_set_supplicant_ie (s.sta_hs, sta_rsne); +handshake_state_set_authenticator_ie (s.sta_hs, ap_rsne); +handshake_state_set_ssid (s.sta_hs, (void *) ssid,strlen (ssid)); +handshake_state_set_pmk (s.sta_hs, psk2,32 ); + +test_ap_sta_run (&s); + +handshake_state_free (s.ap_hs); +handshake_state_free (s.sta_hs); +__handshake_set_install_tk_func (NULL ); + +/* +* There should have been 2 EAPoL-Key frame exchanged: 1/4 and +* 2/4 after which the AP will have detected wrong MIC and not +* sent any more messages with both sides waiting for the +* timeout. +*/ +assert (!s.ap_success && !s.sta_success); +assert (s.to_ap_msg_cnt ==1 && s.to_sta_msg_cnt ==1 ); +} +#define IS_ENABLED (config_macro) _IS_ENABLED1(config_macro)#define _IS_ENABLED1 (config_macro) _IS_ENABLED2(_XXXX##config_macro)#define _XXXX1 _YYYY,
@@ -3845,6 +3911,8 @@ int main(int argc, char *argv[])l_test_add ("EAPoL/Supplicant+Authenticator 4-Way Handshake" , &eapol_ap_sta_handshake_test,NULL ); +l_test_add ("EAPoL/Supplicant+Authenticator 4-Way Handshake Bad PSK" , + &eapol_ap_sta_handshake_bad_psk_test,NULL ); done:return l_test_run ();
Signature · 1 line
2.25.1
PATCH 10/10 unit: Test a EAP-WSC-R setup in test-eapol
In reply to Andrew Zaborowski--- Makefile.am | 4 +- unit/test-eapol.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-)
Makefile.am +3 -1
@@ -457,7 +457,9 @@ unit_test_eapol_SOURCES = unit/test-eapol.c \ src/eap-md5.c src/util.c \ src/eap-tls-common.h src/eap-tls-common.c \ src/erp.h src/erp.c \ - src/mschaputil.h src/mschaputil.c + src/mschaputil.h src/mschaputil.c \ + src/eap-wsc.h src/eap-wsc.c \ + src/wscutil.h src/wscutil.c unit_test_eapol_LDADD = $(ell_ldadd) unit_test_eapol_DEPENDENCIES = $(ell_dependencies) \ unit/cert-server.pem \
unit/test-eapol.c +166 -0
184 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH 10/10] unit: Test a EAP-WSC-R setup in test-eapol
Hi Andrew,
Quoted 5 lines · Andrew Zaborowski
--- Makefile.am | 4 +- unit/test-eapol.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-)
Hmm, would this not fit better into unit/test-wsc.c instead of test-eapol.c?
Regards,
-Denis
Hi Andrew,
Quoted 6 lines · Andrew Zaborowski
Move the update of
station->networks_sortedorder to before we setstation->connected_networkNULL to avoid a crash when we attempt to use the NULL pointer.--- src/station.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Patches 1-9 applied, thanks.
Regards,
-Denis