$search
00001 /* 00002 * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM 00003 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 * 00014 * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM 00015 * cards through PC/SC smartcard library. These functions are used to implement 00016 * authentication routines for EAP-SIM and EAP-AKA. 00017 */ 00018 00019 #include "includes.h" 00020 #include <winscard.h> 00021 00022 #include "common.h" 00023 #include "pcsc_funcs.h" 00024 00025 00026 /* See ETSI GSM 11.11 and ETSI TS 102 221 for details. 00027 * SIM commands: 00028 * Command APDU: CLA INS P1 P2 P3 Data 00029 * CLA (class of instruction): A0 for GSM, 00 for USIM 00030 * INS (instruction) 00031 * P1 P2 P3 (parameters, P3 = length of Data) 00032 * Response APDU: Data SW1 SW2 00033 * SW1 SW2 (Status words) 00034 * Commands (INS P1 P2 P3): 00035 * SELECT: A4 00 00 02 <file_id, 2 bytes> 00036 * GET RESPONSE: C0 00 00 <len> 00037 * RUN GSM ALG: 88 00 00 00 <RAND len = 10> 00038 * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN 00039 * P1 = ID of alg in card 00040 * P2 = ID of secret key 00041 * READ BINARY: B0 <offset high> <offset low> <len> 00042 * READ RECORD: B2 <record number> <mode> <len> 00043 * P2 (mode) = '02' (next record), '03' (previous record), 00044 * '04' (absolute mode) 00045 * VERIFY CHV: 20 00 <CHV number> 08 00046 * CHANGE CHV: 24 00 <CHV number> 10 00047 * DISABLE CHV: 26 00 01 08 00048 * ENABLE CHV: 28 00 01 08 00049 * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 00050 * SLEEP: FA 00 00 00 00051 */ 00052 00053 /* GSM SIM commands */ 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 /* USIM commands */ 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 /* MinGW does not yet support WinScard, so load the needed functions 00102 * dynamically from winscard.dll for now. */ 00103 00104 static HINSTANCE dll = NULL; /* winscard.dll */ 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 /* __MINGW32_VERSION */ 00219 00220 #define mingw_load_symbols() 0 00221 #define mingw_unload_symbols() do { } while (0) 00222 00223 #endif /* __MINGW32_VERSION */ 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 /* TODO: there could be more than one PS_DO entry because of 00315 * multiple PINs in key reference.. */ 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; /* 0x61 */ 00331 unsigned char appl_template_len; 00332 unsigned char appl_id_tag; /* 0x4f */ 00333 unsigned char aid_len; 00334 unsigned char rid[5]; 00335 unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ 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 /* CONFIG_NATIVE_WINDOWS */ 00442 char *readers = NULL; 00443 #endif /* CONFIG_NATIVE_WINDOWS */ 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 /* UNICODE */ 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 /* readers is a list of available reader. Last entry is terminated with 00492 * double NUL. 00493 * TODO: add support for selecting the reader; now just use the first 00494 * one.. */ 00495 #ifdef UNICODE 00496 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); 00497 #else /* UNICODE */ 00498 wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); 00499 #endif /* UNICODE */ 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 /* Select based on AID = 3G RID from EF_DIR. This is usually 00570 * starting with A0 00 00 00 87. */ 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 /* Verify whether CHV1 (PIN1) is needed to access the card. */ 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 /* Verify whether CHV1 (PIN1) is needed to access the card. */ 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; /* Select by AID */ 00726 cmd[4] = aidlen; /* len */ 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 /* Security status not satisfied (PIN_WLAN) */ 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 /* Normal ending of command; resp[1] bytes available */ 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 /* , len */ }; 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 /* , len */ }; 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 /* , len */ }; 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 /* RES */ 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 /* CK */ 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 /* IK */ 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 }