diff --git a/unit/test-wsc.c b/unit/test-wsc.c index 983570e2..231a7da4 100644 --- a/unit/test-wsc.c +++ b/unit/test-wsc.c @@ -2261,6 +2261,278 @@ static void wsc_test_pin_generate(const void *data) } } +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; + 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->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_install_tk(struct handshake_state *hs, + const uint8_t *tk, uint32_t cipher) +{ + assert(false); +} + +struct wsc_r_test_success_data { + bool credentials_obtained; + bool credentials_sent; + bool ap_eap_failed; + bool sta_eap_failed; + struct test_ap_sta_data *s; +}; + +static void test_ap_sta_hs_event_ap(struct handshake_state *hs, + enum handshake_event event, + void *user_data, ...) +{ + struct wsc_r_test_success_data *data = user_data; + va_list args; + + va_start(args, user_data); + + switch (event) { + case HANDSHAKE_EVENT_EAP_NOTIFY: + assert(va_arg(args, unsigned int) == + EAP_WSC_EVENT_CREDENTIAL_SENT); + assert(!data->credentials_sent); + assert(!data->ap_eap_failed); + data->credentials_sent = true; + break; + case HANDSHAKE_EVENT_FAILED: + assert(va_arg(args, int) == + MMPDU_REASON_CODE_IEEE8021X_FAILED); + assert(!data->ap_eap_failed); + data->ap_eap_failed = true; + data->s->ap_sm = NULL; + break; + default: + break; + } + + va_end(args); +} + +static void test_ap_sta_hs_event_sta(struct handshake_state *hs, + enum handshake_event event, + void *user_data, ...) +{ + struct wsc_r_test_success_data *data = user_data; + va_list args; + + va_start(args, user_data); + + switch (event) { + case HANDSHAKE_EVENT_EAP_NOTIFY: + { + unsigned int eap_event = va_arg(args, unsigned int); + const struct wsc_credential *cred; + + assert(eap_event == EAP_WSC_EVENT_CREDENTIAL_OBTAINED); + cred = va_arg(args, const struct wsc_credential *); + assert(cred->ssid_len == 7 && + !memcmp(cred->ssid, "thessid", 7)); + assert(cred->auth_type == + WSC_AUTHENTICATION_TYPE_WPA2_PERSONAL); + assert(cred->encryption_type == WSC_ENCRYPTION_TYPE_AES_TKIP); + assert(cred->network_key_len == 12 && + !memcmp(cred->network_key, "secretsecret", 12)); + assert(!memcmp(cred->addr, data->s->sta_address, 6)); + assert(!data->credentials_obtained); + assert(!data->sta_eap_failed); + data->credentials_obtained = true; + break; + } + case HANDSHAKE_EVENT_FAILED: + assert(va_arg(args, int) == + MMPDU_REASON_CODE_IEEE8021X_FAILED); + assert(!data->sta_eap_failed); + data->sta_eap_failed = true; + data->s->sta_sm = NULL; + break; + default: + break; + } + + va_end(args); +} + +static void wsc_r_test_pbc_handshake_wpa2(const void *data) +{ + static const unsigned char ap_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 = "TestWPA2EAP"; + static const char *ap_8021x_str = "[Security]\n" + "EAP-Method=WSC-R\n" + "[WSC]\n" + "UUID-R=00112233445566778899aabbccddeeff\n" + "WPA2-SSID=thessid\n" + "WPA2-Passphrase=secretsecret\n" + "RFBand=1\n" + "ConfigurationMethods=0x680\n"; + static const char *sta_8021x_str = "[Security]\n" + "EAP-Identity=WFA-SimpleConfig-Enrollee-1-0\n" + "EAP-Method=WSC\n" + "[WSC]\n" + "RFBand=1\n" + "ConfigurationMethods=0x680\n"; + struct l_settings *ap_8021x_settings = l_settings_new(); + struct l_settings *sta_8021x_settings = l_settings_new(); + 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 }, + }; + struct wsc_r_test_success_data wsc_data = { + .s = &s, + }; + uint8_t uuid_e[16]; + L_AUTO_FREE_VAR(char *, uuid_e_str) = NULL; + + wsc_uuid_from_addr(s.sta_address, uuid_e); + uuid_e_str = l_util_hexstring(uuid_e, 16); + + __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_ap, + &wsc_data); + 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_authenticator_ie(s.ap_hs, ap_rsne); + handshake_state_set_ssid(s.ap_hs, (void *) ssid, strlen(ssid)); + l_settings_load_from_data(ap_8021x_settings, ap_8021x_str, + strlen(ap_8021x_str)); + l_settings_set_string(ap_8021x_settings, "WSC", "EnrolleeMAC", + util_address_to_string(s.sta_address)); + l_settings_set_string(ap_8021x_settings, "WSC", "UUID-E", uuid_e_str); + handshake_state_set_8021x_config(s.ap_hs, ap_8021x_settings); + + handshake_state_set_authenticator(s.sta_hs, false); + handshake_state_set_event_func(s.sta_hs, test_ap_sta_hs_event_sta, + &wsc_data); + 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_authenticator_ie(s.sta_hs, ap_rsne); + handshake_state_set_ssid(s.sta_hs, (void *) ssid, strlen(ssid)); + l_settings_load_from_data(sta_8021x_settings, sta_8021x_str, + strlen(sta_8021x_str)); + l_settings_set_string(sta_8021x_settings, "WSC", "EnrolleeMAC", + util_address_to_string(s.sta_address)); + handshake_state_set_8021x_config(s.sta_hs, sta_8021x_settings); + + test_ap_sta_run(&s); + + handshake_state_free(s.ap_hs); + handshake_state_free(s.sta_hs); + __handshake_set_install_tk_func(NULL); + l_settings_free(ap_8021x_settings); + l_settings_free(sta_8021x_settings); + + assert(wsc_data.sta_eap_failed && wsc_data.credentials_obtained); + assert(wsc_data.ap_eap_failed && wsc_data.credentials_sent); +} + int main(int argc, char *argv[]) { l_test_init(&argc, &argv); @@ -2374,6 +2646,9 @@ int main(int argc, char *argv[]) l_test_add("/wsc/retransmission/no fragmentation", wsc_test_retransmission_no_fragmentation, NULL); + l_test_add("/wsc-r/handshake/PBC Handshake WPA2 Test", + wsc_r_test_pbc_handshake_wpa2, NULL); + done: return l_test_run(); }