00001
00020 #include "includes.h"
00021 #include <winscard.h>
00022
00023 #include "common.h"
00024 #include "pcsc_funcs.h"
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02
00056 #define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10
00057 #define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00
00058 #define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00
00059 #define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00
00060 #define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
00061
00062
00063 #define USIM_CLA 0x00
00064 #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
00065 #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
00066
00067 #define SIM_RECORD_MODE_ABSOLUTE 0x04
00068
00069 #define USIM_FSP_TEMPL_TAG 0x62
00070
00071 #define USIM_TLV_FILE_DESC 0x82
00072 #define USIM_TLV_FILE_ID 0x83
00073 #define USIM_TLV_DF_NAME 0x84
00074 #define USIM_TLV_PROPR_INFO 0xA5
00075 #define USIM_TLV_LIFE_CYCLE_STATUS 0x8A
00076 #define USIM_TLV_FILE_SIZE 0x80
00077 #define USIM_TLV_TOTAL_FILE_SIZE 0x81
00078 #define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
00079 #define USIM_TLV_SHORT_FILE_ID 0x88
00080
00081 #define USIM_PS_DO_TAG 0x90
00082
00083 #define AKA_RAND_LEN 16
00084 #define AKA_AUTN_LEN 16
00085 #define AKA_AUTS_LEN 14
00086 #define RES_MAX_LEN 16
00087 #define IK_LEN 16
00088 #define CK_LEN 16
00089
00090
00091 typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
00092
00093 struct scard_data {
00094 SCARDCONTEXT ctx;
00095 SCARDHANDLE card;
00096 DWORD protocol;
00097 sim_types sim_type;
00098 int pin1_required;
00099 };
00100
00101 #ifdef __MINGW32_VERSION
00102
00103
00104
00105 static HINSTANCE dll = NULL;
00106
00107 static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
00108 #undef SCARD_PCI_T0
00109 #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
00110 #undef SCARD_PCI_T1
00111 #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
00112
00113
00114 static WINSCARDAPI LONG WINAPI
00115 (*dll_SCardEstablishContext)(IN DWORD dwScope,
00116 IN LPCVOID pvReserved1,
00117 IN LPCVOID pvReserved2,
00118 OUT LPSCARDCONTEXT phContext);
00119 #define SCardEstablishContext dll_SCardEstablishContext
00120
00121 static long (*dll_SCardReleaseContext)(long hContext);
00122 #define SCardReleaseContext dll_SCardReleaseContext
00123
00124 static WINSCARDAPI LONG WINAPI
00125 (*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
00126 IN LPCSTR mszGroups,
00127 OUT LPSTR mszReaders,
00128 IN OUT LPDWORD pcchReaders);
00129 #undef SCardListReaders
00130 #define SCardListReaders dll_SCardListReadersA
00131
00132 static WINSCARDAPI LONG WINAPI
00133 (*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
00134 IN LPCSTR szReader,
00135 IN DWORD dwShareMode,
00136 IN DWORD dwPreferredProtocols,
00137 OUT LPSCARDHANDLE phCard,
00138 OUT LPDWORD pdwActiveProtocol);
00139 #undef SCardConnect
00140 #define SCardConnect dll_SCardConnectA
00141
00142 static WINSCARDAPI LONG WINAPI
00143 (*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
00144 IN DWORD dwDisposition);
00145 #define SCardDisconnect dll_SCardDisconnect
00146
00147 static WINSCARDAPI LONG WINAPI
00148 (*dll_SCardTransmit)(IN SCARDHANDLE hCard,
00149 IN LPCSCARD_IO_REQUEST pioSendPci,
00150 IN LPCBYTE pbSendBuffer,
00151 IN DWORD cbSendLength,
00152 IN OUT LPSCARD_IO_REQUEST pioRecvPci,
00153 OUT LPBYTE pbRecvBuffer,
00154 IN OUT LPDWORD pcbRecvLength);
00155 #define SCardTransmit dll_SCardTransmit
00156
00157 static WINSCARDAPI LONG WINAPI
00158 (*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
00159 #define SCardBeginTransaction dll_SCardBeginTransaction
00160
00161 static WINSCARDAPI LONG WINAPI
00162 (*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
00163 #define SCardEndTransaction dll_SCardEndTransaction
00164
00165
00166 static int mingw_load_symbols(void)
00167 {
00168 char *sym;
00169
00170 if (dll)
00171 return 0;
00172
00173 dll = LoadLibrary("winscard");
00174 if (dll == NULL) {
00175 wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
00176 "library");
00177 return -1;
00178 }
00179
00180 #define LOADSYM(s) \
00181 sym = #s; \
00182 dll_ ## s = (void *) GetProcAddress(dll, sym); \
00183 if (dll_ ## s == NULL) \
00184 goto fail;
00185
00186 LOADSYM(SCardEstablishContext);
00187 LOADSYM(SCardReleaseContext);
00188 LOADSYM(SCardListReadersA);
00189 LOADSYM(SCardConnectA);
00190 LOADSYM(SCardDisconnect);
00191 LOADSYM(SCardTransmit);
00192 LOADSYM(SCardBeginTransaction);
00193 LOADSYM(SCardEndTransaction);
00194 LOADSYM(g_rgSCardT0Pci);
00195 LOADSYM(g_rgSCardT1Pci);
00196
00197 #undef LOADSYM
00198
00199 return 0;
00200
00201 fail:
00202 wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
00203 "winscard.dll", sym);
00204 FreeLibrary(dll);
00205 dll = NULL;
00206 return -1;
00207 }
00208
00209
00210 static void mingw_unload_symbols(void)
00211 {
00212 if (dll == NULL)
00213 return;
00214
00215 FreeLibrary(dll);
00216 dll = NULL;
00217 }
00218
00219 #else
00220
00221 #define mingw_load_symbols() 0
00222 #define mingw_unload_symbols() do { } while (0)
00223
00224 #endif
00225
00226
00227 static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
00228 unsigned char *buf, size_t *buf_len,
00229 sim_types sim_type, unsigned char *aid,
00230 size_t aidlen);
00231 static int scard_select_file(struct scard_data *scard, unsigned short file_id,
00232 unsigned char *buf, size_t *buf_len);
00233 static int scard_verify_pin(struct scard_data *scard, const char *pin);
00234 static int scard_get_record_len(struct scard_data *scard,
00235 unsigned char recnum, unsigned char mode);
00236 static int scard_read_record(struct scard_data *scard,
00237 unsigned char *data, size_t len,
00238 unsigned char recnum, unsigned char mode);
00239
00240
00241 static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
00242 int *ps_do, int *file_len)
00243 {
00244 unsigned char *pos, *end;
00245
00246 if (ps_do)
00247 *ps_do = -1;
00248 if (file_len)
00249 *file_len = -1;
00250
00251 pos = buf;
00252 end = pos + buf_len;
00253 if (*pos != USIM_FSP_TEMPL_TAG) {
00254 wpa_printf(MSG_DEBUG, "SCARD: file header did not "
00255 "start with FSP template tag");
00256 return -1;
00257 }
00258 pos++;
00259 if (pos >= end)
00260 return -1;
00261 if ((pos + pos[0]) < end)
00262 end = pos + 1 + pos[0];
00263 pos++;
00264 wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
00265 pos, end - pos);
00266
00267 while (pos + 1 < end) {
00268 wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
00269 "0x%02x len=%d", pos[0], pos[1]);
00270 if (pos + 2 + pos[1] > end)
00271 break;
00272
00273 if (pos[0] == USIM_TLV_FILE_SIZE &&
00274 (pos[1] == 1 || pos[1] == 2) && file_len) {
00275 if (pos[1] == 1)
00276 *file_len = (int) pos[2];
00277 else
00278 *file_len = ((int) pos[2] << 8) |
00279 (int) pos[3];
00280 wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
00281 *file_len);
00282 }
00283
00284 if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
00285 pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
00286 pos[3] >= 1 && ps_do) {
00287 wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
00288 pos[4]);
00289 *ps_do = (int) pos[4];
00290 }
00291
00292 pos += 2 + pos[1];
00293
00294 if (pos == end)
00295 return 0;
00296 }
00297 return -1;
00298 }
00299
00300
00301 static int scard_pin_needed(struct scard_data *scard,
00302 unsigned char *hdr, size_t hlen)
00303 {
00304 if (scard->sim_type == SCARD_GSM_SIM) {
00305 if (hlen > SCARD_CHV1_OFFSET &&
00306 !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
00307 return 1;
00308 return 0;
00309 }
00310
00311 if (scard->sim_type == SCARD_USIM) {
00312 int ps_do;
00313 if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
00314 return -1;
00315
00316
00317 if (ps_do > 0 && (ps_do & 0x80))
00318 return 1;
00319 return 0;
00320 }
00321
00322 return -1;
00323 }
00324
00325
00326 static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
00327 size_t maxlen)
00328 {
00329 int rlen, rec;
00330 struct efdir {
00331 unsigned char appl_template_tag;
00332 unsigned char appl_template_len;
00333 unsigned char appl_id_tag;
00334 unsigned char aid_len;
00335 unsigned char rid[5];
00336 unsigned char appl_code[2];
00337 } *efdir;
00338 unsigned char buf[100];
00339 size_t blen;
00340
00341 efdir = (struct efdir *) buf;
00342 blen = sizeof(buf);
00343 if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
00344 wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
00345 return -1;
00346 }
00347 wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
00348
00349 for (rec = 1; rec < 10; rec++) {
00350 rlen = scard_get_record_len(scard, rec,
00351 SIM_RECORD_MODE_ABSOLUTE);
00352 if (rlen < 0) {
00353 wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
00354 "record length");
00355 return -1;
00356 }
00357 blen = sizeof(buf);
00358 if (rlen > (int) blen) {
00359 wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
00360 return -1;
00361 }
00362 if (scard_read_record(scard, buf, rlen, rec,
00363 SIM_RECORD_MODE_ABSOLUTE) < 0) {
00364 wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
00365 "EF_DIR record %d", rec);
00366 return -1;
00367 }
00368 wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
00369
00370 if (efdir->appl_template_tag != 0x61) {
00371 wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
00372 "template tag 0x%x",
00373 efdir->appl_template_tag);
00374 continue;
00375 }
00376
00377 if (efdir->appl_template_len > rlen - 2) {
00378 wpa_printf(MSG_DEBUG, "SCARD: Too long application "
00379 "template (len=%d rlen=%d)",
00380 efdir->appl_template_len, rlen);
00381 continue;
00382 }
00383
00384 if (efdir->appl_id_tag != 0x4f) {
00385 wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
00386 "identifier tag 0x%x", efdir->appl_id_tag);
00387 continue;
00388 }
00389
00390 if (efdir->aid_len < 1 || efdir->aid_len > 16) {
00391 wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
00392 efdir->aid_len);
00393 continue;
00394 }
00395
00396 wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
00397 efdir->rid, efdir->aid_len);
00398
00399 if (efdir->appl_code[0] == 0x10 &&
00400 efdir->appl_code[1] == 0x02) {
00401 wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
00402 "EF_DIR record %d", rec);
00403 break;
00404 }
00405 }
00406
00407 if (rec >= 10) {
00408 wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
00409 "from EF_DIR records");
00410 return -1;
00411 }
00412
00413 if (efdir->aid_len > maxlen) {
00414 wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
00415 return -1;
00416 }
00417
00418 os_memcpy(aid, efdir->rid, efdir->aid_len);
00419
00420 return efdir->aid_len;
00421 }
00422
00423
00436 struct scard_data * scard_init(scard_sim_type sim_type)
00437 {
00438 long ret;
00439 unsigned long len;
00440 struct scard_data *scard;
00441 #ifdef CONFIG_NATIVE_WINDOWS
00442 TCHAR *readers = NULL;
00443 #else
00444 char *readers = NULL;
00445 #endif
00446 unsigned char buf[100];
00447 size_t blen;
00448 int transaction = 0;
00449 int pin_needed;
00450
00451 wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
00452 if (mingw_load_symbols())
00453 return NULL;
00454 scard = os_zalloc(sizeof(*scard));
00455 if (scard == NULL)
00456 return NULL;
00457
00458 ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
00459 &scard->ctx);
00460 if (ret != SCARD_S_SUCCESS) {
00461 wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
00462 "context (err=%ld)", ret);
00463 goto failed;
00464 }
00465
00466 ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
00467 if (ret != SCARD_S_SUCCESS) {
00468 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
00469 "(err=%ld)", ret);
00470 goto failed;
00471 }
00472
00473 #ifdef UNICODE
00474 len *= 2;
00475 #endif
00476 readers = os_malloc(len);
00477 if (readers == NULL) {
00478 wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
00479 goto failed;
00480 }
00481
00482 ret = SCardListReaders(scard->ctx, NULL, readers, &len);
00483 if (ret != SCARD_S_SUCCESS) {
00484 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
00485 "(err=%ld)", ret);
00486 goto failed;
00487 }
00488 if (len < 3) {
00489 wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
00490 "available.");
00491 goto failed;
00492 }
00493
00494
00495
00496
00497 #ifdef UNICODE
00498 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
00499 #else
00500 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
00501 #endif
00502
00503 ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
00504 SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
00505 if (ret != SCARD_S_SUCCESS) {
00506 if (ret == (long) SCARD_E_NO_SMARTCARD)
00507 wpa_printf(MSG_INFO, "No smart card inserted.");
00508 else
00509 wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
00510 goto failed;
00511 }
00512
00513 os_free(readers);
00514 readers = NULL;
00515
00516 wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
00517 (unsigned int) scard->card, scard->protocol,
00518 scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
00519
00520 ret = SCardBeginTransaction(scard->card);
00521 if (ret != SCARD_S_SUCCESS) {
00522 wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
00523 "0x%x", (unsigned int) ret);
00524 goto failed;
00525 }
00526 transaction = 1;
00527
00528 blen = sizeof(buf);
00529
00530 scard->sim_type = SCARD_GSM_SIM;
00531 if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
00532 wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
00533 if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
00534 SCARD_USIM, NULL, 0)) {
00535 wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
00536 if (sim_type == SCARD_USIM_ONLY)
00537 goto failed;
00538 wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
00539 scard->sim_type = SCARD_GSM_SIM;
00540 } else {
00541 wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
00542 scard->sim_type = SCARD_USIM;
00543 }
00544 }
00545
00546 if (scard->sim_type == SCARD_GSM_SIM) {
00547 blen = sizeof(buf);
00548 if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
00549 wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
00550 goto failed;
00551 }
00552
00553 blen = sizeof(buf);
00554 if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
00555 wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
00556 goto failed;
00557 }
00558 } else {
00559 unsigned char aid[32];
00560 int aid_len;
00561
00562 aid_len = scard_get_aid(scard, aid, sizeof(aid));
00563 if (aid_len < 0) {
00564 wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
00565 "3G USIM app - try to use standard 3G RID");
00566 os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
00567 aid_len = 5;
00568 }
00569 wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
00570
00571
00572
00573 blen = sizeof(buf);
00574 if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
00575 aid, aid_len)) {
00576 wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
00577 "app");
00578 wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
00579 aid, aid_len);
00580 goto failed;
00581 }
00582 }
00583
00584
00585 pin_needed = scard_pin_needed(scard, buf, blen);
00586 if (pin_needed < 0) {
00587 wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
00588 "is needed");
00589 goto failed;
00590 }
00591 if (pin_needed) {
00592 scard->pin1_required = 1;
00593 wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
00594 }
00595
00596 ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
00597 if (ret != SCARD_S_SUCCESS) {
00598 wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
00599 "0x%x", (unsigned int) ret);
00600 }
00601
00602 return scard;
00603
00604 failed:
00605 if (transaction)
00606 SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
00607 os_free(readers);
00608 scard_deinit(scard);
00609 return NULL;
00610 }
00611
00612
00620 int scard_set_pin(struct scard_data *scard, const char *pin)
00621 {
00622 if (scard == NULL)
00623 return -1;
00624
00625
00626 if (scard->pin1_required) {
00627 if (pin == NULL) {
00628 wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
00629 "access");
00630 return -1;
00631 }
00632 if (scard_verify_pin(scard, pin)) {
00633 wpa_printf(MSG_INFO, "PIN verification failed for "
00634 "SIM access");
00635 return -1;
00636 }
00637 }
00638
00639 return 0;
00640 }
00641
00642
00650 void scard_deinit(struct scard_data *scard)
00651 {
00652 long ret;
00653
00654 if (scard == NULL)
00655 return;
00656
00657 wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
00658 if (scard->card) {
00659 ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
00660 if (ret != SCARD_S_SUCCESS) {
00661 wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
00662 "smart card (err=%ld)", ret);
00663 }
00664 }
00665
00666 if (scard->ctx) {
00667 ret = SCardReleaseContext(scard->ctx);
00668 if (ret != SCARD_S_SUCCESS) {
00669 wpa_printf(MSG_DEBUG, "Failed to release smart card "
00670 "context (err=%ld)", ret);
00671 }
00672 }
00673 os_free(scard);
00674 mingw_unload_symbols();
00675 }
00676
00677
00678 static long scard_transmit(struct scard_data *scard,
00679 unsigned char *_send, size_t send_len,
00680 unsigned char *_recv, size_t *recv_len)
00681 {
00682 long ret;
00683 unsigned long rlen;
00684
00685 wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
00686 _send, send_len);
00687 rlen = *recv_len;
00688 ret = SCardTransmit(scard->card,
00689 scard->protocol == SCARD_PROTOCOL_T1 ?
00690 SCARD_PCI_T1 : SCARD_PCI_T0,
00691 _send, (unsigned long) send_len,
00692 NULL, _recv, &rlen);
00693 *recv_len = rlen;
00694 if (ret == SCARD_S_SUCCESS) {
00695 wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
00696 _recv, rlen);
00697 } else {
00698 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
00699 "(err=0x%lx)", ret);
00700 }
00701 return ret;
00702 }
00703
00704
00705 static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
00706 unsigned char *buf, size_t *buf_len,
00707 sim_types sim_type, unsigned char *aid,
00708 size_t aidlen)
00709 {
00710 long ret;
00711 unsigned char resp[3];
00712 unsigned char cmd[50] = { SIM_CMD_SELECT };
00713 int cmdlen;
00714 unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
00715 size_t len, rlen;
00716
00717 if (sim_type == SCARD_USIM) {
00718 cmd[0] = USIM_CLA;
00719 cmd[3] = 0x04;
00720 get_resp[0] = USIM_CLA;
00721 }
00722
00723 wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
00724 if (aid) {
00725 wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
00726 aid, aidlen);
00727 if (5 + aidlen > sizeof(cmd))
00728 return -1;
00729 cmd[2] = 0x04;
00730 cmd[4] = aidlen;
00731 os_memcpy(cmd + 5, aid, aidlen);
00732 cmdlen = 5 + aidlen;
00733 } else {
00734 cmd[5] = file_id >> 8;
00735 cmd[6] = file_id & 0xff;
00736 cmdlen = 7;
00737 }
00738 len = sizeof(resp);
00739 ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
00740 if (ret != SCARD_S_SUCCESS) {
00741 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
00742 "(err=0x%lx)", ret);
00743 return -1;
00744 }
00745
00746 if (len != 2) {
00747 wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
00748 "%d (expected 2)", (int) len);
00749 return -1;
00750 }
00751
00752 if (resp[0] == 0x98 && resp[1] == 0x04) {
00753
00754 wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
00755 "(PIN_WLAN)");
00756 return -1;
00757 }
00758
00759 if (resp[0] == 0x6e) {
00760 wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
00761 return -1;
00762 }
00763
00764 if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
00765 wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
00766 "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
00767 return -1;
00768 }
00769
00770 get_resp[4] = resp[1];
00771 wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
00772 resp[1]);
00773
00774 rlen = *buf_len;
00775 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
00776 if (ret == SCARD_S_SUCCESS) {
00777 *buf_len = resp[1] < rlen ? resp[1] : rlen;
00778 return 0;
00779 }
00780
00781 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
00782 return -1;
00783 }
00784
00785
00786 static int scard_select_file(struct scard_data *scard, unsigned short file_id,
00787 unsigned char *buf, size_t *buf_len)
00788 {
00789 return _scard_select_file(scard, file_id, buf, buf_len,
00790 scard->sim_type, NULL, 0);
00791 }
00792
00793
00794 static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
00795 unsigned char mode)
00796 {
00797 unsigned char buf[255];
00798 unsigned char cmd[5] = { SIM_CMD_READ_RECORD };
00799 size_t blen;
00800 long ret;
00801
00802 if (scard->sim_type == SCARD_USIM)
00803 cmd[0] = USIM_CLA;
00804 cmd[2] = recnum;
00805 cmd[3] = mode;
00806 cmd[4] = sizeof(buf);
00807
00808 blen = sizeof(buf);
00809 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00810 if (ret != SCARD_S_SUCCESS) {
00811 wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
00812 "length for record %d", recnum);
00813 return -1;
00814 }
00815
00816 wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
00817 buf, blen);
00818
00819 if (blen < 2 || buf[0] != 0x6c) {
00820 wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
00821 "length determination");
00822 return -1;
00823 }
00824
00825 return buf[1];
00826 }
00827
00828
00829 static int scard_read_record(struct scard_data *scard,
00830 unsigned char *data, size_t len,
00831 unsigned char recnum, unsigned char mode)
00832 {
00833 unsigned char cmd[5] = { SIM_CMD_READ_RECORD };
00834 size_t blen = len + 3;
00835 unsigned char *buf;
00836 long ret;
00837
00838 if (scard->sim_type == SCARD_USIM)
00839 cmd[0] = USIM_CLA;
00840 cmd[2] = recnum;
00841 cmd[3] = mode;
00842 cmd[4] = len;
00843
00844 buf = os_malloc(blen);
00845 if (buf == NULL)
00846 return -1;
00847
00848 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00849 if (ret != SCARD_S_SUCCESS) {
00850 os_free(buf);
00851 return -2;
00852 }
00853 if (blen != len + 2) {
00854 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
00855 "length %ld (expected %ld)",
00856 (long) blen, (long) len + 2);
00857 os_free(buf);
00858 return -3;
00859 }
00860
00861 if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
00862 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
00863 "status %02x %02x (expected 90 00)",
00864 buf[len], buf[len + 1]);
00865 os_free(buf);
00866 return -4;
00867 }
00868
00869 os_memcpy(data, buf, len);
00870 os_free(buf);
00871
00872 return 0;
00873 }
00874
00875
00876 static int scard_read_file(struct scard_data *scard,
00877 unsigned char *data, size_t len)
00878 {
00879 unsigned char cmd[5] = { SIM_CMD_READ_BIN };
00880 size_t blen = len + 3;
00881 unsigned char *buf;
00882 long ret;
00883
00884 cmd[4] = len;
00885
00886 buf = os_malloc(blen);
00887 if (buf == NULL)
00888 return -1;
00889
00890 if (scard->sim_type == SCARD_USIM)
00891 cmd[0] = USIM_CLA;
00892 ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00893 if (ret != SCARD_S_SUCCESS) {
00894 os_free(buf);
00895 return -2;
00896 }
00897 if (blen != len + 2) {
00898 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
00899 "length %ld (expected %ld)",
00900 (long) blen, (long) len + 2);
00901 os_free(buf);
00902 return -3;
00903 }
00904
00905 if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
00906 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
00907 "status %02x %02x (expected 90 00)",
00908 buf[len], buf[len + 1]);
00909 os_free(buf);
00910 return -4;
00911 }
00912
00913 os_memcpy(data, buf, len);
00914 os_free(buf);
00915
00916 return 0;
00917 }
00918
00919
00920 static int scard_verify_pin(struct scard_data *scard, const char *pin)
00921 {
00922 long ret;
00923 unsigned char resp[3];
00924 unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
00925 size_t len;
00926
00927 wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
00928
00929 if (pin == NULL || os_strlen(pin) > 8)
00930 return -1;
00931
00932 if (scard->sim_type == SCARD_USIM)
00933 cmd[0] = USIM_CLA;
00934 os_memcpy(cmd + 5, pin, os_strlen(pin));
00935 os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
00936
00937 len = sizeof(resp);
00938 ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
00939 if (ret != SCARD_S_SUCCESS)
00940 return -2;
00941
00942 if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
00943 wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
00944 return -1;
00945 }
00946
00947 wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
00948 return 0;
00949 }
00950
00951
00967 int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
00968 {
00969 unsigned char buf[100];
00970 size_t blen, imsilen, i;
00971 char *pos;
00972
00973 wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
00974 blen = sizeof(buf);
00975 if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
00976 return -1;
00977 if (blen < 4) {
00978 wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
00979 "header (len=%ld)", (long) blen);
00980 return -2;
00981 }
00982
00983 if (scard->sim_type == SCARD_GSM_SIM) {
00984 blen = (buf[2] << 8) | buf[3];
00985 } else {
00986 int file_size;
00987 if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
00988 return -3;
00989 blen = file_size;
00990 }
00991 if (blen < 2 || blen > sizeof(buf)) {
00992 wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
00993 (long) blen);
00994 return -3;
00995 }
00996
00997 imsilen = (blen - 2) * 2 + 1;
00998 wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
00999 (long) blen, (long) imsilen);
01000 if (blen < 2 || imsilen > *len) {
01001 *len = imsilen;
01002 return -4;
01003 }
01004
01005 if (scard_read_file(scard, buf, blen))
01006 return -5;
01007
01008 pos = imsi;
01009 *pos++ = '0' + (buf[1] >> 4 & 0x0f);
01010 for (i = 2; i < blen; i++) {
01011 unsigned char digit;
01012
01013 digit = buf[i] & 0x0f;
01014 if (digit < 10)
01015 *pos++ = '0' + digit;
01016 else
01017 imsilen--;
01018
01019 digit = buf[i] >> 4 & 0x0f;
01020 if (digit < 10)
01021 *pos++ = '0' + digit;
01022 else
01023 imsilen--;
01024 }
01025 *len = imsilen;
01026
01027 return 0;
01028 }
01029
01030
01047 int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
01048 unsigned char *sres, unsigned char *kc)
01049 {
01050 unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
01051 int cmdlen;
01052 unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
01053 unsigned char resp[3], buf[12 + 3 + 2];
01054 size_t len;
01055 long ret;
01056
01057 if (scard == NULL)
01058 return -1;
01059
01060 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
01061 if (scard->sim_type == SCARD_GSM_SIM) {
01062 cmdlen = 5 + 16;
01063 os_memcpy(cmd + 5, _rand, 16);
01064 } else {
01065 cmdlen = 5 + 1 + 16;
01066 cmd[0] = USIM_CLA;
01067 cmd[3] = 0x80;
01068 cmd[4] = 17;
01069 cmd[5] = 16;
01070 os_memcpy(cmd + 6, _rand, 16);
01071 }
01072 len = sizeof(resp);
01073 ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
01074 if (ret != SCARD_S_SUCCESS)
01075 return -2;
01076
01077 if ((scard->sim_type == SCARD_GSM_SIM &&
01078 (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
01079 (scard->sim_type == SCARD_USIM &&
01080 (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
01081 wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
01082 "auth request (len=%ld resp=%02x %02x)",
01083 (long) len, resp[0], resp[1]);
01084 return -3;
01085 }
01086 get_resp[4] = resp[1];
01087
01088 len = sizeof(buf);
01089 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
01090 if (ret != SCARD_S_SUCCESS)
01091 return -4;
01092
01093 if (scard->sim_type == SCARD_GSM_SIM) {
01094 if (len != 4 + 8 + 2) {
01095 wpa_printf(MSG_WARNING, "SCARD: unexpected data "
01096 "length for GSM auth (len=%ld, expected 14)",
01097 (long) len);
01098 return -5;
01099 }
01100 os_memcpy(sres, buf, 4);
01101 os_memcpy(kc, buf + 4, 8);
01102 } else {
01103 if (len != 1 + 4 + 1 + 8 + 2) {
01104 wpa_printf(MSG_WARNING, "SCARD: unexpected data "
01105 "length for USIM auth (len=%ld, "
01106 "expected 16)", (long) len);
01107 return -5;
01108 }
01109 if (buf[0] != 4 || buf[5] != 8) {
01110 wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
01111 "length (%d %d, expected 4 8)",
01112 buf[0], buf[5]);
01113 }
01114 os_memcpy(sres, buf + 1, 4);
01115 os_memcpy(kc, buf + 6, 8);
01116 }
01117
01118 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
01119 wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
01120
01121 return 0;
01122 }
01123
01124
01146 int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
01147 const unsigned char *autn,
01148 unsigned char *res, size_t *res_len,
01149 unsigned char *ik, unsigned char *ck, unsigned char *auts)
01150 {
01151 unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
01152 { USIM_CMD_RUN_UMTS_ALG };
01153 unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
01154 unsigned char resp[3], buf[64], *pos, *end;
01155 size_t len;
01156 long ret;
01157
01158 if (scard == NULL)
01159 return -1;
01160
01161 if (scard->sim_type == SCARD_GSM_SIM) {
01162 wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
01163 "auth");
01164 return -1;
01165 }
01166
01167 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
01168 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
01169 cmd[5] = AKA_RAND_LEN;
01170 os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
01171 cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
01172 os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
01173
01174 len = sizeof(resp);
01175 ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
01176 if (ret != SCARD_S_SUCCESS)
01177 return -1;
01178
01179 if (len <= sizeof(resp))
01180 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
01181
01182 if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
01183 wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
01184 "MAC != XMAC");
01185 return -1;
01186 } else if (len != 2 || resp[0] != 0x61) {
01187 wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
01188 "auth request (len=%ld resp=%02x %02x)",
01189 (long) len, resp[0], resp[1]);
01190 return -1;
01191 }
01192 get_resp[4] = resp[1];
01193
01194 len = sizeof(buf);
01195 ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
01196 if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
01197 return -1;
01198
01199 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
01200 if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
01201 buf[1] == AKA_AUTS_LEN) {
01202 wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
01203 os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
01204 wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
01205 return -2;
01206 } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
01207 pos = buf + 1;
01208 end = buf + len;
01209
01210
01211 if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
01212 wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
01213 return -1;
01214 }
01215 *res_len = *pos++;
01216 os_memcpy(res, pos, *res_len);
01217 pos += *res_len;
01218 wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
01219
01220
01221 if (pos[0] != CK_LEN || pos + CK_LEN > end) {
01222 wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
01223 return -1;
01224 }
01225 pos++;
01226 os_memcpy(ck, pos, CK_LEN);
01227 pos += CK_LEN;
01228 wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
01229
01230
01231 if (pos[0] != IK_LEN || pos + IK_LEN > end) {
01232 wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
01233 return -1;
01234 }
01235 pos++;
01236 os_memcpy(ik, pos, IK_LEN);
01237 pos += IK_LEN;
01238 wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
01239
01240 return 0;
01241 }
01242
01243 wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
01244 return -1;
01245 }
01246