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