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