wpa_supplicant: Add option -I for additional config file
[mech_eap.git] / wpa_supplicant / eapol_test.c
1 /*
2  * WPA Supplicant - test code
3  * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  *
8  * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
9  * Not used in production version.
10  */
11
12 #include "includes.h"
13 #include <assert.h>
14
15 #include "common.h"
16 #include "utils/ext_password.h"
17 #include "config.h"
18 #include "eapol_supp/eapol_supp_sm.h"
19 #include "eap_peer/eap.h"
20 #include "eap_server/eap_methods.h"
21 #include "eloop.h"
22 #include "utils/base64.h"
23 #include "rsn_supp/wpa.h"
24 #include "wpa_supplicant_i.h"
25 #include "radius/radius.h"
26 #include "radius/radius_client.h"
27 #include "common/wpa_ctrl.h"
28 #include "ctrl_iface.h"
29 #include "pcsc_funcs.h"
30
31
32 extern int wpa_debug_level;
33 extern int wpa_debug_show_keys;
34
35 struct wpa_driver_ops *wpa_drivers[] = { NULL };
36
37
38 struct extra_radius_attr {
39         u8 type;
40         char syntax;
41         char *data;
42         struct extra_radius_attr *next;
43 };
44
45 struct eapol_test_data {
46         struct wpa_supplicant *wpa_s;
47
48         int eapol_test_num_reauths;
49         int no_mppe_keys;
50         int num_mppe_ok, num_mppe_mismatch;
51
52         u8 radius_identifier;
53         struct radius_msg *last_recv_radius;
54         struct in_addr own_ip_addr;
55         struct radius_client_data *radius;
56         struct hostapd_radius_servers *radius_conf;
57
58          /* last received EAP Response from Authentication Server */
59         struct wpabuf *last_eap_radius;
60
61         u8 authenticator_pmk[PMK_LEN];
62         size_t authenticator_pmk_len;
63         int radius_access_accept_received;
64         int radius_access_reject_received;
65         int auth_timed_out;
66
67         u8 *eap_identity;
68         size_t eap_identity_len;
69
70         char *connect_info;
71         u8 own_addr[ETH_ALEN];
72         struct extra_radius_attr *extra_attrs;
73
74         FILE *server_cert_file;
75 };
76
77 static struct eapol_test_data eapol_test;
78
79
80 static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
81
82
83 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
84                               int level, const char *txt, size_t len)
85 {
86         if (addr)
87                 wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n",
88                            MAC2STR(addr), txt);
89         else
90                 wpa_printf(MSG_DEBUG, "%s", txt);
91 }
92
93
94 static int add_extra_attr(struct radius_msg *msg,
95                           struct extra_radius_attr *attr)
96 {
97         size_t len;
98         char *pos;
99         u32 val;
100         char buf[RADIUS_MAX_ATTR_LEN + 1];
101
102         switch (attr->syntax) {
103         case 's':
104                 os_snprintf(buf, sizeof(buf), "%s", attr->data);
105                 len = os_strlen(buf);
106                 break;
107         case 'n':
108                 buf[0] = '\0';
109                 len = 1;
110                 break;
111         case 'x':
112                 pos = attr->data;
113                 if (pos[0] == '0' && pos[1] == 'x')
114                         pos += 2;
115                 len = os_strlen(pos);
116                 if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) {
117                         printf("Invalid extra attribute hexstring\n");
118                         return -1;
119                 }
120                 len /= 2;
121                 if (hexstr2bin(pos, (u8 *) buf, len) < 0) {
122                         printf("Invalid extra attribute hexstring\n");
123                         return -1;
124                 }
125                 break;
126         case 'd':
127                 val = htonl(atoi(attr->data));
128                 os_memcpy(buf, &val, 4);
129                 len = 4;
130                 break;
131         default:
132                 printf("Incorrect extra attribute syntax specification\n");
133                 return -1;
134         }
135
136         if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) {
137                 printf("Could not add attribute %d\n", attr->type);
138                 return -1;
139         }
140
141         return 0;
142 }
143
144
145 static int add_extra_attrs(struct radius_msg *msg,
146                            struct extra_radius_attr *attrs)
147 {
148         struct extra_radius_attr *p;
149         for (p = attrs; p; p = p->next) {
150                 if (add_extra_attr(msg, p) < 0)
151                         return -1;
152         }
153         return 0;
154 }
155
156
157 static struct extra_radius_attr *
158 find_extra_attr(struct extra_radius_attr *attrs, u8 type)
159 {
160         struct extra_radius_attr *p;
161         for (p = attrs; p; p = p->next) {
162                 if (p->type == type)
163                         return p;
164         }
165         return NULL;
166 }
167
168
169 static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
170                                           const u8 *eap, size_t len)
171 {
172         struct radius_msg *msg;
173         char buf[RADIUS_MAX_ATTR_LEN + 1];
174         const struct eap_hdr *hdr;
175         const u8 *pos;
176
177         wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
178                    "packet");
179
180         e->radius_identifier = radius_client_get_id(e->radius);
181         msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
182                              e->radius_identifier);
183         if (msg == NULL) {
184                 printf("Could not create net RADIUS packet\n");
185                 return;
186         }
187
188         radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
189
190         hdr = (const struct eap_hdr *) eap;
191         pos = (const u8 *) (hdr + 1);
192         if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
193             pos[0] == EAP_TYPE_IDENTITY) {
194                 pos++;
195                 os_free(e->eap_identity);
196                 e->eap_identity_len = len - sizeof(*hdr) - 1;
197                 e->eap_identity = os_malloc(e->eap_identity_len);
198                 if (e->eap_identity) {
199                         os_memcpy(e->eap_identity, pos, e->eap_identity_len);
200                         wpa_hexdump(MSG_DEBUG, "Learned identity from "
201                                     "EAP-Response-Identity",
202                                     e->eap_identity, e->eap_identity_len);
203                 }
204         }
205
206         if (e->eap_identity &&
207             !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
208                                  e->eap_identity, e->eap_identity_len)) {
209                 printf("Could not add User-Name\n");
210                 goto fail;
211         }
212
213         if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) &&
214             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
215                                  (u8 *) &e->own_ip_addr, 4)) {
216                 printf("Could not add NAS-IP-Address\n");
217                 goto fail;
218         }
219
220         os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
221                     MAC2STR(e->wpa_s->own_addr));
222         if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID)
223             &&
224             !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
225                                  (u8 *) buf, os_strlen(buf))) {
226                 printf("Could not add Calling-Station-Id\n");
227                 goto fail;
228         }
229
230         /* TODO: should probably check MTU from driver config; 2304 is max for
231          * IEEE 802.11, but use 1400 to avoid problems with too large packets
232          */
233         if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) &&
234             !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
235                 printf("Could not add Framed-MTU\n");
236                 goto fail;
237         }
238
239         if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) &&
240             !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
241                                        RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
242                 printf("Could not add NAS-Port-Type\n");
243                 goto fail;
244         }
245
246         os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
247         if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) &&
248             !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
249                                  (u8 *) buf, os_strlen(buf))) {
250                 printf("Could not add Connect-Info\n");
251                 goto fail;
252         }
253
254         if (add_extra_attrs(msg, e->extra_attrs) < 0)
255                 goto fail;
256
257         if (eap && !radius_msg_add_eap(msg, eap, len)) {
258                 printf("Could not add EAP-Message\n");
259                 goto fail;
260         }
261
262         /* State attribute must be copied if and only if this packet is
263          * Access-Request reply to the previous Access-Challenge */
264         if (e->last_recv_radius &&
265             radius_msg_get_hdr(e->last_recv_radius)->code ==
266             RADIUS_CODE_ACCESS_CHALLENGE) {
267                 int res = radius_msg_copy_attr(msg, e->last_recv_radius,
268                                                RADIUS_ATTR_STATE);
269                 if (res < 0) {
270                         printf("Could not copy State attribute from previous "
271                                "Access-Challenge\n");
272                         goto fail;
273                 }
274                 if (res > 0) {
275                         wpa_printf(MSG_DEBUG, "  Copied RADIUS State "
276                                    "Attribute");
277                 }
278         }
279
280         if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr)
281             < 0)
282                 goto fail;
283         return;
284
285  fail:
286         radius_msg_free(msg);
287 }
288
289
290 static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
291                                  size_t len)
292 {
293         printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
294                type, (unsigned long) len);
295         if (type == IEEE802_1X_TYPE_EAP_PACKET) {
296                 wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
297                 ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
298         }
299         return 0;
300 }
301
302
303 static void eapol_test_set_config_blob(void *ctx,
304                                        struct wpa_config_blob *blob)
305 {
306         struct eapol_test_data *e = ctx;
307         wpa_config_set_blob(e->wpa_s->conf, blob);
308 }
309
310
311 static const struct wpa_config_blob *
312 eapol_test_get_config_blob(void *ctx, const char *name)
313 {
314         struct eapol_test_data *e = ctx;
315         return wpa_config_get_blob(e->wpa_s->conf, name);
316 }
317
318
319 static void eapol_test_eapol_done_cb(void *ctx)
320 {
321         printf("WPA: EAPOL processing complete\n");
322 }
323
324
325 static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx)
326 {
327         struct eapol_test_data *e = eloop_ctx;
328         printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n");
329         e->radius_access_accept_received = 0;
330         send_eap_request_identity(e->wpa_s, NULL);
331 }
332
333
334 static int eapol_test_compare_pmk(struct eapol_test_data *e)
335 {
336         u8 pmk[PMK_LEN];
337         int ret = 1;
338
339         if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
340                 wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
341                 if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) {
342                         printf("WARNING: PMK mismatch\n");
343                         wpa_hexdump(MSG_DEBUG, "PMK from AS",
344                                     e->authenticator_pmk, PMK_LEN);
345                 } else if (e->radius_access_accept_received)
346                         ret = 0;
347         } else if (e->authenticator_pmk_len == 16 &&
348                    eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) {
349                 wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16);
350                 if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) {
351                         printf("WARNING: PMK mismatch\n");
352                         wpa_hexdump(MSG_DEBUG, "PMK from AS",
353                                     e->authenticator_pmk, 16);
354                 } else if (e->radius_access_accept_received)
355                         ret = 0;
356         } else if (e->radius_access_accept_received && e->no_mppe_keys) {
357                 /* No keying material expected */
358                 ret = 0;
359         }
360
361         if (ret && !e->no_mppe_keys)
362                 e->num_mppe_mismatch++;
363         else if (!e->no_mppe_keys)
364                 e->num_mppe_ok++;
365
366         return ret;
367 }
368
369
370 static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
371 {
372         struct eapol_test_data *e = ctx;
373         printf("eapol_sm_cb: success=%d\n", success);
374         e->eapol_test_num_reauths--;
375         if (e->eapol_test_num_reauths < 0)
376                 eloop_terminate();
377         else {
378                 eapol_test_compare_pmk(e);
379                 eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL);
380         }
381 }
382
383
384 static void eapol_test_write_cert(FILE *f, const char *subject,
385                                   const struct wpabuf *cert)
386 {
387         unsigned char *encoded;
388
389         encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
390         if (encoded == NULL)
391                 return;
392         fprintf(f, "%s\n-----BEGIN CERTIFICATE-----\n%s"
393                 "-----END CERTIFICATE-----\n\n", subject, encoded);
394         os_free(encoded);
395 }
396
397
398 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
399                                const char *cert_hash,
400                                const struct wpabuf *cert)
401 {
402         struct eapol_test_data *e = ctx;
403
404         wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
405                 "depth=%d subject='%s'%s%s",
406                 depth, subject,
407                 cert_hash ? " hash=" : "",
408                 cert_hash ? cert_hash : "");
409
410         if (cert) {
411                 char *cert_hex;
412                 size_t len = wpabuf_len(cert) * 2 + 1;
413                 cert_hex = os_malloc(len);
414                 if (cert_hex) {
415                         wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
416                                          wpabuf_len(cert));
417                         wpa_msg_ctrl(e->wpa_s, MSG_INFO,
418                                      WPA_EVENT_EAP_PEER_CERT
419                                      "depth=%d subject='%s' cert=%s",
420                                      depth, subject, cert_hex);
421                         os_free(cert_hex);
422                 }
423
424                 if (e->server_cert_file)
425                         eapol_test_write_cert(e->server_cert_file,
426                                               subject, cert);
427         }
428 }
429
430
431 static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len)
432 {
433         struct eapol_test_data *e = ctx;
434         struct wpa_supplicant *wpa_s = e->wpa_s;
435         char *str;
436         int res;
437
438         wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
439                           id, len);
440
441         if (wpa_s->current_ssid == NULL)
442                 return;
443
444         if (id == NULL) {
445                 if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
446                                    "NULL", 0) < 0)
447                         return;
448         } else {
449                 str = os_malloc(len * 2 + 1);
450                 if (str == NULL)
451                         return;
452                 wpa_snprintf_hex(str, len * 2 + 1, id, len);
453                 res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
454                                      str, 0);
455                 os_free(str);
456                 if (res < 0)
457                         return;
458         }
459 }
460
461
462 static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
463                       struct wpa_ssid *ssid)
464 {
465         struct eapol_config eapol_conf;
466         struct eapol_ctx *ctx;
467
468         ctx = os_zalloc(sizeof(*ctx));
469         if (ctx == NULL) {
470                 printf("Failed to allocate EAPOL context.\n");
471                 return -1;
472         }
473         ctx->ctx = e;
474         ctx->msg_ctx = wpa_s;
475         ctx->scard_ctx = wpa_s->scard;
476         ctx->cb = eapol_sm_cb;
477         ctx->cb_ctx = e;
478         ctx->eapol_send_ctx = wpa_s;
479         ctx->preauth = 0;
480         ctx->eapol_done_cb = eapol_test_eapol_done_cb;
481         ctx->eapol_send = eapol_test_eapol_send;
482         ctx->set_config_blob = eapol_test_set_config_blob;
483         ctx->get_config_blob = eapol_test_get_config_blob;
484         ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
485         ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
486         ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
487         ctx->cert_cb = eapol_test_cert_cb;
488         ctx->cert_in_cb = 1;
489         ctx->set_anon_id = eapol_test_set_anon_id;
490
491         wpa_s->eapol = eapol_sm_init(ctx);
492         if (wpa_s->eapol == NULL) {
493                 os_free(ctx);
494                 printf("Failed to initialize EAPOL state machines.\n");
495                 return -1;
496         }
497
498         wpa_s->current_ssid = ssid;
499         os_memset(&eapol_conf, 0, sizeof(eapol_conf));
500         eapol_conf.accept_802_1x_keys = 1;
501         eapol_conf.required_keys = 0;
502         eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
503         eapol_conf.workaround = ssid->eap_workaround;
504         eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
505         eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
506
507
508         eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
509         /* 802.1X::portControl = Auto */
510         eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
511
512         return 0;
513 }
514
515
516 static void test_eapol_clean(struct eapol_test_data *e,
517                              struct wpa_supplicant *wpa_s)
518 {
519         struct extra_radius_attr *p, *prev;
520
521         radius_client_deinit(e->radius);
522         wpabuf_free(e->last_eap_radius);
523         radius_msg_free(e->last_recv_radius);
524         e->last_recv_radius = NULL;
525         os_free(e->eap_identity);
526         e->eap_identity = NULL;
527         eapol_sm_deinit(wpa_s->eapol);
528         wpa_s->eapol = NULL;
529         if (e->radius_conf && e->radius_conf->auth_server) {
530                 os_free(e->radius_conf->auth_server->shared_secret);
531                 os_free(e->radius_conf->auth_server);
532         }
533         os_free(e->radius_conf);
534         e->radius_conf = NULL;
535         scard_deinit(wpa_s->scard);
536         if (wpa_s->ctrl_iface) {
537                 wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
538                 wpa_s->ctrl_iface = NULL;
539         }
540
541         ext_password_deinit(wpa_s->ext_pw);
542         wpa_s->ext_pw = NULL;
543
544         wpa_config_free(wpa_s->conf);
545
546         p = e->extra_attrs;
547         while (p) {
548                 prev = p;
549                 p = p->next;
550                 os_free(prev);
551         }
552 }
553
554
555 static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
556 {
557         struct wpa_supplicant *wpa_s = eloop_ctx;
558         u8 buf[100], *pos;
559         struct ieee802_1x_hdr *hdr;
560         struct eap_hdr *eap;
561
562         hdr = (struct ieee802_1x_hdr *) buf;
563         hdr->version = EAPOL_VERSION;
564         hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
565         hdr->length = htons(5);
566
567         eap = (struct eap_hdr *) (hdr + 1);
568         eap->code = EAP_CODE_REQUEST;
569         eap->identifier = 0;
570         eap->length = htons(5);
571         pos = (u8 *) (eap + 1);
572         *pos = EAP_TYPE_IDENTITY;
573
574         printf("Sending fake EAP-Request-Identity\n");
575         eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf,
576                           sizeof(*hdr) + 5);
577 }
578
579
580 static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
581 {
582         struct eapol_test_data *e = eloop_ctx;
583         printf("EAPOL test timed out\n");
584         e->auth_timed_out = 1;
585         eloop_terminate();
586 }
587
588
589 static char *eap_type_text(u8 type)
590 {
591         switch (type) {
592         case EAP_TYPE_IDENTITY: return "Identity";
593         case EAP_TYPE_NOTIFICATION: return "Notification";
594         case EAP_TYPE_NAK: return "Nak";
595         case EAP_TYPE_TLS: return "TLS";
596         case EAP_TYPE_TTLS: return "TTLS";
597         case EAP_TYPE_PEAP: return "PEAP";
598         case EAP_TYPE_SIM: return "SIM";
599         case EAP_TYPE_GTC: return "GTC";
600         case EAP_TYPE_MD5: return "MD5";
601         case EAP_TYPE_OTP: return "OTP";
602         case EAP_TYPE_FAST: return "FAST";
603         case EAP_TYPE_SAKE: return "SAKE";
604         case EAP_TYPE_PSK: return "PSK";
605         default: return "Unknown";
606         }
607 }
608
609
610 static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
611 {
612         struct wpabuf *eap;
613         const struct eap_hdr *hdr;
614         int eap_type = -1;
615         char buf[64];
616         struct radius_msg *msg;
617
618         if (e->last_recv_radius == NULL)
619                 return;
620
621         msg = e->last_recv_radius;
622
623         eap = radius_msg_get_eap(msg);
624         if (eap == NULL) {
625                 /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
626                  * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
627                  * attribute */
628                 wpa_printf(MSG_DEBUG, "could not extract "
629                                "EAP-Message from RADIUS message");
630                 wpabuf_free(e->last_eap_radius);
631                 e->last_eap_radius = NULL;
632                 return;
633         }
634
635         if (wpabuf_len(eap) < sizeof(*hdr)) {
636                 wpa_printf(MSG_DEBUG, "too short EAP packet "
637                                "received from authentication server");
638                 wpabuf_free(eap);
639                 return;
640         }
641
642         if (wpabuf_len(eap) > sizeof(*hdr))
643                 eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
644
645         hdr = wpabuf_head(eap);
646         switch (hdr->code) {
647         case EAP_CODE_REQUEST:
648                 os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
649                             eap_type >= 0 ? eap_type_text(eap_type) : "??",
650                             eap_type);
651                 break;
652         case EAP_CODE_RESPONSE:
653                 os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
654                             eap_type >= 0 ? eap_type_text(eap_type) : "??",
655                             eap_type);
656                 break;
657         case EAP_CODE_SUCCESS:
658                 os_strlcpy(buf, "EAP Success", sizeof(buf));
659                 /* LEAP uses EAP Success within an authentication, so must not
660                  * stop here with eloop_terminate(); */
661                 break;
662         case EAP_CODE_FAILURE:
663                 os_strlcpy(buf, "EAP Failure", sizeof(buf));
664                 eloop_terminate();
665                 break;
666         default:
667                 os_strlcpy(buf, "unknown EAP code", sizeof(buf));
668                 wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
669                 break;
670         }
671         wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
672                        "id=%d len=%d) from RADIUS server: %s",
673                       hdr->code, hdr->identifier, ntohs(hdr->length), buf);
674
675         /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
676
677         wpabuf_free(e->last_eap_radius);
678         e->last_eap_radius = eap;
679
680         {
681                 struct ieee802_1x_hdr *dot1x;
682                 dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap));
683                 assert(dot1x != NULL);
684                 dot1x->version = EAPOL_VERSION;
685                 dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
686                 dot1x->length = htons(wpabuf_len(eap));
687                 os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap),
688                           wpabuf_len(eap));
689                 eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
690                                   (u8 *) dot1x,
691                                   sizeof(*dot1x) + wpabuf_len(eap));
692                 os_free(dot1x);
693         }
694 }
695
696
697 static void ieee802_1x_get_keys(struct eapol_test_data *e,
698                                 struct radius_msg *msg, struct radius_msg *req,
699                                 const u8 *shared_secret,
700                                 size_t shared_secret_len)
701 {
702         struct radius_ms_mppe_keys *keys;
703
704         keys = radius_msg_get_ms_keys(msg, req, shared_secret,
705                                       shared_secret_len);
706         if (keys && keys->send == NULL && keys->recv == NULL) {
707                 os_free(keys);
708                 keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
709                                                  shared_secret_len);
710         }
711
712         if (keys) {
713                 if (keys->send) {
714                         wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)",
715                                     keys->send, keys->send_len);
716                 }
717                 if (keys->recv) {
718                         wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
719                                     keys->recv, keys->recv_len);
720                         e->authenticator_pmk_len =
721                                 keys->recv_len > PMK_LEN ? PMK_LEN :
722                                 keys->recv_len;
723                         os_memcpy(e->authenticator_pmk, keys->recv,
724                                   e->authenticator_pmk_len);
725                         if (e->authenticator_pmk_len == 16 && keys->send &&
726                             keys->send_len == 16) {
727                                 /* MS-CHAP-v2 derives 16 octet keys */
728                                 wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
729                                            "to extend PMK to 32 octets");
730                                 os_memcpy(e->authenticator_pmk +
731                                           e->authenticator_pmk_len,
732                                           keys->send, keys->send_len);
733                                 e->authenticator_pmk_len += keys->send_len;
734                         }
735                 }
736
737                 os_free(keys->send);
738                 os_free(keys->recv);
739                 os_free(keys);
740         }
741 }
742
743
744 /* Process the RADIUS frames from Authentication Server */
745 static RadiusRxResult
746 ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
747                         const u8 *shared_secret, size_t shared_secret_len,
748                         void *data)
749 {
750         struct eapol_test_data *e = data;
751         struct radius_hdr *hdr = radius_msg_get_hdr(msg);
752
753         /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
754          * present when packet contains an EAP-Message attribute */
755         if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
756             radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
757                                 0) < 0 &&
758             radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
759                 wpa_printf(MSG_DEBUG, "Allowing RADIUS "
760                               "Access-Reject without Message-Authenticator "
761                               "since it does not include EAP-Message\n");
762         } else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
763                                      req, 1)) {
764                 printf("Incoming RADIUS packet did not have correct "
765                        "Message-Authenticator - dropped\n");
766                 return RADIUS_RX_UNKNOWN;
767         }
768
769         if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
770             hdr->code != RADIUS_CODE_ACCESS_REJECT &&
771             hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
772                 printf("Unknown RADIUS message code\n");
773                 return RADIUS_RX_UNKNOWN;
774         }
775
776         e->radius_identifier = -1;
777         wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");
778
779         radius_msg_free(e->last_recv_radius);
780         e->last_recv_radius = msg;
781
782         switch (hdr->code) {
783         case RADIUS_CODE_ACCESS_ACCEPT:
784                 e->radius_access_accept_received = 1;
785                 ieee802_1x_get_keys(e, msg, req, shared_secret,
786                                     shared_secret_len);
787                 break;
788         case RADIUS_CODE_ACCESS_REJECT:
789                 e->radius_access_reject_received = 1;
790                 break;
791         }
792
793         ieee802_1x_decapsulate_radius(e);
794
795         if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
796              e->eapol_test_num_reauths < 0) ||
797             hdr->code == RADIUS_CODE_ACCESS_REJECT) {
798                 eloop_terminate();
799         }
800
801         return RADIUS_RX_QUEUED;
802 }
803
804
805 static void wpa_init_conf(struct eapol_test_data *e,
806                           struct wpa_supplicant *wpa_s, const char *authsrv,
807                           int port, const char *secret,
808                           const char *cli_addr)
809 {
810         struct hostapd_radius_server *as;
811         int res;
812
813         wpa_s->bssid[5] = 1;
814         os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN);
815         e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
816         os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
817
818         e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers));
819         assert(e->radius_conf != NULL);
820         e->radius_conf->num_auth_servers = 1;
821         as = os_zalloc(sizeof(struct hostapd_radius_server));
822         assert(as != NULL);
823 #if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
824         {
825                 int a[4];
826                 u8 *pos;
827                 sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
828                 pos = (u8 *) &as->addr.u.v4;
829                 *pos++ = a[0];
830                 *pos++ = a[1];
831                 *pos++ = a[2];
832                 *pos++ = a[3];
833         }
834 #else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
835         inet_aton(authsrv, &as->addr.u.v4);
836 #endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
837         as->addr.af = AF_INET;
838         as->port = port;
839         as->shared_secret = (u8 *) os_strdup(secret);
840         as->shared_secret_len = os_strlen(secret);
841         e->radius_conf->auth_server = as;
842         e->radius_conf->auth_servers = as;
843         e->radius_conf->msg_dumps = 1;
844         if (cli_addr) {
845                 if (hostapd_parse_ip_addr(cli_addr,
846                                           &e->radius_conf->client_addr) == 0)
847                         e->radius_conf->force_client_addr = 1;
848                 else {
849                         wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
850                                    cli_addr);
851                         assert(0);
852                 }
853         }
854
855         e->radius = radius_client_init(wpa_s, e->radius_conf);
856         assert(e->radius != NULL);
857
858         res = radius_client_register(e->radius, RADIUS_AUTH,
859                                      ieee802_1x_receive_auth, e);
860         assert(res == 0);
861 }
862
863
864 static int scard_test(void)
865 {
866         struct scard_data *scard;
867         size_t len;
868         char imsi[20];
869         unsigned char _rand[16];
870 #ifdef PCSC_FUNCS
871         unsigned char sres[4];
872         unsigned char kc[8];
873 #endif /* PCSC_FUNCS */
874 #define num_triplets 5
875         unsigned char rand_[num_triplets][16];
876         unsigned char sres_[num_triplets][4];
877         unsigned char kc_[num_triplets][8];
878         int i, res;
879         size_t j;
880
881 #define AKA_RAND_LEN 16
882 #define AKA_AUTN_LEN 16
883 #define AKA_AUTS_LEN 14
884 #define RES_MAX_LEN 16
885 #define IK_LEN 16
886 #define CK_LEN 16
887         unsigned char aka_rand[AKA_RAND_LEN];
888         unsigned char aka_autn[AKA_AUTN_LEN];
889         unsigned char aka_auts[AKA_AUTS_LEN];
890         unsigned char aka_res[RES_MAX_LEN];
891         size_t aka_res_len;
892         unsigned char aka_ik[IK_LEN];
893         unsigned char aka_ck[CK_LEN];
894
895         scard = scard_init(SCARD_TRY_BOTH, NULL);
896         if (scard == NULL)
897                 return -1;
898         if (scard_set_pin(scard, "1234")) {
899                 wpa_printf(MSG_WARNING, "PIN validation failed");
900                 scard_deinit(scard);
901                 return -1;
902         }
903
904         len = sizeof(imsi);
905         if (scard_get_imsi(scard, imsi, &len))
906                 goto failed;
907         wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len);
908         /* NOTE: Permanent Username: 1 | IMSI */
909
910         wpa_printf(MSG_DEBUG, "SCARD: MNC length %d",
911                    scard_get_mnc_len(scard));
912
913         os_memset(_rand, 0, sizeof(_rand));
914         if (scard_gsm_auth(scard, _rand, sres, kc))
915                 goto failed;
916
917         os_memset(_rand, 0xff, sizeof(_rand));
918         if (scard_gsm_auth(scard, _rand, sres, kc))
919                 goto failed;
920
921         for (i = 0; i < num_triplets; i++) {
922                 os_memset(rand_[i], i, sizeof(rand_[i]));
923                 if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i]))
924                         goto failed;
925         }
926
927         for (i = 0; i < num_triplets; i++) {
928                 printf("1");
929                 for (j = 0; j < len; j++)
930                         printf("%c", imsi[j]);
931                 printf(",");
932                 for (j = 0; j < 16; j++)
933                         printf("%02X", rand_[i][j]);
934                 printf(",");
935                 for (j = 0; j < 4; j++)
936                         printf("%02X", sres_[i][j]);
937                 printf(",");
938                 for (j = 0; j < 8; j++)
939                         printf("%02X", kc_[i][j]);
940                 printf("\n");
941         }
942
943         wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication");
944
945         /* seq 39 (0x28) */
946         os_memset(aka_rand, 0xaa, 16);
947         os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf"
948                   "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16);
949
950         res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len,
951                               aka_ik, aka_ck, aka_auts);
952         if (res == 0) {
953                 wpa_printf(MSG_DEBUG, "UMTS auth completed successfully");
954                 wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len);
955                 wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN);
956                 wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN);
957         } else if (res == -2) {
958                 wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization "
959                            "failure");
960                 wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN);
961         } else {
962                 wpa_printf(MSG_DEBUG, "UMTS auth failed");
963         }
964
965 failed:
966         scard_deinit(scard);
967
968         return 0;
969 #undef num_triplets
970 }
971
972
973 static int scard_get_triplets(int argc, char *argv[])
974 {
975         struct scard_data *scard;
976         size_t len;
977         char imsi[20];
978         unsigned char _rand[16];
979         unsigned char sres[4];
980         unsigned char kc[8];
981         int num_triplets;
982         int i;
983         size_t j;
984
985         if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) {
986                 printf("invalid parameters for sim command\n");
987                 return -1;
988         }
989
990         if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) {
991                 /* disable debug output */
992                 wpa_debug_level = 99;
993         }
994
995         scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
996         if (scard == NULL) {
997                 printf("Failed to open smartcard connection\n");
998                 return -1;
999         }
1000         if (scard_set_pin(scard, argv[0])) {
1001                 wpa_printf(MSG_WARNING, "PIN validation failed");
1002                 scard_deinit(scard);
1003                 return -1;
1004         }
1005
1006         len = sizeof(imsi);
1007         if (scard_get_imsi(scard, imsi, &len)) {
1008                 scard_deinit(scard);
1009                 return -1;
1010         }
1011
1012         for (i = 0; i < num_triplets; i++) {
1013                 os_memset(_rand, i, sizeof(_rand));
1014                 if (scard_gsm_auth(scard, _rand, sres, kc))
1015                         break;
1016
1017                 /* IMSI:Kc:SRES:RAND */
1018                 for (j = 0; j < len; j++)
1019                         printf("%c", imsi[j]);
1020                 printf(":");
1021                 for (j = 0; j < 8; j++)
1022                         printf("%02X", kc[j]);
1023                 printf(":");
1024                 for (j = 0; j < 4; j++)
1025                         printf("%02X", sres[j]);
1026                 printf(":");
1027                 for (j = 0; j < 16; j++)
1028                         printf("%02X", _rand[j]);
1029                 printf("\n");
1030         }
1031
1032         scard_deinit(scard);
1033
1034         return 0;
1035 }
1036
1037
1038 static void eapol_test_terminate(int sig, void *signal_ctx)
1039 {
1040         struct wpa_supplicant *wpa_s = signal_ctx;
1041         wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig);
1042         eloop_terminate();
1043 }
1044
1045
1046 static void usage(void)
1047 {
1048         printf("usage:\n"
1049                "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
1050                "[-s<AS secret>]\\\n"
1051                "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
1052                "           [-M<client MAC address>] [-o<server cert file] \\\n"
1053                "           [-N<attr spec>] \\\n"
1054                "           [-A<client IP>]\n"
1055                "eapol_test scard\n"
1056                "eapol_test sim <PIN> <num triplets> [debug]\n"
1057                "\n");
1058         printf("options:\n"
1059                "  -c<conf> = configuration file\n"
1060                "  -a<AS IP> = IP address of the authentication server, "
1061                "default 127.0.0.1\n"
1062                "  -p<AS port> = UDP port of the authentication server, "
1063                "default 1812\n"
1064                "  -s<AS secret> = shared secret with the authentication "
1065                "server, default 'radius'\n"
1066                "  -A<client IP> = IP address of the client, default: select "
1067                "automatically\n"
1068                "  -r<count> = number of re-authentications\n"
1069                "  -W = wait for a control interface monitor before starting\n"
1070                "  -S = save configuration after authentication\n"
1071                "  -n = no MPPE keys expected\n"
1072                "  -t<timeout> = sets timeout in seconds (default: 30 s)\n"
1073                "  -C<Connect-Info> = RADIUS Connect-Info (default: "
1074                "CONNECT 11Mbps 802.11b)\n"
1075                "  -M<client MAC address> = Set own MAC address "
1076                "(Calling-Station-Id,\n"
1077                "                           default: 02:00:00:00:00:01)\n"
1078                "  -o<server cert file> = Write received server certificate\n"
1079                "                         chain to the specified file\n"
1080                "  -N<attr spec> = send arbitrary attribute specified by:\n"
1081                "                  attr_id:syntax:value or attr_id\n"
1082                "                  attr_id - number id of the attribute\n"
1083                "                  syntax - one of: s, d, x\n"
1084                "                     s = string\n"
1085                "                     d = integer\n"
1086                "                     x = octet string\n"
1087                "                  value - attribute value.\n"
1088                "       When only attr_id is specified, NULL will be used as "
1089                "value.\n"
1090                "       Multiple attributes can be specified by using the "
1091                "option several times.\n");
1092 }
1093
1094
1095 int main(int argc, char *argv[])
1096 {
1097         struct wpa_supplicant wpa_s;
1098         int c, ret = 1, wait_for_monitor = 0, save_config = 0;
1099         char *as_addr = "127.0.0.1";
1100         int as_port = 1812;
1101         char *as_secret = "radius";
1102         char *cli_addr = NULL;
1103         char *conf = NULL;
1104         int timeout = 30;
1105         char *pos;
1106         struct extra_radius_attr *p = NULL, *p1;
1107
1108         if (os_program_init())
1109                 return -1;
1110
1111         hostapd_logger_register_cb(hostapd_logger_cb);
1112
1113         os_memset(&eapol_test, 0, sizeof(eapol_test));
1114         eapol_test.connect_info = "CONNECT 11Mbps 802.11b";
1115         os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN);
1116
1117         wpa_debug_level = 0;
1118         wpa_debug_show_keys = 1;
1119
1120         for (;;) {
1121                 c = getopt(argc, argv, "a:A:c:C:M:nN:o:p:r:s:St:W");
1122                 if (c < 0)
1123                         break;
1124                 switch (c) {
1125                 case 'a':
1126                         as_addr = optarg;
1127                         break;
1128                 case 'A':
1129                         cli_addr = optarg;
1130                         break;
1131                 case 'c':
1132                         conf = optarg;
1133                         break;
1134                 case 'C':
1135                         eapol_test.connect_info = optarg;
1136                         break;
1137                 case 'M':
1138                         if (hwaddr_aton(optarg, eapol_test.own_addr)) {
1139                                 usage();
1140                                 return -1;
1141                         }
1142                         break;
1143                 case 'n':
1144                         eapol_test.no_mppe_keys++;
1145                         break;
1146                 case 'o':
1147                         if (eapol_test.server_cert_file)
1148                                 fclose(eapol_test.server_cert_file);
1149                         eapol_test.server_cert_file = fopen(optarg, "w");
1150                         if (eapol_test.server_cert_file == NULL) {
1151                                 printf("Could not open '%s' for writing\n",
1152                                        optarg);
1153                                 return -1;
1154                         }
1155                         break;
1156                 case 'p':
1157                         as_port = atoi(optarg);
1158                         break;
1159                 case 'r':
1160                         eapol_test.eapol_test_num_reauths = atoi(optarg);
1161                         break;
1162                 case 's':
1163                         as_secret = optarg;
1164                         break;
1165                 case 'S':
1166                         save_config++;
1167                         break;
1168                 case 't':
1169                         timeout = atoi(optarg);
1170                         break;
1171                 case 'W':
1172                         wait_for_monitor++;
1173                         break;
1174                 case 'N':
1175                         p1 = os_zalloc(sizeof(*p1));
1176                         if (p1 == NULL)
1177                                 break;
1178                         if (!p)
1179                                 eapol_test.extra_attrs = p1;
1180                         else
1181                                 p->next = p1;
1182                         p = p1;
1183
1184                         p->type = atoi(optarg);
1185                         pos = os_strchr(optarg, ':');
1186                         if (pos == NULL) {
1187                                 p->syntax = 'n';
1188                                 p->data = NULL;
1189                                 break;
1190                         }
1191
1192                         pos++;
1193                         if (pos[0] == '\0' || pos[1] != ':') {
1194                                 printf("Incorrect format of attribute "
1195                                        "specification\n");
1196                                 break;
1197                         }
1198
1199                         p->syntax = pos[0];
1200                         p->data = pos + 2;
1201                         break;
1202                 default:
1203                         usage();
1204                         return -1;
1205                 }
1206         }
1207
1208         if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
1209                 return scard_test();
1210         }
1211
1212         if (argc > optind && os_strcmp(argv[optind], "sim") == 0) {
1213                 return scard_get_triplets(argc - optind - 1,
1214                                           &argv[optind + 1]);
1215         }
1216
1217         if (conf == NULL) {
1218                 usage();
1219                 printf("Configuration file is required.\n");
1220                 return -1;
1221         }
1222
1223         if (eap_register_methods()) {
1224                 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
1225                 return -1;
1226         }
1227
1228         if (eloop_init()) {
1229                 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
1230                 return -1;
1231         }
1232
1233         os_memset(&wpa_s, 0, sizeof(wpa_s));
1234         eapol_test.wpa_s = &wpa_s;
1235         wpa_s.conf = wpa_config_read(conf, NULL);
1236         if (wpa_s.conf == NULL) {
1237                 printf("Failed to parse configuration file '%s'.\n", conf);
1238                 return -1;
1239         }
1240         if (wpa_s.conf->ssid == NULL) {
1241                 printf("No networks defined.\n");
1242                 return -1;
1243         }
1244
1245         wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
1246                       cli_addr);
1247         wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
1248         if (wpa_s.ctrl_iface == NULL) {
1249                 printf("Failed to initialize control interface '%s'.\n"
1250                        "You may have another eapol_test process already "
1251                        "running or the file was\n"
1252                        "left by an unclean termination of eapol_test in "
1253                        "which case you will need\n"
1254                        "to manually remove this file before starting "
1255                        "eapol_test again.\n",
1256                        wpa_s.conf->ctrl_interface);
1257                 return -1;
1258         }
1259         if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
1260                 return -1;
1261
1262         if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
1263                 return -1;
1264
1265         if (wpas_init_ext_pw(&wpa_s) < 0)
1266                 return -1;
1267
1268         if (wait_for_monitor)
1269                 wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
1270
1271         eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test,
1272                                NULL);
1273         eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL);
1274         eloop_register_signal_terminate(eapol_test_terminate, &wpa_s);
1275         eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s);
1276         eloop_run();
1277
1278         eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL);
1279         eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL);
1280
1281         if (eapol_test_compare_pmk(&eapol_test) == 0 ||
1282             eapol_test.no_mppe_keys)
1283                 ret = 0;
1284         if (eapol_test.auth_timed_out)
1285                 ret = -2;
1286         if (eapol_test.radius_access_reject_received)
1287                 ret = -3;
1288
1289         if (save_config)
1290                 wpa_config_write(conf, wpa_s.conf);
1291
1292         test_eapol_clean(&eapol_test, &wpa_s);
1293
1294         eap_peer_unregister_methods();
1295 #ifdef CONFIG_AP
1296         eap_server_unregister_methods();
1297 #endif /* CONFIG_AP */
1298
1299         eloop_destroy();
1300
1301         if (eapol_test.server_cert_file)
1302                 fclose(eapol_test.server_cert_file);
1303
1304         printf("MPPE keys OK: %d  mismatch: %d\n",
1305                eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
1306         if (eapol_test.num_mppe_mismatch)
1307                 ret = -4;
1308         if (ret)
1309                 printf("FAILURE\n");
1310         else
1311                 printf("SUCCESS\n");
1312
1313         os_program_deinit();
1314
1315         return ret;
1316 }