1/* 2 * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM 3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 * 14 * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM 15 * cards through PC/SC smartcard library. These functions are used to implement 16 * authentication routines for EAP-SIM and EAP-AKA. 17 */ 18 19#include "includes.h" 20#include <winscard.h> 21 22#include "common.h" 23#include "pcsc_funcs.h" 24 25 26/* See ETSI GSM 11.11 and ETSI TS 102 221 for details. 27 * SIM commands: 28 * Command APDU: CLA INS P1 P2 P3 Data 29 * CLA (class of instruction): A0 for GSM, 00 for USIM 30 * INS (instruction) 31 * P1 P2 P3 (parameters, P3 = length of Data) 32 * Response APDU: Data SW1 SW2 33 * SW1 SW2 (Status words) 34 * Commands (INS P1 P2 P3): 35 * SELECT: A4 00 00 02 <file_id, 2 bytes> 36 * GET RESPONSE: C0 00 00 <len> 37 * RUN GSM ALG: 88 00 00 00 <RAND len = 10> 38 * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN 39 * P1 = ID of alg in card 40 * P2 = ID of secret key 41 * READ BINARY: B0 <offset high> <offset low> <len> 42 * READ RECORD: B2 <record number> <mode> <len> 43 * P2 (mode) = '02' (next record), '03' (previous record), 44 * '04' (absolute mode) 45 * VERIFY CHV: 20 00 <CHV number> 08 46 * CHANGE CHV: 24 00 <CHV number> 10 47 * DISABLE CHV: 26 00 01 08 48 * ENABLE CHV: 28 00 01 08 49 * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 50 * SLEEP: FA 00 00 00 51 */ 52 53/* GSM SIM commands */ 54#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 55#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 56#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 57#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 58#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 59#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 60 61/* USIM commands */ 62#define USIM_CLA 0x00 63#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 64#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 65 66#define SIM_RECORD_MODE_ABSOLUTE 0x04 67 68#define USIM_FSP_TEMPL_TAG 0x62 69 70#define USIM_TLV_FILE_DESC 0x82 71#define USIM_TLV_FILE_ID 0x83 72#define USIM_TLV_DF_NAME 0x84 73#define USIM_TLV_PROPR_INFO 0xA5 74#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A 75#define USIM_TLV_FILE_SIZE 0x80 76#define USIM_TLV_TOTAL_FILE_SIZE 0x81 77#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 78#define USIM_TLV_SHORT_FILE_ID 0x88 79 80#define USIM_PS_DO_TAG 0x90 81 82#define AKA_RAND_LEN 16 83#define AKA_AUTN_LEN 16 84#define AKA_AUTS_LEN 14 85#define RES_MAX_LEN 16 86#define IK_LEN 16 87#define CK_LEN 16 88 89 90typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; 91 92struct scard_data { 93 SCARDCONTEXT ctx; 94 SCARDHANDLE card; 95 DWORD protocol; 96 sim_types sim_type; 97 int pin1_required; 98}; 99 100#ifdef __MINGW32_VERSION 101/* MinGW does not yet support WinScard, so load the needed functions 102 * dynamically from winscard.dll for now. */ 103 104static HINSTANCE dll = NULL; /* winscard.dll */ 105 106static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; 107#undef SCARD_PCI_T0 108#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) 109#undef SCARD_PCI_T1 110#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) 111 112 113static WINSCARDAPI LONG WINAPI 114(*dll_SCardEstablishContext)(IN DWORD dwScope, 115 IN LPCVOID pvReserved1, 116 IN LPCVOID pvReserved2, 117 OUT LPSCARDCONTEXT phContext); 118#define SCardEstablishContext dll_SCardEstablishContext 119 120static long (*dll_SCardReleaseContext)(long hContext); 121#define SCardReleaseContext dll_SCardReleaseContext 122 123static WINSCARDAPI LONG WINAPI 124(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, 125 IN LPCSTR mszGroups, 126 OUT LPSTR mszReaders, 127 IN OUT LPDWORD pcchReaders); 128#undef SCardListReaders 129#define SCardListReaders dll_SCardListReadersA 130 131static WINSCARDAPI LONG WINAPI 132(*dll_SCardConnectA)(IN SCARDCONTEXT hContext, 133 IN LPCSTR szReader, 134 IN DWORD dwShareMode, 135 IN DWORD dwPreferredProtocols, 136 OUT LPSCARDHANDLE phCard, 137 OUT LPDWORD pdwActiveProtocol); 138#undef SCardConnect 139#define SCardConnect dll_SCardConnectA 140 141static WINSCARDAPI LONG WINAPI 142(*dll_SCardDisconnect)(IN SCARDHANDLE hCard, 143 IN DWORD dwDisposition); 144#define SCardDisconnect dll_SCardDisconnect 145 146static WINSCARDAPI LONG WINAPI 147(*dll_SCardTransmit)(IN SCARDHANDLE hCard, 148 IN LPCSCARD_IO_REQUEST pioSendPci, 149 IN LPCBYTE pbSendBuffer, 150 IN DWORD cbSendLength, 151 IN OUT LPSCARD_IO_REQUEST pioRecvPci, 152 OUT LPBYTE pbRecvBuffer, 153 IN OUT LPDWORD pcbRecvLength); 154#define SCardTransmit dll_SCardTransmit 155 156static WINSCARDAPI LONG WINAPI 157(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); 158#define SCardBeginTransaction dll_SCardBeginTransaction 159 160static WINSCARDAPI LONG WINAPI 161(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); 162#define SCardEndTransaction dll_SCardEndTransaction 163 164 165static int mingw_load_symbols(void) 166{ 167 char *sym; 168 169 if (dll) 170 return 0; 171 172 dll = LoadLibrary("winscard"); 173 if (dll == NULL) { 174 wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " 175 "library"); 176 return -1; 177 } 178 179#define LOADSYM(s) \ 180 sym = #s; \ 181 dll_ ## s = (void *) GetProcAddress(dll, sym); \ 182 if (dll_ ## s == NULL) \ 183 goto fail; 184 185 LOADSYM(SCardEstablishContext); 186 LOADSYM(SCardReleaseContext); 187 LOADSYM(SCardListReadersA); 188 LOADSYM(SCardConnectA); 189 LOADSYM(SCardDisconnect); 190 LOADSYM(SCardTransmit); 191 LOADSYM(SCardBeginTransaction); 192 LOADSYM(SCardEndTransaction); 193 LOADSYM(g_rgSCardT0Pci); 194 LOADSYM(g_rgSCardT1Pci); 195 196#undef LOADSYM 197 198 return 0; 199 200fail: 201 wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " 202 "winscard.dll", sym); 203 FreeLibrary(dll); 204 dll = NULL; 205 return -1; 206} 207 208 209static void mingw_unload_symbols(void) 210{ 211 if (dll == NULL) 212 return; 213 214 FreeLibrary(dll); 215 dll = NULL; 216} 217 218#else /* __MINGW32_VERSION */ 219 220#define mingw_load_symbols() 0 221#define mingw_unload_symbols() do { } while (0) 222 223#endif /* __MINGW32_VERSION */ 224 225 226static int _scard_select_file(struct scard_data *scard, unsigned short file_id, 227 unsigned char *buf, size_t *buf_len, 228 sim_types sim_type, unsigned char *aid, 229 size_t aidlen); 230static int scard_select_file(struct scard_data *scard, unsigned short file_id, 231 unsigned char *buf, size_t *buf_len); 232static int scard_verify_pin(struct scard_data *scard, const char *pin); 233static int scard_get_record_len(struct scard_data *scard, 234 unsigned char recnum, unsigned char mode); 235static int scard_read_record(struct scard_data *scard, 236 unsigned char *data, size_t len, 237 unsigned char recnum, unsigned char mode); 238 239 240static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, 241 int *ps_do, int *file_len) 242{ 243 unsigned char *pos, *end; 244 245 if (ps_do) 246 *ps_do = -1; 247 if (file_len) 248 *file_len = -1; 249 250 pos = buf; 251 end = pos + buf_len; 252 if (*pos != USIM_FSP_TEMPL_TAG) { 253 wpa_printf(MSG_DEBUG, "SCARD: file header did not " 254 "start with FSP template tag"); 255 return -1; 256 } 257 pos++; 258 if (pos >= end) 259 return -1; 260 if ((pos + pos[0]) < end) 261 end = pos + 1 + pos[0]; 262 pos++; 263 wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", 264 pos, end - pos); 265 266 while (pos + 1 < end) { 267 wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV " 268 "0x%02x len=%d", pos[0], pos[1]); 269 if (pos + 2 + pos[1] > end) 270 break; 271 272 if (pos[0] == USIM_TLV_FILE_SIZE && 273 (pos[1] == 1 || pos[1] == 2) && file_len) { 274 if (pos[1] == 1) 275 *file_len = (int) pos[2]; 276 else 277 *file_len = ((int) pos[2] << 8) | 278 (int) pos[3]; 279 wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", 280 *file_len); 281 } 282 283 if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE && 284 pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && 285 pos[3] >= 1 && ps_do) { 286 wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", 287 pos[4]); 288 *ps_do = (int) pos[4]; 289 } 290 291 pos += 2 + pos[1]; 292 293 if (pos == end) 294 return 0; 295 } 296 return -1; 297} 298 299 300static int scard_pin_needed(struct scard_data *scard, 301 unsigned char *hdr, size_t hlen) 302{ 303 if (scard->sim_type == SCARD_GSM_SIM) { 304 if (hlen > SCARD_CHV1_OFFSET && 305 !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) 306 return 1; 307 return 0; 308 } 309 310 if (scard->sim_type == SCARD_USIM) { 311 int ps_do; 312 if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) 313 return -1; 314 /* TODO: there could be more than one PS_DO entry because of 315 * multiple PINs in key reference.. */ 316 if (ps_do > 0 && (ps_do & 0x80)) 317 return 1; 318 return 0; 319 } 320 321 return -1; 322} 323 324 325static int scard_get_aid(struct scard_data *scard, unsigned char *aid, 326 size_t maxlen) 327{ 328 int rlen, rec; 329 struct efdir { 330 unsigned char appl_template_tag; /* 0x61 */ 331 unsigned char appl_template_len; 332 unsigned char appl_id_tag; /* 0x4f */ 333 unsigned char aid_len; 334 unsigned char rid[5]; 335 unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ 336 } *efdir; 337 unsigned char buf[100]; 338 size_t blen; 339 340 efdir = (struct efdir *) buf; 341 blen = sizeof(buf); 342 if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { 343 wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); 344 return -1; 345 } 346 wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); 347 348 for (rec = 1; rec < 10; rec++) { 349 rlen = scard_get_record_len(scard, rec, 350 SIM_RECORD_MODE_ABSOLUTE); 351 if (rlen < 0) { 352 wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " 353 "record length"); 354 return -1; 355 } 356 blen = sizeof(buf); 357 if (rlen > (int) blen) { 358 wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); 359 return -1; 360 } 361 if (scard_read_record(scard, buf, rlen, rec, 362 SIM_RECORD_MODE_ABSOLUTE) < 0) { 363 wpa_printf(MSG_DEBUG, "SCARD: Failed to read " 364 "EF_DIR record %d", rec); 365 return -1; 366 } 367 wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); 368 369 if (efdir->appl_template_tag != 0x61) { 370 wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 371 "template tag 0x%x", 372 efdir->appl_template_tag); 373 continue; 374 } 375 376 if (efdir->appl_template_len > rlen - 2) { 377 wpa_printf(MSG_DEBUG, "SCARD: Too long application " 378 "template (len=%d rlen=%d)", 379 efdir->appl_template_len, rlen); 380 continue; 381 } 382 383 if (efdir->appl_id_tag != 0x4f) { 384 wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 385 "identifier tag 0x%x", efdir->appl_id_tag); 386 continue; 387 } 388 389 if (efdir->aid_len < 1 || efdir->aid_len > 16) { 390 wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", 391 efdir->aid_len); 392 continue; 393 } 394 395 wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", 396 efdir->rid, efdir->aid_len); 397 398 if (efdir->appl_code[0] == 0x10 && 399 efdir->appl_code[1] == 0x02) { 400 wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " 401 "EF_DIR record %d", rec); 402 break; 403 } 404 } 405 406 if (rec >= 10) { 407 wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " 408 "from EF_DIR records"); 409 return -1; 410 } 411 412 if (efdir->aid_len > maxlen) { 413 wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); 414 return -1; 415 } 416 417 os_memcpy(aid, efdir->rid, efdir->aid_len); 418 419 return efdir->aid_len; 420} 421 422 423/** 424 * scard_init - Initialize SIM/USIM connection using PC/SC 425 * @sim_type: Allowed SIM types (SIM, USIM, or both) 426 * Returns: Pointer to private data structure, or %NULL on failure 427 * 428 * This function is used to initialize SIM/USIM connection. PC/SC is used to 429 * open connection to the SIM/USIM card and the card is verified to support the 430 * selected sim_type. In addition, local flag is set if a PIN is needed to 431 * access some of the card functions. Once the connection is not needed 432 * anymore, scard_deinit() can be used to close it. 433 */ 434struct scard_data * scard_init(scard_sim_type sim_type) 435{ 436 long ret; 437 unsigned long len; 438 struct scard_data *scard; 439#ifdef CONFIG_NATIVE_WINDOWS 440 TCHAR *readers = NULL; 441#else /* CONFIG_NATIVE_WINDOWS */ 442 char *readers = NULL; 443#endif /* CONFIG_NATIVE_WINDOWS */ 444 unsigned char buf[100]; 445 size_t blen; 446 int transaction = 0; 447 int pin_needed; 448 449 wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); 450 if (mingw_load_symbols()) 451 return NULL; 452 scard = os_zalloc(sizeof(*scard)); 453 if (scard == NULL) 454 return NULL; 455 456 ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, 457 &scard->ctx); 458 if (ret != SCARD_S_SUCCESS) { 459 wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " 460 "context (err=%ld)", ret); 461 goto failed; 462 } 463 464 ret = SCardListReaders(scard->ctx, NULL, NULL, &len); 465 if (ret != SCARD_S_SUCCESS) { 466 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " 467 "(err=%ld)", ret); 468 goto failed; 469 } 470 471#ifdef UNICODE 472 len *= 2; 473#endif /* UNICODE */ 474 readers = os_malloc(len); 475 if (readers == NULL) { 476 wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); 477 goto failed; 478 } 479 480 ret = SCardListReaders(scard->ctx, NULL, readers, &len); 481 if (ret != SCARD_S_SUCCESS) { 482 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " 483 "(err=%ld)", ret); 484 goto failed; 485 } 486 if (len < 3) { 487 wpa_printf(MSG_WARNING, "SCARD: No smart card readers " 488 "available."); 489 goto failed; 490 } 491 /* readers is a list of available reader. Last entry is terminated with 492 * double NUL. 493 * TODO: add support for selecting the reader; now just use the first 494 * one.. */ 495#ifdef UNICODE 496 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); 497#else /* UNICODE */ 498 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); 499#endif /* UNICODE */ 500 501 ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, 502 SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); 503 if (ret != SCARD_S_SUCCESS) { 504 if (ret == (long) SCARD_E_NO_SMARTCARD) 505 wpa_printf(MSG_INFO, "No smart card inserted."); 506 else 507 wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); 508 goto failed; 509 } 510 511 os_free(readers); 512 readers = NULL; 513 514 wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", 515 (unsigned int) scard->card, scard->protocol, 516 scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); 517 518 ret = SCardBeginTransaction(scard->card); 519 if (ret != SCARD_S_SUCCESS) { 520 wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " 521 "0x%x", (unsigned int) ret); 522 goto failed; 523 } 524 transaction = 1; 525 526 blen = sizeof(buf); 527 528 scard->sim_type = SCARD_GSM_SIM; 529 if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { 530 wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); 531 if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, 532 SCARD_USIM, NULL, 0)) { 533 wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); 534 if (sim_type == SCARD_USIM_ONLY) 535 goto failed; 536 wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM"); 537 scard->sim_type = SCARD_GSM_SIM; 538 } else { 539 wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); 540 scard->sim_type = SCARD_USIM; 541 } 542 } 543 544 if (scard->sim_type == SCARD_GSM_SIM) { 545 blen = sizeof(buf); 546 if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { 547 wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); 548 goto failed; 549 } 550 551 blen = sizeof(buf); 552 if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { 553 wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); 554 goto failed; 555 } 556 } else { 557 unsigned char aid[32]; 558 int aid_len; 559 560 aid_len = scard_get_aid(scard, aid, sizeof(aid)); 561 if (aid_len < 0) { 562 wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " 563 "3G USIM app - try to use standard 3G RID"); 564 os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); 565 aid_len = 5; 566 } 567 wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); 568 569 /* Select based on AID = 3G RID from EF_DIR. This is usually 570 * starting with A0 00 00 00 87. */ 571 blen = sizeof(buf); 572 if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, 573 aid, aid_len)) { 574 wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " 575 "app"); 576 wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", 577 aid, aid_len); 578 goto failed; 579 } 580 } 581 582 /* Verify whether CHV1 (PIN1) is needed to access the card. */ 583 pin_needed = scard_pin_needed(scard, buf, blen); 584 if (pin_needed < 0) { 585 wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " 586 "is needed"); 587 goto failed; 588 } 589 if (pin_needed) { 590 scard->pin1_required = 1; 591 wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); 592 } 593 594 ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 595 if (ret != SCARD_S_SUCCESS) { 596 wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " 597 "0x%x", (unsigned int) ret); 598 } 599 600 return scard; 601 602failed: 603 if (transaction) 604 SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 605 os_free(readers); 606 scard_deinit(scard); 607 return NULL; 608} 609 610 611/** 612 * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands 613 * @scard: Pointer to private data from scard_init() 614 * @pin: PIN code as an ASCII string (e.g., "1234") 615 * Returns: 0 on success, -1 on failure 616 */ 617int scard_set_pin(struct scard_data *scard, const char *pin) 618{ 619 if (scard == NULL) 620 return -1; 621 622 /* Verify whether CHV1 (PIN1) is needed to access the card. */ 623 if (scard->pin1_required) { 624 if (pin == NULL) { 625 wpa_printf(MSG_DEBUG, "No PIN configured for SIM " 626 "access"); 627 return -1; 628 } 629 if (scard_verify_pin(scard, pin)) { 630 wpa_printf(MSG_INFO, "PIN verification failed for " 631 "SIM access"); 632 return -1; 633 } 634 } 635 636 return 0; 637} 638 639 640/** 641 * scard_deinit - Deinitialize SIM/USIM connection 642 * @scard: Pointer to private data from scard_init() 643 * 644 * This function closes the SIM/USIM connect opened with scard_init(). 645 */ 646void scard_deinit(struct scard_data *scard) 647{ 648 long ret; 649 650 if (scard == NULL) 651 return; 652 653 wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); 654 if (scard->card) { 655 ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); 656 if (ret != SCARD_S_SUCCESS) { 657 wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " 658 "smart card (err=%ld)", ret); 659 } 660 } 661 662 if (scard->ctx) { 663 ret = SCardReleaseContext(scard->ctx); 664 if (ret != SCARD_S_SUCCESS) { 665 wpa_printf(MSG_DEBUG, "Failed to release smart card " 666 "context (err=%ld)", ret); 667 } 668 } 669 os_free(scard); 670 mingw_unload_symbols(); 671} 672 673 674static long scard_transmit(struct scard_data *scard, 675 unsigned char *_send, size_t send_len, 676 unsigned char *_recv, size_t *recv_len) 677{ 678 long ret; 679 unsigned long rlen; 680 681 wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", 682 _send, send_len); 683 rlen = *recv_len; 684 ret = SCardTransmit(scard->card, 685 scard->protocol == SCARD_PROTOCOL_T1 ? 686 SCARD_PCI_T1 : SCARD_PCI_T0, 687 _send, (unsigned long) send_len, 688 NULL, _recv, &rlen); 689 *recv_len = rlen; 690 if (ret == SCARD_S_SUCCESS) { 691 wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", 692 _recv, rlen); 693 } else { 694 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 695 "(err=0x%lx)", ret); 696 } 697 return ret; 698} 699 700 701static int _scard_select_file(struct scard_data *scard, unsigned short file_id, 702 unsigned char *buf, size_t *buf_len, 703 sim_types sim_type, unsigned char *aid, 704 size_t aidlen) 705{ 706 long ret; 707 unsigned char resp[3]; 708 unsigned char cmd[50] = { SIM_CMD_SELECT }; 709 int cmdlen; 710 unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 711 size_t len, rlen; 712 713 if (sim_type == SCARD_USIM) { 714 cmd[0] = USIM_CLA; 715 cmd[3] = 0x04; 716 get_resp[0] = USIM_CLA; 717 } 718 719 wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); 720 if (aid) { 721 wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", 722 aid, aidlen); 723 if (5 + aidlen > sizeof(cmd)) 724 return -1; 725 cmd[2] = 0x04; /* Select by AID */ 726 cmd[4] = aidlen; /* len */ 727 os_memcpy(cmd + 5, aid, aidlen); 728 cmdlen = 5 + aidlen; 729 } else { 730 cmd[5] = file_id >> 8; 731 cmd[6] = file_id & 0xff; 732 cmdlen = 7; 733 } 734 len = sizeof(resp); 735 ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 736 if (ret != SCARD_S_SUCCESS) { 737 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 738 "(err=0x%lx)", ret); 739 return -1; 740 } 741 742 if (len != 2) { 743 wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " 744 "%d (expected 2)", (int) len); 745 return -1; 746 } 747 748 if (resp[0] == 0x98 && resp[1] == 0x04) { 749 /* Security status not satisfied (PIN_WLAN) */ 750 wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " 751 "(PIN_WLAN)"); 752 return -1; 753 } 754 755 if (resp[0] == 0x6e) { 756 wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); 757 return -1; 758 } 759 760 if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { 761 wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " 762 "(expected 0x61, 0x6c, or 0x9f)", resp[0]); 763 return -1; 764 } 765 /* Normal ending of command; resp[1] bytes available */ 766 get_resp[4] = resp[1]; 767 wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", 768 resp[1]); 769 770 rlen = *buf_len; 771 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); 772 if (ret == SCARD_S_SUCCESS) { 773 *buf_len = resp[1] < rlen ? resp[1] : rlen; 774 return 0; 775 } 776 777 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); 778 return -1; 779} 780 781 782static int scard_select_file(struct scard_data *scard, unsigned short file_id, 783 unsigned char *buf, size_t *buf_len) 784{ 785 return _scard_select_file(scard, file_id, buf, buf_len, 786 scard->sim_type, NULL, 0); 787} 788 789 790static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, 791 unsigned char mode) 792{ 793 unsigned char buf[255]; 794 unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 795 size_t blen; 796 long ret; 797 798 if (scard->sim_type == SCARD_USIM) 799 cmd[0] = USIM_CLA; 800 cmd[2] = recnum; 801 cmd[3] = mode; 802 cmd[4] = sizeof(buf); 803 804 blen = sizeof(buf); 805 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 806 if (ret != SCARD_S_SUCCESS) { 807 wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " 808 "length for record %d", recnum); 809 return -1; 810 } 811 812 wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", 813 buf, blen); 814 815 if (blen < 2 || buf[0] != 0x6c) { 816 wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " 817 "length determination"); 818 return -1; 819 } 820 821 return buf[1]; 822} 823 824 825static int scard_read_record(struct scard_data *scard, 826 unsigned char *data, size_t len, 827 unsigned char recnum, unsigned char mode) 828{ 829 unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 830 size_t blen = len + 3; 831 unsigned char *buf; 832 long ret; 833 834 if (scard->sim_type == SCARD_USIM) 835 cmd[0] = USIM_CLA; 836 cmd[2] = recnum; 837 cmd[3] = mode; 838 cmd[4] = len; 839 840 buf = os_malloc(blen); 841 if (buf == NULL) 842 return -1; 843 844 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 845 if (ret != SCARD_S_SUCCESS) { 846 os_free(buf); 847 return -2; 848 } 849 if (blen != len + 2) { 850 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 851 "length %ld (expected %ld)", 852 (long) blen, (long) len + 2); 853 os_free(buf); 854 return -3; 855 } 856 857 if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 858 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 859 "status %02x %02x (expected 90 00)", 860 buf[len], buf[len + 1]); 861 os_free(buf); 862 return -4; 863 } 864 865 os_memcpy(data, buf, len); 866 os_free(buf); 867 868 return 0; 869} 870 871 872static int scard_read_file(struct scard_data *scard, 873 unsigned char *data, size_t len) 874{ 875 unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; 876 size_t blen = len + 3; 877 unsigned char *buf; 878 long ret; 879 880 cmd[4] = len; 881 882 buf = os_malloc(blen); 883 if (buf == NULL) 884 return -1; 885 886 if (scard->sim_type == SCARD_USIM) 887 cmd[0] = USIM_CLA; 888 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 889 if (ret != SCARD_S_SUCCESS) { 890 os_free(buf); 891 return -2; 892 } 893 if (blen != len + 2) { 894 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 895 "length %ld (expected %ld)", 896 (long) blen, (long) len + 2); 897 os_free(buf); 898 return -3; 899 } 900 901 if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 902 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 903 "status %02x %02x (expected 90 00)", 904 buf[len], buf[len + 1]); 905 os_free(buf); 906 return -4; 907 } 908 909 os_memcpy(data, buf, len); 910 os_free(buf); 911 912 return 0; 913} 914 915 916static int scard_verify_pin(struct scard_data *scard, const char *pin) 917{ 918 long ret; 919 unsigned char resp[3]; 920 unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; 921 size_t len; 922 923 wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); 924 925 if (pin == NULL || os_strlen(pin) > 8) 926 return -1; 927 928 if (scard->sim_type == SCARD_USIM) 929 cmd[0] = USIM_CLA; 930 os_memcpy(cmd + 5, pin, os_strlen(pin)); 931 os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); 932 933 len = sizeof(resp); 934 ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 935 if (ret != SCARD_S_SUCCESS) 936 return -2; 937 938 if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { 939 wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); 940 return -1; 941 } 942 943 wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); 944 return 0; 945} 946 947 948/** 949 * scard_get_imsi - Read IMSI from SIM/USIM card 950 * @scard: Pointer to private data from scard_init() 951 * @imsi: Buffer for IMSI 952 * @len: Length of imsi buffer; set to IMSI length on success 953 * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file 954 * selection returns invalid result code, -3 if parsing FSP template file fails 955 * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set 956 * to needed length), -5 if reading IMSI file fails. 957 * 958 * This function can be used to read IMSI from the SIM/USIM card. If the IMSI 959 * file is PIN protected, scard_set_pin() must have been used to set the 960 * correct PIN code before calling scard_get_imsi(). 961 */ 962int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) 963{ 964 unsigned char buf[100]; 965 size_t blen, imsilen, i; 966 char *pos; 967 968 wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); 969 blen = sizeof(buf); 970 if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) 971 return -1; 972 if (blen < 4) { 973 wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " 974 "header (len=%ld)", (long) blen); 975 return -2; 976 } 977 978 if (scard->sim_type == SCARD_GSM_SIM) { 979 blen = (buf[2] << 8) | buf[3]; 980 } else { 981 int file_size; 982 if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) 983 return -3; 984 blen = file_size; 985 } 986 if (blen < 2 || blen > sizeof(buf)) { 987 wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", 988 (long) blen); 989 return -3; 990 } 991 992 imsilen = (blen - 2) * 2 + 1; 993 wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", 994 (long) blen, (long) imsilen); 995 if (blen < 2 || imsilen > *len) { 996 *len = imsilen; 997 return -4; 998 } 999 1000 if (scard_read_file(scard, buf, blen)) 1001 return -5; 1002 1003 pos = imsi; 1004 *pos++ = '0' + (buf[1] >> 4 & 0x0f); 1005 for (i = 2; i < blen; i++) { 1006 unsigned char digit; 1007 1008 digit = buf[i] & 0x0f; 1009 if (digit < 10) 1010 *pos++ = '0' + digit; 1011 else 1012 imsilen--; 1013 1014 digit = buf[i] >> 4 & 0x0f; 1015 if (digit < 10) 1016 *pos++ = '0' + digit; 1017 else 1018 imsilen--; 1019 } 1020 *len = imsilen; 1021 1022 return 0; 1023} 1024 1025 1026/** 1027 * scard_gsm_auth - Run GSM authentication command on SIM card 1028 * @scard: Pointer to private data from scard_init() 1029 * @_rand: 16-byte RAND value from HLR/AuC 1030 * @sres: 4-byte buffer for SRES 1031 * @kc: 8-byte buffer for Kc 1032 * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, 1033 * -2 if authentication command execution fails, -3 if unknown response code 1034 * for authentication command is received, -4 if reading of response fails, 1035 * -5 if if response data is of unexpected length 1036 * 1037 * This function performs GSM authentication using SIM/USIM card and the 1038 * provided RAND value from HLR/AuC. If authentication command can be completed 1039 * successfully, SRES and Kc values will be written into sres and kc buffers. 1040 */ 1041int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, 1042 unsigned char *sres, unsigned char *kc) 1043{ 1044 unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; 1045 int cmdlen; 1046 unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 1047 unsigned char resp[3], buf[12 + 3 + 2]; 1048 size_t len; 1049 long ret; 1050 1051 if (scard == NULL) 1052 return -1; 1053 1054 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); 1055 if (scard->sim_type == SCARD_GSM_SIM) { 1056 cmdlen = 5 + 16; 1057 os_memcpy(cmd + 5, _rand, 16); 1058 } else { 1059 cmdlen = 5 + 1 + 16; 1060 cmd[0] = USIM_CLA; 1061 cmd[3] = 0x80; 1062 cmd[4] = 17; 1063 cmd[5] = 16; 1064 os_memcpy(cmd + 6, _rand, 16); 1065 } 1066 len = sizeof(resp); 1067 ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 1068 if (ret != SCARD_S_SUCCESS) 1069 return -2; 1070 1071 if ((scard->sim_type == SCARD_GSM_SIM && 1072 (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || 1073 (scard->sim_type == SCARD_USIM && 1074 (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { 1075 wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " 1076 "auth request (len=%ld resp=%02x %02x)", 1077 (long) len, resp[0], resp[1]); 1078 return -3; 1079 } 1080 get_resp[4] = resp[1]; 1081 1082 len = sizeof(buf); 1083 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 1084 if (ret != SCARD_S_SUCCESS) 1085 return -4; 1086 1087 if (scard->sim_type == SCARD_GSM_SIM) { 1088 if (len != 4 + 8 + 2) { 1089 wpa_printf(MSG_WARNING, "SCARD: unexpected data " 1090 "length for GSM auth (len=%ld, expected 14)", 1091 (long) len); 1092 return -5; 1093 } 1094 os_memcpy(sres, buf, 4); 1095 os_memcpy(kc, buf + 4, 8); 1096 } else { 1097 if (len != 1 + 4 + 1 + 8 + 2) { 1098 wpa_printf(MSG_WARNING, "SCARD: unexpected data " 1099 "length for USIM auth (len=%ld, " 1100 "expected 16)", (long) len); 1101 return -5; 1102 } 1103 if (buf[0] != 4 || buf[5] != 8) { 1104 wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " 1105 "length (%d %d, expected 4 8)", 1106 buf[0], buf[5]); 1107 } 1108 os_memcpy(sres, buf + 1, 4); 1109 os_memcpy(kc, buf + 6, 8); 1110 } 1111 1112 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); 1113 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); 1114 1115 return 0; 1116} 1117 1118 1119/** 1120 * scard_umts_auth - Run UMTS authentication command on USIM card 1121 * @scard: Pointer to private data from scard_init() 1122 * @_rand: 16-byte RAND value from HLR/AuC 1123 * @autn: 16-byte AUTN value from HLR/AuC 1124 * @res: 16-byte buffer for RES 1125 * @res_len: Variable that will be set to RES length 1126 * @ik: 16-byte buffer for IK 1127 * @ck: 16-byte buffer for CK 1128 * @auts: 14-byte buffer for AUTS 1129 * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization 1130 * failure 1131 * 1132 * This function performs AKA authentication using USIM card and the provided 1133 * RAND and AUTN values from HLR/AuC. If authentication command can be 1134 * completed successfully, RES, IK, and CK values will be written into provided 1135 * buffers and res_len is set to length of received RES value. If USIM reports 1136 * synchronization failure, the received AUTS value will be written into auts 1137 * buffer. In this case, RES, IK, and CK are not valid. 1138 */ 1139int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, 1140 const unsigned char *autn, 1141 unsigned char *res, size_t *res_len, 1142 unsigned char *ik, unsigned char *ck, unsigned char *auts) 1143{ 1144 unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = 1145 { USIM_CMD_RUN_UMTS_ALG }; 1146 unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; 1147 unsigned char resp[3], buf[64], *pos, *end; 1148 size_t len; 1149 long ret; 1150 1151 if (scard == NULL) 1152 return -1; 1153 1154 if (scard->sim_type == SCARD_GSM_SIM) { 1155 wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " 1156 "auth"); 1157 return -1; 1158 } 1159 1160 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); 1161 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); 1162 cmd[5] = AKA_RAND_LEN; 1163 os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); 1164 cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; 1165 os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); 1166 1167 len = sizeof(resp); 1168 ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 1169 if (ret != SCARD_S_SUCCESS) 1170 return -1; 1171 1172 if (len <= sizeof(resp)) 1173 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); 1174 1175 if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { 1176 wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " 1177 "MAC != XMAC"); 1178 return -1; 1179 } else if (len != 2 || resp[0] != 0x61) { 1180 wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " 1181 "auth request (len=%ld resp=%02x %02x)", 1182 (long) len, resp[0], resp[1]); 1183 return -1; 1184 } 1185 get_resp[4] = resp[1]; 1186 1187 len = sizeof(buf); 1188 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 1189 if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) 1190 return -1; 1191 1192 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); 1193 if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && 1194 buf[1] == AKA_AUTS_LEN) { 1195 wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); 1196 os_memcpy(auts, buf + 2, AKA_AUTS_LEN); 1197 wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); 1198 return -2; 1199 } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { 1200 pos = buf + 1; 1201 end = buf + len; 1202 1203 /* RES */ 1204 if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { 1205 wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); 1206 return -1; 1207 } 1208 *res_len = *pos++; 1209 os_memcpy(res, pos, *res_len); 1210 pos += *res_len; 1211 wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); 1212 1213 /* CK */ 1214 if (pos[0] != CK_LEN || pos + CK_LEN > end) { 1215 wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); 1216 return -1; 1217 } 1218 pos++; 1219 os_memcpy(ck, pos, CK_LEN); 1220 pos += CK_LEN; 1221 wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); 1222 1223 /* IK */ 1224 if (pos[0] != IK_LEN || pos + IK_LEN > end) { 1225 wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); 1226 return -1; 1227 } 1228 pos++; 1229 os_memcpy(ik, pos, IK_LEN); 1230 pos += IK_LEN; 1231 wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); 1232 1233 return 0; 1234 } 1235 1236 wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); 1237 return -1; 1238} 1239