1 /* 2 * WPA Supplicant - test code 3 * Copyright (c) 2003-2012, Jouni Malinen <j (at) 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 } 1317