1189251Ssam/* 2189251Ssam * WPA Supplicant - test code 3189251Ssam * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam * 14189251Ssam * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c. 15189251Ssam * Not used in production version. 16189251Ssam */ 17189251Ssam 18189251Ssam#include "includes.h" 19189251Ssam#include <assert.h> 20189251Ssam 21189251Ssam#include "common.h" 22189251Ssam#include "config.h" 23189251Ssam#include "eapol_supp/eapol_supp_sm.h" 24189251Ssam#include "eap_peer/eap.h" 25189251Ssam#include "eloop.h" 26214734Srpaulo#include "rsn_supp/wpa.h" 27189251Ssam#include "eap_peer/eap_i.h" 28189251Ssam#include "wpa_supplicant_i.h" 29189251Ssam#include "radius/radius.h" 30189251Ssam#include "radius/radius_client.h" 31189251Ssam#include "ctrl_iface.h" 32189251Ssam#include "pcsc_funcs.h" 33189251Ssam 34189251Ssam 35189251Ssamextern int wpa_debug_level; 36189251Ssamextern int wpa_debug_show_keys; 37189251Ssam 38214734Srpaulostruct wpa_driver_ops *wpa_drivers[] = { NULL }; 39189251Ssam 40189251Ssam 41189251Ssamstruct extra_radius_attr { 42189251Ssam u8 type; 43189251Ssam char syntax; 44189251Ssam char *data; 45189251Ssam struct extra_radius_attr *next; 46189251Ssam}; 47189251Ssam 48189251Ssamstruct eapol_test_data { 49189251Ssam struct wpa_supplicant *wpa_s; 50189251Ssam 51189251Ssam int eapol_test_num_reauths; 52189251Ssam int no_mppe_keys; 53189251Ssam int num_mppe_ok, num_mppe_mismatch; 54189251Ssam 55189251Ssam u8 radius_identifier; 56189251Ssam struct radius_msg *last_recv_radius; 57189251Ssam struct in_addr own_ip_addr; 58189251Ssam struct radius_client_data *radius; 59189251Ssam struct hostapd_radius_servers *radius_conf; 60189251Ssam 61189251Ssam u8 *last_eap_radius; /* last received EAP Response from Authentication 62189251Ssam * Server */ 63189251Ssam size_t last_eap_radius_len; 64189251Ssam 65189251Ssam u8 authenticator_pmk[PMK_LEN]; 66189251Ssam size_t authenticator_pmk_len; 67189251Ssam int radius_access_accept_received; 68189251Ssam int radius_access_reject_received; 69189251Ssam int auth_timed_out; 70189251Ssam 71189251Ssam u8 *eap_identity; 72189251Ssam size_t eap_identity_len; 73189251Ssam 74189251Ssam char *connect_info; 75189251Ssam u8 own_addr[ETH_ALEN]; 76189251Ssam struct extra_radius_attr *extra_attrs; 77189251Ssam}; 78189251Ssam 79189251Ssamstatic struct eapol_test_data eapol_test; 80189251Ssam 81189251Ssam 82189251Ssamstatic void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx); 83189251Ssam 84189251Ssam 85189251Ssamstatic void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, 86189251Ssam int level, const char *txt, size_t len) 87189251Ssam{ 88189251Ssam if (addr) 89189251Ssam wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n", 90189251Ssam MAC2STR(addr), txt); 91189251Ssam else 92189251Ssam wpa_printf(MSG_DEBUG, "%s", txt); 93189251Ssam} 94189251Ssam 95189251Ssam 96189251Ssamstatic int add_extra_attr(struct radius_msg *msg, 97189251Ssam struct extra_radius_attr *attr) 98189251Ssam{ 99189251Ssam size_t len; 100189251Ssam char *pos; 101189251Ssam u32 val; 102189251Ssam char buf[128]; 103189251Ssam 104189251Ssam switch (attr->syntax) { 105189251Ssam case 's': 106189251Ssam os_snprintf(buf, sizeof(buf), "%s", attr->data); 107189251Ssam len = os_strlen(buf); 108189251Ssam break; 109189251Ssam case 'n': 110189251Ssam buf[0] = '\0'; 111189251Ssam len = 1; 112189251Ssam break; 113189251Ssam case 'x': 114189251Ssam pos = attr->data; 115189251Ssam if (pos[0] == '0' && pos[1] == 'x') 116189251Ssam pos += 2; 117189251Ssam len = os_strlen(pos); 118189251Ssam if ((len & 1) || (len / 2) > sizeof(buf)) { 119189251Ssam printf("Invalid extra attribute hexstring\n"); 120189251Ssam return -1; 121189251Ssam } 122189251Ssam len /= 2; 123189251Ssam if (hexstr2bin(pos, (u8 *) buf, len) < 0) { 124189251Ssam printf("Invalid extra attribute hexstring\n"); 125189251Ssam return -1; 126189251Ssam } 127189251Ssam break; 128189251Ssam case 'd': 129189251Ssam val = htonl(atoi(attr->data)); 130189251Ssam os_memcpy(buf, &val, 4); 131189251Ssam len = 4; 132189251Ssam break; 133189251Ssam default: 134189251Ssam printf("Incorrect extra attribute syntax specification\n"); 135189251Ssam return -1; 136189251Ssam } 137189251Ssam 138189251Ssam if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) { 139189251Ssam printf("Could not add attribute %d\n", attr->type); 140189251Ssam return -1; 141189251Ssam } 142189251Ssam 143189251Ssam return 0; 144189251Ssam} 145189251Ssam 146189251Ssam 147189251Ssamstatic int add_extra_attrs(struct radius_msg *msg, 148189251Ssam struct extra_radius_attr *attrs) 149189251Ssam{ 150189251Ssam struct extra_radius_attr *p; 151189251Ssam for (p = attrs; p; p = p->next) { 152189251Ssam if (add_extra_attr(msg, p) < 0) 153189251Ssam return -1; 154189251Ssam } 155189251Ssam return 0; 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamstatic struct extra_radius_attr * 160189251Ssamfind_extra_attr(struct extra_radius_attr *attrs, u8 type) 161189251Ssam{ 162189251Ssam struct extra_radius_attr *p; 163189251Ssam for (p = attrs; p; p = p->next) { 164189251Ssam if (p->type == type) 165189251Ssam return p; 166189251Ssam } 167189251Ssam return NULL; 168189251Ssam} 169189251Ssam 170189251Ssam 171189251Ssamstatic void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, 172189251Ssam const u8 *eap, size_t len) 173189251Ssam{ 174189251Ssam struct radius_msg *msg; 175189251Ssam char buf[128]; 176189251Ssam const struct eap_hdr *hdr; 177189251Ssam const u8 *pos; 178189251Ssam 179189251Ssam wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 180189251Ssam "packet"); 181189251Ssam 182189251Ssam e->radius_identifier = radius_client_get_id(e->radius); 183189251Ssam msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 184189251Ssam e->radius_identifier); 185189251Ssam if (msg == NULL) { 186189251Ssam printf("Could not create net RADIUS packet\n"); 187189251Ssam return; 188189251Ssam } 189189251Ssam 190189251Ssam radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); 191189251Ssam 192189251Ssam hdr = (const struct eap_hdr *) eap; 193189251Ssam pos = (const u8 *) (hdr + 1); 194189251Ssam if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && 195189251Ssam pos[0] == EAP_TYPE_IDENTITY) { 196189251Ssam pos++; 197189251Ssam os_free(e->eap_identity); 198189251Ssam e->eap_identity_len = len - sizeof(*hdr) - 1; 199189251Ssam e->eap_identity = os_malloc(e->eap_identity_len); 200189251Ssam if (e->eap_identity) { 201189251Ssam os_memcpy(e->eap_identity, pos, e->eap_identity_len); 202189251Ssam wpa_hexdump(MSG_DEBUG, "Learned identity from " 203189251Ssam "EAP-Response-Identity", 204189251Ssam e->eap_identity, e->eap_identity_len); 205189251Ssam } 206189251Ssam } 207189251Ssam 208189251Ssam if (e->eap_identity && 209189251Ssam !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 210189251Ssam e->eap_identity, e->eap_identity_len)) { 211189251Ssam printf("Could not add User-Name\n"); 212189251Ssam goto fail; 213189251Ssam } 214189251Ssam 215189251Ssam if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && 216189251Ssam !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 217189251Ssam (u8 *) &e->own_ip_addr, 4)) { 218189251Ssam printf("Could not add NAS-IP-Address\n"); 219189251Ssam goto fail; 220189251Ssam } 221189251Ssam 222189251Ssam os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 223189251Ssam MAC2STR(e->wpa_s->own_addr)); 224189251Ssam if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) 225189251Ssam && 226189251Ssam !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 227189251Ssam (u8 *) buf, os_strlen(buf))) { 228189251Ssam printf("Could not add Calling-Station-Id\n"); 229189251Ssam goto fail; 230189251Ssam } 231189251Ssam 232189251Ssam /* TODO: should probably check MTU from driver config; 2304 is max for 233189251Ssam * IEEE 802.11, but use 1400 to avoid problems with too large packets 234189251Ssam */ 235189251Ssam if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && 236189251Ssam !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 237189251Ssam printf("Could not add Framed-MTU\n"); 238189251Ssam goto fail; 239189251Ssam } 240189251Ssam 241189251Ssam if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && 242189251Ssam !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 243189251Ssam RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 244189251Ssam printf("Could not add NAS-Port-Type\n"); 245189251Ssam goto fail; 246189251Ssam } 247189251Ssam 248189251Ssam os_snprintf(buf, sizeof(buf), "%s", e->connect_info); 249189251Ssam if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && 250189251Ssam !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 251189251Ssam (u8 *) buf, os_strlen(buf))) { 252189251Ssam printf("Could not add Connect-Info\n"); 253189251Ssam goto fail; 254189251Ssam } 255189251Ssam 256189251Ssam if (add_extra_attrs(msg, e->extra_attrs) < 0) 257189251Ssam goto fail; 258189251Ssam 259189251Ssam if (eap && !radius_msg_add_eap(msg, eap, len)) { 260189251Ssam printf("Could not add EAP-Message\n"); 261189251Ssam goto fail; 262189251Ssam } 263189251Ssam 264189251Ssam /* State attribute must be copied if and only if this packet is 265189251Ssam * Access-Request reply to the previous Access-Challenge */ 266214734Srpaulo if (e->last_recv_radius && 267214734Srpaulo radius_msg_get_hdr(e->last_recv_radius)->code == 268189251Ssam RADIUS_CODE_ACCESS_CHALLENGE) { 269189251Ssam int res = radius_msg_copy_attr(msg, e->last_recv_radius, 270189251Ssam RADIUS_ATTR_STATE); 271189251Ssam if (res < 0) { 272189251Ssam printf("Could not copy State attribute from previous " 273189251Ssam "Access-Challenge\n"); 274189251Ssam goto fail; 275189251Ssam } 276189251Ssam if (res > 0) { 277189251Ssam wpa_printf(MSG_DEBUG, " Copied RADIUS State " 278189251Ssam "Attribute"); 279189251Ssam } 280189251Ssam } 281189251Ssam 282189251Ssam radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr); 283189251Ssam return; 284189251Ssam 285189251Ssam fail: 286189251Ssam radius_msg_free(msg); 287189251Ssam} 288189251Ssam 289189251Ssam 290189251Ssamstatic int eapol_test_eapol_send(void *ctx, int type, const u8 *buf, 291189251Ssam size_t len) 292189251Ssam{ 293189251Ssam /* struct wpa_supplicant *wpa_s = ctx; */ 294189251Ssam printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n", 295189251Ssam type, (unsigned long) len); 296189251Ssam if (type == IEEE802_1X_TYPE_EAP_PACKET) { 297189251Ssam wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len); 298189251Ssam ieee802_1x_encapsulate_radius(&eapol_test, buf, len); 299189251Ssam } 300189251Ssam return 0; 301189251Ssam} 302189251Ssam 303189251Ssam 304189251Ssamstatic void eapol_test_set_config_blob(void *ctx, 305189251Ssam struct wpa_config_blob *blob) 306189251Ssam{ 307189251Ssam struct wpa_supplicant *wpa_s = ctx; 308189251Ssam wpa_config_set_blob(wpa_s->conf, blob); 309189251Ssam} 310189251Ssam 311189251Ssam 312189251Ssamstatic const struct wpa_config_blob * 313189251Ssameapol_test_get_config_blob(void *ctx, const char *name) 314189251Ssam{ 315189251Ssam struct wpa_supplicant *wpa_s = ctx; 316189251Ssam return wpa_config_get_blob(wpa_s->conf, name); 317189251Ssam} 318189251Ssam 319189251Ssam 320189251Ssamstatic void eapol_test_eapol_done_cb(void *ctx) 321189251Ssam{ 322189251Ssam printf("WPA: EAPOL processing complete\n"); 323189251Ssam} 324189251Ssam 325189251Ssam 326189251Ssamstatic void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx) 327189251Ssam{ 328189251Ssam struct eapol_test_data *e = eloop_ctx; 329189251Ssam printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n"); 330189251Ssam e->radius_access_accept_received = 0; 331189251Ssam send_eap_request_identity(e->wpa_s, NULL); 332189251Ssam} 333189251Ssam 334189251Ssam 335189251Ssamstatic int eapol_test_compare_pmk(struct eapol_test_data *e) 336189251Ssam{ 337189251Ssam u8 pmk[PMK_LEN]; 338189251Ssam int ret = 1; 339189251Ssam 340189251Ssam if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) { 341189251Ssam wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN); 342189251Ssam if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) { 343189251Ssam printf("WARNING: PMK mismatch\n"); 344189251Ssam wpa_hexdump(MSG_DEBUG, "PMK from AS", 345189251Ssam e->authenticator_pmk, PMK_LEN); 346189251Ssam } else if (e->radius_access_accept_received) 347189251Ssam ret = 0; 348189251Ssam } else if (e->authenticator_pmk_len == 16 && 349189251Ssam eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) { 350189251Ssam wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16); 351189251Ssam if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) { 352189251Ssam printf("WARNING: PMK mismatch\n"); 353189251Ssam wpa_hexdump(MSG_DEBUG, "PMK from AS", 354189251Ssam e->authenticator_pmk, 16); 355189251Ssam } else if (e->radius_access_accept_received) 356189251Ssam ret = 0; 357189251Ssam } else if (e->radius_access_accept_received && e->no_mppe_keys) { 358189251Ssam /* No keying material expected */ 359189251Ssam ret = 0; 360189251Ssam } 361189251Ssam 362189251Ssam if (ret && !e->no_mppe_keys) 363189251Ssam e->num_mppe_mismatch++; 364189251Ssam else if (!e->no_mppe_keys) 365189251Ssam e->num_mppe_ok++; 366189251Ssam 367189251Ssam return ret; 368189251Ssam} 369189251Ssam 370189251Ssam 371189251Ssamstatic void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx) 372189251Ssam{ 373189251Ssam struct eapol_test_data *e = ctx; 374189251Ssam printf("eapol_sm_cb: success=%d\n", success); 375189251Ssam e->eapol_test_num_reauths--; 376189251Ssam if (e->eapol_test_num_reauths < 0) 377189251Ssam eloop_terminate(); 378189251Ssam else { 379189251Ssam eapol_test_compare_pmk(e); 380189251Ssam eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL); 381189251Ssam } 382189251Ssam} 383189251Ssam 384189251Ssam 385189251Ssamstatic int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, 386189251Ssam struct wpa_ssid *ssid) 387189251Ssam{ 388189251Ssam struct eapol_config eapol_conf; 389189251Ssam struct eapol_ctx *ctx; 390189251Ssam 391189251Ssam ctx = os_zalloc(sizeof(*ctx)); 392189251Ssam if (ctx == NULL) { 393189251Ssam printf("Failed to allocate EAPOL context.\n"); 394189251Ssam return -1; 395189251Ssam } 396189251Ssam ctx->ctx = wpa_s; 397189251Ssam ctx->msg_ctx = wpa_s; 398189251Ssam ctx->scard_ctx = wpa_s->scard; 399189251Ssam ctx->cb = eapol_sm_cb; 400189251Ssam ctx->cb_ctx = e; 401189251Ssam ctx->eapol_send_ctx = wpa_s; 402189251Ssam ctx->preauth = 0; 403189251Ssam ctx->eapol_done_cb = eapol_test_eapol_done_cb; 404189251Ssam ctx->eapol_send = eapol_test_eapol_send; 405189251Ssam ctx->set_config_blob = eapol_test_set_config_blob; 406189251Ssam ctx->get_config_blob = eapol_test_get_config_blob; 407189251Ssam ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; 408189251Ssam ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; 409189251Ssam ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; 410189251Ssam 411189251Ssam wpa_s->eapol = eapol_sm_init(ctx); 412189251Ssam if (wpa_s->eapol == NULL) { 413189251Ssam os_free(ctx); 414189251Ssam printf("Failed to initialize EAPOL state machines.\n"); 415189251Ssam return -1; 416189251Ssam } 417189251Ssam 418189251Ssam wpa_s->current_ssid = ssid; 419189251Ssam os_memset(&eapol_conf, 0, sizeof(eapol_conf)); 420189251Ssam eapol_conf.accept_802_1x_keys = 1; 421189251Ssam eapol_conf.required_keys = 0; 422189251Ssam eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; 423189251Ssam eapol_conf.workaround = ssid->eap_workaround; 424189251Ssam eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); 425189251Ssam eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); 426189251Ssam 427189251Ssam 428189251Ssam eapol_sm_notify_portValid(wpa_s->eapol, FALSE); 429189251Ssam /* 802.1X::portControl = Auto */ 430189251Ssam eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); 431189251Ssam 432189251Ssam return 0; 433189251Ssam} 434189251Ssam 435189251Ssam 436189251Ssamstatic void test_eapol_clean(struct eapol_test_data *e, 437189251Ssam struct wpa_supplicant *wpa_s) 438189251Ssam{ 439189251Ssam struct extra_radius_attr *p, *prev; 440189251Ssam 441189251Ssam radius_client_deinit(e->radius); 442189251Ssam os_free(e->last_eap_radius); 443214734Srpaulo radius_msg_free(e->last_recv_radius); 444214734Srpaulo e->last_recv_radius = NULL; 445189251Ssam os_free(e->eap_identity); 446189251Ssam e->eap_identity = NULL; 447189251Ssam eapol_sm_deinit(wpa_s->eapol); 448189251Ssam wpa_s->eapol = NULL; 449189251Ssam if (e->radius_conf && e->radius_conf->auth_server) { 450189251Ssam os_free(e->radius_conf->auth_server->shared_secret); 451189251Ssam os_free(e->radius_conf->auth_server); 452189251Ssam } 453189251Ssam os_free(e->radius_conf); 454189251Ssam e->radius_conf = NULL; 455189251Ssam scard_deinit(wpa_s->scard); 456189251Ssam if (wpa_s->ctrl_iface) { 457189251Ssam wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); 458189251Ssam wpa_s->ctrl_iface = NULL; 459189251Ssam } 460189251Ssam wpa_config_free(wpa_s->conf); 461189251Ssam 462189251Ssam p = e->extra_attrs; 463189251Ssam while (p) { 464189251Ssam prev = p; 465189251Ssam p = p->next; 466189251Ssam os_free(prev); 467189251Ssam } 468189251Ssam} 469189251Ssam 470189251Ssam 471189251Ssamstatic void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx) 472189251Ssam{ 473189251Ssam struct wpa_supplicant *wpa_s = eloop_ctx; 474189251Ssam u8 buf[100], *pos; 475189251Ssam struct ieee802_1x_hdr *hdr; 476189251Ssam struct eap_hdr *eap; 477189251Ssam 478189251Ssam hdr = (struct ieee802_1x_hdr *) buf; 479189251Ssam hdr->version = EAPOL_VERSION; 480189251Ssam hdr->type = IEEE802_1X_TYPE_EAP_PACKET; 481189251Ssam hdr->length = htons(5); 482189251Ssam 483189251Ssam eap = (struct eap_hdr *) (hdr + 1); 484189251Ssam eap->code = EAP_CODE_REQUEST; 485189251Ssam eap->identifier = 0; 486189251Ssam eap->length = htons(5); 487189251Ssam pos = (u8 *) (eap + 1); 488189251Ssam *pos = EAP_TYPE_IDENTITY; 489189251Ssam 490189251Ssam printf("Sending fake EAP-Request-Identity\n"); 491189251Ssam eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf, 492189251Ssam sizeof(*hdr) + 5); 493189251Ssam} 494189251Ssam 495189251Ssam 496189251Ssamstatic void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx) 497189251Ssam{ 498189251Ssam struct eapol_test_data *e = eloop_ctx; 499189251Ssam printf("EAPOL test timed out\n"); 500189251Ssam e->auth_timed_out = 1; 501189251Ssam eloop_terminate(); 502189251Ssam} 503189251Ssam 504189251Ssam 505189251Ssamstatic char *eap_type_text(u8 type) 506189251Ssam{ 507189251Ssam switch (type) { 508189251Ssam case EAP_TYPE_IDENTITY: return "Identity"; 509189251Ssam case EAP_TYPE_NOTIFICATION: return "Notification"; 510189251Ssam case EAP_TYPE_NAK: return "Nak"; 511189251Ssam case EAP_TYPE_TLS: return "TLS"; 512189251Ssam case EAP_TYPE_TTLS: return "TTLS"; 513189251Ssam case EAP_TYPE_PEAP: return "PEAP"; 514189251Ssam case EAP_TYPE_SIM: return "SIM"; 515189251Ssam case EAP_TYPE_GTC: return "GTC"; 516189251Ssam case EAP_TYPE_MD5: return "MD5"; 517189251Ssam case EAP_TYPE_OTP: return "OTP"; 518189251Ssam case EAP_TYPE_FAST: return "FAST"; 519189251Ssam case EAP_TYPE_SAKE: return "SAKE"; 520189251Ssam case EAP_TYPE_PSK: return "PSK"; 521189251Ssam default: return "Unknown"; 522189251Ssam } 523189251Ssam} 524189251Ssam 525189251Ssam 526189251Ssamstatic void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) 527189251Ssam{ 528189251Ssam u8 *eap; 529189251Ssam size_t len; 530189251Ssam struct eap_hdr *hdr; 531189251Ssam int eap_type = -1; 532189251Ssam char buf[64]; 533189251Ssam struct radius_msg *msg; 534189251Ssam 535189251Ssam if (e->last_recv_radius == NULL) 536189251Ssam return; 537189251Ssam 538189251Ssam msg = e->last_recv_radius; 539189251Ssam 540189251Ssam eap = radius_msg_get_eap(msg, &len); 541189251Ssam if (eap == NULL) { 542189251Ssam /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: 543189251Ssam * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 544189251Ssam * attribute */ 545189251Ssam wpa_printf(MSG_DEBUG, "could not extract " 546189251Ssam "EAP-Message from RADIUS message"); 547189251Ssam os_free(e->last_eap_radius); 548189251Ssam e->last_eap_radius = NULL; 549189251Ssam e->last_eap_radius_len = 0; 550189251Ssam return; 551189251Ssam } 552189251Ssam 553189251Ssam if (len < sizeof(*hdr)) { 554189251Ssam wpa_printf(MSG_DEBUG, "too short EAP packet " 555189251Ssam "received from authentication server"); 556189251Ssam os_free(eap); 557189251Ssam return; 558189251Ssam } 559189251Ssam 560189251Ssam if (len > sizeof(*hdr)) 561189251Ssam eap_type = eap[sizeof(*hdr)]; 562189251Ssam 563189251Ssam hdr = (struct eap_hdr *) eap; 564189251Ssam switch (hdr->code) { 565189251Ssam case EAP_CODE_REQUEST: 566189251Ssam os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 567189251Ssam eap_type >= 0 ? eap_type_text(eap_type) : "??", 568189251Ssam eap_type); 569189251Ssam break; 570189251Ssam case EAP_CODE_RESPONSE: 571189251Ssam os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 572189251Ssam eap_type >= 0 ? eap_type_text(eap_type) : "??", 573189251Ssam eap_type); 574189251Ssam break; 575189251Ssam case EAP_CODE_SUCCESS: 576189251Ssam os_strlcpy(buf, "EAP Success", sizeof(buf)); 577189251Ssam /* LEAP uses EAP Success within an authentication, so must not 578189251Ssam * stop here with eloop_terminate(); */ 579189251Ssam break; 580189251Ssam case EAP_CODE_FAILURE: 581189251Ssam os_strlcpy(buf, "EAP Failure", sizeof(buf)); 582189251Ssam eloop_terminate(); 583189251Ssam break; 584189251Ssam default: 585189251Ssam os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 586189251Ssam wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len); 587189251Ssam break; 588189251Ssam } 589189251Ssam wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " 590189251Ssam "id=%d len=%d) from RADIUS server: %s", 591189251Ssam hdr->code, hdr->identifier, ntohs(hdr->length), buf); 592189251Ssam 593189251Ssam /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ 594189251Ssam 595189251Ssam os_free(e->last_eap_radius); 596189251Ssam e->last_eap_radius = eap; 597189251Ssam e->last_eap_radius_len = len; 598189251Ssam 599189251Ssam { 600189251Ssam struct ieee802_1x_hdr *dot1x; 601189251Ssam dot1x = os_malloc(sizeof(*dot1x) + len); 602189251Ssam assert(dot1x != NULL); 603189251Ssam dot1x->version = EAPOL_VERSION; 604189251Ssam dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; 605189251Ssam dot1x->length = htons(len); 606189251Ssam os_memcpy((u8 *) (dot1x + 1), eap, len); 607189251Ssam eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, 608189251Ssam (u8 *) dot1x, sizeof(*dot1x) + len); 609189251Ssam os_free(dot1x); 610189251Ssam } 611189251Ssam} 612189251Ssam 613189251Ssam 614189251Ssamstatic void ieee802_1x_get_keys(struct eapol_test_data *e, 615189251Ssam struct radius_msg *msg, struct radius_msg *req, 616209158Srpaulo const u8 *shared_secret, 617209158Srpaulo size_t shared_secret_len) 618189251Ssam{ 619189251Ssam struct radius_ms_mppe_keys *keys; 620189251Ssam 621189251Ssam keys = radius_msg_get_ms_keys(msg, req, shared_secret, 622189251Ssam shared_secret_len); 623189251Ssam if (keys && keys->send == NULL && keys->recv == NULL) { 624189251Ssam os_free(keys); 625189251Ssam keys = radius_msg_get_cisco_keys(msg, req, shared_secret, 626189251Ssam shared_secret_len); 627189251Ssam } 628189251Ssam 629189251Ssam if (keys) { 630189251Ssam if (keys->send) { 631189251Ssam wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)", 632189251Ssam keys->send, keys->send_len); 633189251Ssam } 634189251Ssam if (keys->recv) { 635189251Ssam wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)", 636189251Ssam keys->recv, keys->recv_len); 637189251Ssam e->authenticator_pmk_len = 638189251Ssam keys->recv_len > PMK_LEN ? PMK_LEN : 639189251Ssam keys->recv_len; 640189251Ssam os_memcpy(e->authenticator_pmk, keys->recv, 641189251Ssam e->authenticator_pmk_len); 642189251Ssam if (e->authenticator_pmk_len == 16 && keys->send && 643189251Ssam keys->send_len == 16) { 644189251Ssam /* MS-CHAP-v2 derives 16 octet keys */ 645189251Ssam wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key " 646189251Ssam "to extend PMK to 32 octets"); 647189251Ssam os_memcpy(e->authenticator_pmk + 648189251Ssam e->authenticator_pmk_len, 649189251Ssam keys->send, keys->send_len); 650189251Ssam e->authenticator_pmk_len += keys->send_len; 651189251Ssam } 652189251Ssam } 653189251Ssam 654189251Ssam os_free(keys->send); 655189251Ssam os_free(keys->recv); 656189251Ssam os_free(keys); 657189251Ssam } 658189251Ssam} 659189251Ssam 660189251Ssam 661189251Ssam/* Process the RADIUS frames from Authentication Server */ 662189251Ssamstatic RadiusRxResult 663189251Ssamieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 664209158Srpaulo const u8 *shared_secret, size_t shared_secret_len, 665189251Ssam void *data) 666189251Ssam{ 667189251Ssam struct eapol_test_data *e = data; 668214734Srpaulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 669189251Ssam 670189251Ssam /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 671189251Ssam * present when packet contains an EAP-Message attribute */ 672214734Srpaulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 673189251Ssam radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 674189251Ssam 0) < 0 && 675189251Ssam radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 676189251Ssam wpa_printf(MSG_DEBUG, "Allowing RADIUS " 677189251Ssam "Access-Reject without Message-Authenticator " 678189251Ssam "since it does not include EAP-Message\n"); 679189251Ssam } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 680189251Ssam req, 1)) { 681189251Ssam printf("Incoming RADIUS packet did not have correct " 682189251Ssam "Message-Authenticator - dropped\n"); 683189251Ssam return RADIUS_RX_UNKNOWN; 684189251Ssam } 685189251Ssam 686214734Srpaulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 687214734Srpaulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 688214734Srpaulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 689189251Ssam printf("Unknown RADIUS message code\n"); 690189251Ssam return RADIUS_RX_UNKNOWN; 691189251Ssam } 692189251Ssam 693189251Ssam e->radius_identifier = -1; 694189251Ssam wpa_printf(MSG_DEBUG, "RADIUS packet matching with station"); 695189251Ssam 696214734Srpaulo radius_msg_free(e->last_recv_radius); 697189251Ssam e->last_recv_radius = msg; 698189251Ssam 699214734Srpaulo switch (hdr->code) { 700189251Ssam case RADIUS_CODE_ACCESS_ACCEPT: 701189251Ssam e->radius_access_accept_received = 1; 702189251Ssam ieee802_1x_get_keys(e, msg, req, shared_secret, 703189251Ssam shared_secret_len); 704189251Ssam break; 705189251Ssam case RADIUS_CODE_ACCESS_REJECT: 706189251Ssam e->radius_access_reject_received = 1; 707189251Ssam break; 708189251Ssam } 709189251Ssam 710189251Ssam ieee802_1x_decapsulate_radius(e); 711189251Ssam 712214734Srpaulo if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 713189251Ssam e->eapol_test_num_reauths < 0) || 714214734Srpaulo hdr->code == RADIUS_CODE_ACCESS_REJECT) { 715189251Ssam eloop_terminate(); 716189251Ssam } 717189251Ssam 718189251Ssam return RADIUS_RX_QUEUED; 719189251Ssam} 720189251Ssam 721189251Ssam 722189251Ssamstatic void wpa_init_conf(struct eapol_test_data *e, 723189251Ssam struct wpa_supplicant *wpa_s, const char *authsrv, 724189251Ssam int port, const char *secret, 725189251Ssam const char *cli_addr) 726189251Ssam{ 727189251Ssam struct hostapd_radius_server *as; 728189251Ssam int res; 729189251Ssam 730189251Ssam wpa_s->bssid[5] = 1; 731189251Ssam os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN); 732189251Ssam e->own_ip_addr.s_addr = htonl((127 << 24) | 1); 733189251Ssam os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname)); 734189251Ssam 735189251Ssam e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers)); 736189251Ssam assert(e->radius_conf != NULL); 737189251Ssam e->radius_conf->num_auth_servers = 1; 738189251Ssam as = os_zalloc(sizeof(struct hostapd_radius_server)); 739189251Ssam assert(as != NULL); 740189251Ssam#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) 741189251Ssam { 742189251Ssam int a[4]; 743189251Ssam u8 *pos; 744189251Ssam sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); 745189251Ssam pos = (u8 *) &as->addr.u.v4; 746189251Ssam *pos++ = a[0]; 747189251Ssam *pos++ = a[1]; 748189251Ssam *pos++ = a[2]; 749189251Ssam *pos++ = a[3]; 750189251Ssam } 751189251Ssam#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ 752189251Ssam inet_aton(authsrv, &as->addr.u.v4); 753189251Ssam#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ 754189251Ssam as->addr.af = AF_INET; 755189251Ssam as->port = port; 756189251Ssam as->shared_secret = (u8 *) os_strdup(secret); 757189251Ssam as->shared_secret_len = os_strlen(secret); 758189251Ssam e->radius_conf->auth_server = as; 759189251Ssam e->radius_conf->auth_servers = as; 760189251Ssam e->radius_conf->msg_dumps = 1; 761189251Ssam if (cli_addr) { 762189251Ssam if (hostapd_parse_ip_addr(cli_addr, 763189251Ssam &e->radius_conf->client_addr) == 0) 764189251Ssam e->radius_conf->force_client_addr = 1; 765189251Ssam else { 766189251Ssam wpa_printf(MSG_ERROR, "Invalid IP address '%s'", 767189251Ssam cli_addr); 768189251Ssam assert(0); 769189251Ssam } 770189251Ssam } 771189251Ssam 772189251Ssam e->radius = radius_client_init(wpa_s, e->radius_conf); 773189251Ssam assert(e->radius != NULL); 774189251Ssam 775189251Ssam res = radius_client_register(e->radius, RADIUS_AUTH, 776189251Ssam ieee802_1x_receive_auth, e); 777189251Ssam assert(res == 0); 778189251Ssam} 779189251Ssam 780189251Ssam 781189251Ssamstatic int scard_test(void) 782189251Ssam{ 783189251Ssam struct scard_data *scard; 784189251Ssam size_t len; 785189251Ssam char imsi[20]; 786189251Ssam unsigned char _rand[16]; 787189251Ssam#ifdef PCSC_FUNCS 788189251Ssam unsigned char sres[4]; 789189251Ssam unsigned char kc[8]; 790189251Ssam#endif /* PCSC_FUNCS */ 791189251Ssam#define num_triplets 5 792189251Ssam unsigned char rand_[num_triplets][16]; 793189251Ssam unsigned char sres_[num_triplets][4]; 794189251Ssam unsigned char kc_[num_triplets][8]; 795189251Ssam int i, res; 796189251Ssam size_t j; 797189251Ssam 798189251Ssam#define AKA_RAND_LEN 16 799189251Ssam#define AKA_AUTN_LEN 16 800189251Ssam#define AKA_AUTS_LEN 14 801189251Ssam#define RES_MAX_LEN 16 802189251Ssam#define IK_LEN 16 803189251Ssam#define CK_LEN 16 804189251Ssam unsigned char aka_rand[AKA_RAND_LEN]; 805189251Ssam unsigned char aka_autn[AKA_AUTN_LEN]; 806189251Ssam unsigned char aka_auts[AKA_AUTS_LEN]; 807189251Ssam unsigned char aka_res[RES_MAX_LEN]; 808189251Ssam size_t aka_res_len; 809189251Ssam unsigned char aka_ik[IK_LEN]; 810189251Ssam unsigned char aka_ck[CK_LEN]; 811189251Ssam 812189251Ssam scard = scard_init(SCARD_TRY_BOTH); 813189251Ssam if (scard == NULL) 814189251Ssam return -1; 815189251Ssam if (scard_set_pin(scard, "1234")) { 816189251Ssam wpa_printf(MSG_WARNING, "PIN validation failed"); 817189251Ssam scard_deinit(scard); 818189251Ssam return -1; 819189251Ssam } 820189251Ssam 821189251Ssam len = sizeof(imsi); 822189251Ssam if (scard_get_imsi(scard, imsi, &len)) 823189251Ssam goto failed; 824189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len); 825189251Ssam /* NOTE: Permanent Username: 1 | IMSI */ 826189251Ssam 827189251Ssam os_memset(_rand, 0, sizeof(_rand)); 828189251Ssam if (scard_gsm_auth(scard, _rand, sres, kc)) 829189251Ssam goto failed; 830189251Ssam 831189251Ssam os_memset(_rand, 0xff, sizeof(_rand)); 832189251Ssam if (scard_gsm_auth(scard, _rand, sres, kc)) 833189251Ssam goto failed; 834189251Ssam 835189251Ssam for (i = 0; i < num_triplets; i++) { 836189251Ssam os_memset(rand_[i], i, sizeof(rand_[i])); 837189251Ssam if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i])) 838189251Ssam goto failed; 839189251Ssam } 840189251Ssam 841189251Ssam for (i = 0; i < num_triplets; i++) { 842189251Ssam printf("1"); 843189251Ssam for (j = 0; j < len; j++) 844189251Ssam printf("%c", imsi[j]); 845189251Ssam printf(","); 846189251Ssam for (j = 0; j < 16; j++) 847189251Ssam printf("%02X", rand_[i][j]); 848189251Ssam printf(","); 849189251Ssam for (j = 0; j < 4; j++) 850189251Ssam printf("%02X", sres_[i][j]); 851189251Ssam printf(","); 852189251Ssam for (j = 0; j < 8; j++) 853189251Ssam printf("%02X", kc_[i][j]); 854189251Ssam printf("\n"); 855189251Ssam } 856189251Ssam 857189251Ssam wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication"); 858189251Ssam 859189251Ssam /* seq 39 (0x28) */ 860189251Ssam os_memset(aka_rand, 0xaa, 16); 861189251Ssam os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf" 862189251Ssam "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16); 863189251Ssam 864189251Ssam res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len, 865189251Ssam aka_ik, aka_ck, aka_auts); 866189251Ssam if (res == 0) { 867189251Ssam wpa_printf(MSG_DEBUG, "UMTS auth completed successfully"); 868189251Ssam wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len); 869189251Ssam wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN); 870189251Ssam wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN); 871189251Ssam } else if (res == -2) { 872189251Ssam wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization " 873189251Ssam "failure"); 874189251Ssam wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN); 875189251Ssam } else { 876189251Ssam wpa_printf(MSG_DEBUG, "UMTS auth failed"); 877189251Ssam } 878189251Ssam 879189251Ssamfailed: 880189251Ssam scard_deinit(scard); 881189251Ssam 882189251Ssam return 0; 883189251Ssam#undef num_triplets 884189251Ssam} 885189251Ssam 886189251Ssam 887189251Ssamstatic int scard_get_triplets(int argc, char *argv[]) 888189251Ssam{ 889189251Ssam struct scard_data *scard; 890189251Ssam size_t len; 891189251Ssam char imsi[20]; 892189251Ssam unsigned char _rand[16]; 893189251Ssam unsigned char sres[4]; 894189251Ssam unsigned char kc[8]; 895189251Ssam int num_triplets; 896189251Ssam int i; 897189251Ssam size_t j; 898189251Ssam 899189251Ssam if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) { 900189251Ssam printf("invalid parameters for sim command\n"); 901189251Ssam return -1; 902189251Ssam } 903189251Ssam 904189251Ssam if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) { 905189251Ssam /* disable debug output */ 906189251Ssam wpa_debug_level = 99; 907189251Ssam } 908189251Ssam 909189251Ssam scard = scard_init(SCARD_GSM_SIM_ONLY); 910189251Ssam if (scard == NULL) { 911189251Ssam printf("Failed to open smartcard connection\n"); 912189251Ssam return -1; 913189251Ssam } 914189251Ssam if (scard_set_pin(scard, argv[0])) { 915189251Ssam wpa_printf(MSG_WARNING, "PIN validation failed"); 916189251Ssam scard_deinit(scard); 917189251Ssam return -1; 918189251Ssam } 919189251Ssam 920189251Ssam len = sizeof(imsi); 921189251Ssam if (scard_get_imsi(scard, imsi, &len)) { 922189251Ssam scard_deinit(scard); 923189251Ssam return -1; 924189251Ssam } 925189251Ssam 926189251Ssam for (i = 0; i < num_triplets; i++) { 927189251Ssam os_memset(_rand, i, sizeof(_rand)); 928189251Ssam if (scard_gsm_auth(scard, _rand, sres, kc)) 929189251Ssam break; 930189251Ssam 931189251Ssam /* IMSI:Kc:SRES:RAND */ 932189251Ssam for (j = 0; j < len; j++) 933189251Ssam printf("%c", imsi[j]); 934189251Ssam printf(":"); 935189251Ssam for (j = 0; j < 8; j++) 936189251Ssam printf("%02X", kc[j]); 937189251Ssam printf(":"); 938189251Ssam for (j = 0; j < 4; j++) 939189251Ssam printf("%02X", sres[j]); 940189251Ssam printf(":"); 941189251Ssam for (j = 0; j < 16; j++) 942189251Ssam printf("%02X", _rand[j]); 943189251Ssam printf("\n"); 944189251Ssam } 945189251Ssam 946189251Ssam scard_deinit(scard); 947189251Ssam 948189251Ssam return 0; 949189251Ssam} 950189251Ssam 951189251Ssam 952214734Srpaulostatic void eapol_test_terminate(int sig, void *signal_ctx) 953189251Ssam{ 954214734Srpaulo struct wpa_supplicant *wpa_s = signal_ctx; 955189251Ssam wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig); 956189251Ssam eloop_terminate(); 957189251Ssam} 958189251Ssam 959189251Ssam 960189251Ssamstatic void usage(void) 961189251Ssam{ 962189251Ssam printf("usage:\n" 963189251Ssam "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] " 964189251Ssam "[-s<AS secret>]\\\n" 965189251Ssam " [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n" 966189251Ssam " [-M<client MAC address>] \\\n" 967189251Ssam " [-N<attr spec>] \\\n" 968189251Ssam " [-A<client IP>]\n" 969189251Ssam "eapol_test scard\n" 970189251Ssam "eapol_test sim <PIN> <num triplets> [debug]\n" 971189251Ssam "\n"); 972189251Ssam printf("options:\n" 973189251Ssam " -c<conf> = configuration file\n" 974189251Ssam " -a<AS IP> = IP address of the authentication server, " 975189251Ssam "default 127.0.0.1\n" 976189251Ssam " -p<AS port> = UDP port of the authentication server, " 977189251Ssam "default 1812\n" 978189251Ssam " -s<AS secret> = shared secret with the authentication " 979189251Ssam "server, default 'radius'\n" 980189251Ssam " -A<client IP> = IP address of the client, default: select " 981189251Ssam "automatically\n" 982189251Ssam " -r<count> = number of re-authentications\n" 983189251Ssam " -W = wait for a control interface monitor before starting\n" 984189251Ssam " -S = save configuration after authentication\n" 985189251Ssam " -n = no MPPE keys expected\n" 986189251Ssam " -t<timeout> = sets timeout in seconds (default: 30 s)\n" 987189251Ssam " -C<Connect-Info> = RADIUS Connect-Info (default: " 988189251Ssam "CONNECT 11Mbps 802.11b)\n" 989189251Ssam " -M<client MAC address> = Set own MAC address " 990189251Ssam "(Calling-Station-Id,\n" 991189251Ssam " default: 02:00:00:00:00:01)\n" 992189251Ssam " -N<attr spec> = send arbitrary attribute specified by:\n" 993189251Ssam " attr_id:syntax:value or attr_id\n" 994189251Ssam " attr_id - number id of the attribute\n" 995189251Ssam " syntax - one of: s, d, x\n" 996189251Ssam " s = string\n" 997189251Ssam " d = integer\n" 998189251Ssam " x = octet string\n" 999189251Ssam " value - attribute value.\n" 1000189251Ssam " When only attr_id is specified, NULL will be used as " 1001189251Ssam "value.\n" 1002189251Ssam " Multiple attributes can be specified by using the " 1003189251Ssam "option several times.\n"); 1004189251Ssam} 1005189251Ssam 1006189251Ssam 1007189251Ssamint main(int argc, char *argv[]) 1008189251Ssam{ 1009189251Ssam struct wpa_supplicant wpa_s; 1010189251Ssam int c, ret = 1, wait_for_monitor = 0, save_config = 0; 1011189251Ssam char *as_addr = "127.0.0.1"; 1012189251Ssam int as_port = 1812; 1013189251Ssam char *as_secret = "radius"; 1014189251Ssam char *cli_addr = NULL; 1015189251Ssam char *conf = NULL; 1016189251Ssam int timeout = 30; 1017189251Ssam char *pos; 1018189251Ssam struct extra_radius_attr *p = NULL, *p1; 1019189251Ssam 1020189251Ssam if (os_program_init()) 1021189251Ssam return -1; 1022189251Ssam 1023189251Ssam hostapd_logger_register_cb(hostapd_logger_cb); 1024189251Ssam 1025189251Ssam os_memset(&eapol_test, 0, sizeof(eapol_test)); 1026189251Ssam eapol_test.connect_info = "CONNECT 11Mbps 802.11b"; 1027189251Ssam os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN); 1028189251Ssam 1029189251Ssam wpa_debug_level = 0; 1030189251Ssam wpa_debug_show_keys = 1; 1031189251Ssam 1032189251Ssam for (;;) { 1033189251Ssam c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W"); 1034189251Ssam if (c < 0) 1035189251Ssam break; 1036189251Ssam switch (c) { 1037189251Ssam case 'a': 1038189251Ssam as_addr = optarg; 1039189251Ssam break; 1040189251Ssam case 'A': 1041189251Ssam cli_addr = optarg; 1042189251Ssam break; 1043189251Ssam case 'c': 1044189251Ssam conf = optarg; 1045189251Ssam break; 1046189251Ssam case 'C': 1047189251Ssam eapol_test.connect_info = optarg; 1048189251Ssam break; 1049189251Ssam case 'M': 1050189251Ssam if (hwaddr_aton(optarg, eapol_test.own_addr)) { 1051189251Ssam usage(); 1052189251Ssam return -1; 1053189251Ssam } 1054189251Ssam break; 1055189251Ssam case 'n': 1056189251Ssam eapol_test.no_mppe_keys++; 1057189251Ssam break; 1058189251Ssam case 'p': 1059189251Ssam as_port = atoi(optarg); 1060189251Ssam break; 1061189251Ssam case 'r': 1062189251Ssam eapol_test.eapol_test_num_reauths = atoi(optarg); 1063189251Ssam break; 1064189251Ssam case 's': 1065189251Ssam as_secret = optarg; 1066189251Ssam break; 1067189251Ssam case 'S': 1068189251Ssam save_config++; 1069189251Ssam break; 1070189251Ssam case 't': 1071189251Ssam timeout = atoi(optarg); 1072189251Ssam break; 1073189251Ssam case 'W': 1074189251Ssam wait_for_monitor++; 1075189251Ssam break; 1076189251Ssam case 'N': 1077189251Ssam p1 = os_zalloc(sizeof(p1)); 1078189251Ssam if (p1 == NULL) 1079189251Ssam break; 1080189251Ssam if (!p) 1081189251Ssam eapol_test.extra_attrs = p1; 1082189251Ssam else 1083189251Ssam p->next = p1; 1084189251Ssam p = p1; 1085189251Ssam 1086189251Ssam p->type = atoi(optarg); 1087189251Ssam pos = os_strchr(optarg, ':'); 1088189251Ssam if (pos == NULL) { 1089189251Ssam p->syntax = 'n'; 1090189251Ssam p->data = NULL; 1091189251Ssam break; 1092189251Ssam } 1093189251Ssam 1094189251Ssam pos++; 1095189251Ssam if (pos[0] == '\0' || pos[1] != ':') { 1096189251Ssam printf("Incorrect format of attribute " 1097189251Ssam "specification\n"); 1098189251Ssam break; 1099189251Ssam } 1100189251Ssam 1101189251Ssam p->syntax = pos[0]; 1102189251Ssam p->data = pos + 2; 1103189251Ssam break; 1104189251Ssam default: 1105189251Ssam usage(); 1106189251Ssam return -1; 1107189251Ssam } 1108189251Ssam } 1109189251Ssam 1110189251Ssam if (argc > optind && os_strcmp(argv[optind], "scard") == 0) { 1111189251Ssam return scard_test(); 1112189251Ssam } 1113189251Ssam 1114189251Ssam if (argc > optind && os_strcmp(argv[optind], "sim") == 0) { 1115189251Ssam return scard_get_triplets(argc - optind - 1, 1116189251Ssam &argv[optind + 1]); 1117189251Ssam } 1118189251Ssam 1119189251Ssam if (conf == NULL) { 1120189251Ssam usage(); 1121189251Ssam printf("Configuration file is required.\n"); 1122189251Ssam return -1; 1123189251Ssam } 1124189251Ssam 1125214734Srpaulo if (eap_register_methods()) { 1126189251Ssam wpa_printf(MSG_ERROR, "Failed to register EAP methods"); 1127189251Ssam return -1; 1128189251Ssam } 1129189251Ssam 1130214734Srpaulo if (eloop_init()) { 1131189251Ssam wpa_printf(MSG_ERROR, "Failed to initialize event loop"); 1132189251Ssam return -1; 1133189251Ssam } 1134189251Ssam 1135189251Ssam os_memset(&wpa_s, 0, sizeof(wpa_s)); 1136189251Ssam eapol_test.wpa_s = &wpa_s; 1137189251Ssam wpa_s.conf = wpa_config_read(conf); 1138189251Ssam if (wpa_s.conf == NULL) { 1139189251Ssam printf("Failed to parse configuration file '%s'.\n", conf); 1140189251Ssam return -1; 1141189251Ssam } 1142189251Ssam if (wpa_s.conf->ssid == NULL) { 1143189251Ssam printf("No networks defined.\n"); 1144189251Ssam return -1; 1145189251Ssam } 1146189251Ssam 1147189251Ssam wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret, 1148189251Ssam cli_addr); 1149189251Ssam wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); 1150189251Ssam if (wpa_s.ctrl_iface == NULL) { 1151189251Ssam printf("Failed to initialize control interface '%s'.\n" 1152189251Ssam "You may have another eapol_test process already " 1153189251Ssam "running or the file was\n" 1154189251Ssam "left by an unclean termination of eapol_test in " 1155189251Ssam "which case you will need\n" 1156189251Ssam "to manually remove this file before starting " 1157189251Ssam "eapol_test again.\n", 1158189251Ssam wpa_s.conf->ctrl_interface); 1159189251Ssam return -1; 1160189251Ssam } 1161189251Ssam if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid)) 1162189251Ssam return -1; 1163189251Ssam 1164189251Ssam if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid)) 1165189251Ssam return -1; 1166189251Ssam 1167189251Ssam if (wait_for_monitor) 1168189251Ssam wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); 1169189251Ssam 1170189251Ssam eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test, 1171189251Ssam NULL); 1172189251Ssam eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL); 1173214734Srpaulo eloop_register_signal_terminate(eapol_test_terminate, &wpa_s); 1174214734Srpaulo eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s); 1175189251Ssam eloop_run(); 1176189251Ssam 1177189251Ssam eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL); 1178189251Ssam eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL); 1179189251Ssam 1180189251Ssam if (eapol_test_compare_pmk(&eapol_test) == 0 || 1181189251Ssam eapol_test.no_mppe_keys) 1182189251Ssam ret = 0; 1183189251Ssam if (eapol_test.auth_timed_out) 1184189251Ssam ret = -2; 1185189251Ssam if (eapol_test.radius_access_reject_received) 1186189251Ssam ret = -3; 1187189251Ssam 1188189251Ssam if (save_config) 1189189251Ssam wpa_config_write(conf, wpa_s.conf); 1190189251Ssam 1191189251Ssam test_eapol_clean(&eapol_test, &wpa_s); 1192189251Ssam 1193189251Ssam eap_peer_unregister_methods(); 1194189251Ssam 1195189251Ssam eloop_destroy(); 1196189251Ssam 1197189251Ssam printf("MPPE keys OK: %d mismatch: %d\n", 1198189251Ssam eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch); 1199189251Ssam if (eapol_test.num_mppe_mismatch) 1200189251Ssam ret = -4; 1201189251Ssam if (ret) 1202189251Ssam printf("FAILURE\n"); 1203189251Ssam else 1204189251Ssam printf("SUCCESS\n"); 1205189251Ssam 1206189251Ssam os_program_deinit(); 1207189251Ssam 1208189251Ssam return ret; 1209189251Ssam} 1210