139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM 339beb93cSSam Leffler * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler * 1439beb93cSSam Leffler * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM 1539beb93cSSam Leffler * cards through PC/SC smartcard library. These functions are used to implement 1639beb93cSSam Leffler * authentication routines for EAP-SIM and EAP-AKA. 1739beb93cSSam Leffler */ 1839beb93cSSam Leffler 1939beb93cSSam Leffler #include "includes.h" 2039beb93cSSam Leffler #include <winscard.h> 2139beb93cSSam Leffler 2239beb93cSSam Leffler #include "common.h" 2339beb93cSSam Leffler #include "pcsc_funcs.h" 2439beb93cSSam Leffler 2539beb93cSSam Leffler 2639beb93cSSam Leffler /* See ETSI GSM 11.11 and ETSI TS 102 221 for details. 2739beb93cSSam Leffler * SIM commands: 2839beb93cSSam Leffler * Command APDU: CLA INS P1 P2 P3 Data 2939beb93cSSam Leffler * CLA (class of instruction): A0 for GSM, 00 for USIM 3039beb93cSSam Leffler * INS (instruction) 3139beb93cSSam Leffler * P1 P2 P3 (parameters, P3 = length of Data) 3239beb93cSSam Leffler * Response APDU: Data SW1 SW2 3339beb93cSSam Leffler * SW1 SW2 (Status words) 3439beb93cSSam Leffler * Commands (INS P1 P2 P3): 3539beb93cSSam Leffler * SELECT: A4 00 00 02 <file_id, 2 bytes> 3639beb93cSSam Leffler * GET RESPONSE: C0 00 00 <len> 3739beb93cSSam Leffler * RUN GSM ALG: 88 00 00 00 <RAND len = 10> 3839beb93cSSam Leffler * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN 3939beb93cSSam Leffler * P1 = ID of alg in card 4039beb93cSSam Leffler * P2 = ID of secret key 4139beb93cSSam Leffler * READ BINARY: B0 <offset high> <offset low> <len> 4239beb93cSSam Leffler * READ RECORD: B2 <record number> <mode> <len> 4339beb93cSSam Leffler * P2 (mode) = '02' (next record), '03' (previous record), 4439beb93cSSam Leffler * '04' (absolute mode) 4539beb93cSSam Leffler * VERIFY CHV: 20 00 <CHV number> 08 4639beb93cSSam Leffler * CHANGE CHV: 24 00 <CHV number> 10 4739beb93cSSam Leffler * DISABLE CHV: 26 00 01 08 4839beb93cSSam Leffler * ENABLE CHV: 28 00 01 08 4939beb93cSSam Leffler * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 5039beb93cSSam Leffler * SLEEP: FA 00 00 00 5139beb93cSSam Leffler */ 5239beb93cSSam Leffler 5339beb93cSSam Leffler /* GSM SIM commands */ 5439beb93cSSam Leffler #define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 5539beb93cSSam Leffler #define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 5639beb93cSSam Leffler #define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 5739beb93cSSam Leffler #define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 5839beb93cSSam Leffler #define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 5939beb93cSSam Leffler #define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 6039beb93cSSam Leffler 6139beb93cSSam Leffler /* USIM commands */ 6239beb93cSSam Leffler #define USIM_CLA 0x00 6339beb93cSSam Leffler #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 6439beb93cSSam Leffler #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 6539beb93cSSam Leffler 6639beb93cSSam Leffler #define SIM_RECORD_MODE_ABSOLUTE 0x04 6739beb93cSSam Leffler 6839beb93cSSam Leffler #define USIM_FSP_TEMPL_TAG 0x62 6939beb93cSSam Leffler 7039beb93cSSam Leffler #define USIM_TLV_FILE_DESC 0x82 7139beb93cSSam Leffler #define USIM_TLV_FILE_ID 0x83 7239beb93cSSam Leffler #define USIM_TLV_DF_NAME 0x84 7339beb93cSSam Leffler #define USIM_TLV_PROPR_INFO 0xA5 7439beb93cSSam Leffler #define USIM_TLV_LIFE_CYCLE_STATUS 0x8A 7539beb93cSSam Leffler #define USIM_TLV_FILE_SIZE 0x80 7639beb93cSSam Leffler #define USIM_TLV_TOTAL_FILE_SIZE 0x81 7739beb93cSSam Leffler #define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 7839beb93cSSam Leffler #define USIM_TLV_SHORT_FILE_ID 0x88 7939beb93cSSam Leffler 8039beb93cSSam Leffler #define USIM_PS_DO_TAG 0x90 8139beb93cSSam Leffler 8239beb93cSSam Leffler #define AKA_RAND_LEN 16 8339beb93cSSam Leffler #define AKA_AUTN_LEN 16 8439beb93cSSam Leffler #define AKA_AUTS_LEN 14 8539beb93cSSam Leffler #define RES_MAX_LEN 16 8639beb93cSSam Leffler #define IK_LEN 16 8739beb93cSSam Leffler #define CK_LEN 16 8839beb93cSSam Leffler 8939beb93cSSam Leffler 9039beb93cSSam Leffler typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; 9139beb93cSSam Leffler 9239beb93cSSam Leffler struct scard_data { 9339beb93cSSam Leffler SCARDCONTEXT ctx; 9439beb93cSSam Leffler SCARDHANDLE card; 9539beb93cSSam Leffler DWORD protocol; 9639beb93cSSam Leffler sim_types sim_type; 9739beb93cSSam Leffler int pin1_required; 9839beb93cSSam Leffler }; 9939beb93cSSam Leffler 10039beb93cSSam Leffler #ifdef __MINGW32_VERSION 10139beb93cSSam Leffler /* MinGW does not yet support WinScard, so load the needed functions 10239beb93cSSam Leffler * dynamically from winscard.dll for now. */ 10339beb93cSSam Leffler 10439beb93cSSam Leffler static HINSTANCE dll = NULL; /* winscard.dll */ 10539beb93cSSam Leffler 10639beb93cSSam Leffler static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; 10739beb93cSSam Leffler #undef SCARD_PCI_T0 10839beb93cSSam Leffler #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) 10939beb93cSSam Leffler #undef SCARD_PCI_T1 11039beb93cSSam Leffler #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) 11139beb93cSSam Leffler 11239beb93cSSam Leffler 11339beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 11439beb93cSSam Leffler (*dll_SCardEstablishContext)(IN DWORD dwScope, 11539beb93cSSam Leffler IN LPCVOID pvReserved1, 11639beb93cSSam Leffler IN LPCVOID pvReserved2, 11739beb93cSSam Leffler OUT LPSCARDCONTEXT phContext); 11839beb93cSSam Leffler #define SCardEstablishContext dll_SCardEstablishContext 11939beb93cSSam Leffler 12039beb93cSSam Leffler static long (*dll_SCardReleaseContext)(long hContext); 12139beb93cSSam Leffler #define SCardReleaseContext dll_SCardReleaseContext 12239beb93cSSam Leffler 12339beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 12439beb93cSSam Leffler (*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, 12539beb93cSSam Leffler IN LPCSTR mszGroups, 12639beb93cSSam Leffler OUT LPSTR mszReaders, 12739beb93cSSam Leffler IN OUT LPDWORD pcchReaders); 12839beb93cSSam Leffler #undef SCardListReaders 12939beb93cSSam Leffler #define SCardListReaders dll_SCardListReadersA 13039beb93cSSam Leffler 13139beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 13239beb93cSSam Leffler (*dll_SCardConnectA)(IN SCARDCONTEXT hContext, 13339beb93cSSam Leffler IN LPCSTR szReader, 13439beb93cSSam Leffler IN DWORD dwShareMode, 13539beb93cSSam Leffler IN DWORD dwPreferredProtocols, 13639beb93cSSam Leffler OUT LPSCARDHANDLE phCard, 13739beb93cSSam Leffler OUT LPDWORD pdwActiveProtocol); 13839beb93cSSam Leffler #undef SCardConnect 13939beb93cSSam Leffler #define SCardConnect dll_SCardConnectA 14039beb93cSSam Leffler 14139beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 14239beb93cSSam Leffler (*dll_SCardDisconnect)(IN SCARDHANDLE hCard, 14339beb93cSSam Leffler IN DWORD dwDisposition); 14439beb93cSSam Leffler #define SCardDisconnect dll_SCardDisconnect 14539beb93cSSam Leffler 14639beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 14739beb93cSSam Leffler (*dll_SCardTransmit)(IN SCARDHANDLE hCard, 14839beb93cSSam Leffler IN LPCSCARD_IO_REQUEST pioSendPci, 14939beb93cSSam Leffler IN LPCBYTE pbSendBuffer, 15039beb93cSSam Leffler IN DWORD cbSendLength, 15139beb93cSSam Leffler IN OUT LPSCARD_IO_REQUEST pioRecvPci, 15239beb93cSSam Leffler OUT LPBYTE pbRecvBuffer, 15339beb93cSSam Leffler IN OUT LPDWORD pcbRecvLength); 15439beb93cSSam Leffler #define SCardTransmit dll_SCardTransmit 15539beb93cSSam Leffler 15639beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 15739beb93cSSam Leffler (*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); 15839beb93cSSam Leffler #define SCardBeginTransaction dll_SCardBeginTransaction 15939beb93cSSam Leffler 16039beb93cSSam Leffler static WINSCARDAPI LONG WINAPI 16139beb93cSSam Leffler (*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); 16239beb93cSSam Leffler #define SCardEndTransaction dll_SCardEndTransaction 16339beb93cSSam Leffler 16439beb93cSSam Leffler 16539beb93cSSam Leffler static int mingw_load_symbols(void) 16639beb93cSSam Leffler { 16739beb93cSSam Leffler char *sym; 16839beb93cSSam Leffler 16939beb93cSSam Leffler if (dll) 17039beb93cSSam Leffler return 0; 17139beb93cSSam Leffler 17239beb93cSSam Leffler dll = LoadLibrary("winscard"); 17339beb93cSSam Leffler if (dll == NULL) { 17439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " 17539beb93cSSam Leffler "library"); 17639beb93cSSam Leffler return -1; 17739beb93cSSam Leffler } 17839beb93cSSam Leffler 17939beb93cSSam Leffler #define LOADSYM(s) \ 18039beb93cSSam Leffler sym = #s; \ 18139beb93cSSam Leffler dll_ ## s = (void *) GetProcAddress(dll, sym); \ 18239beb93cSSam Leffler if (dll_ ## s == NULL) \ 18339beb93cSSam Leffler goto fail; 18439beb93cSSam Leffler 18539beb93cSSam Leffler LOADSYM(SCardEstablishContext); 18639beb93cSSam Leffler LOADSYM(SCardReleaseContext); 18739beb93cSSam Leffler LOADSYM(SCardListReadersA); 18839beb93cSSam Leffler LOADSYM(SCardConnectA); 18939beb93cSSam Leffler LOADSYM(SCardDisconnect); 19039beb93cSSam Leffler LOADSYM(SCardTransmit); 19139beb93cSSam Leffler LOADSYM(SCardBeginTransaction); 19239beb93cSSam Leffler LOADSYM(SCardEndTransaction); 19339beb93cSSam Leffler LOADSYM(g_rgSCardT0Pci); 19439beb93cSSam Leffler LOADSYM(g_rgSCardT1Pci); 19539beb93cSSam Leffler 19639beb93cSSam Leffler #undef LOADSYM 19739beb93cSSam Leffler 19839beb93cSSam Leffler return 0; 19939beb93cSSam Leffler 20039beb93cSSam Leffler fail: 20139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " 20239beb93cSSam Leffler "winscard.dll", sym); 20339beb93cSSam Leffler FreeLibrary(dll); 20439beb93cSSam Leffler dll = NULL; 20539beb93cSSam Leffler return -1; 20639beb93cSSam Leffler } 20739beb93cSSam Leffler 20839beb93cSSam Leffler 20939beb93cSSam Leffler static void mingw_unload_symbols(void) 21039beb93cSSam Leffler { 21139beb93cSSam Leffler if (dll == NULL) 21239beb93cSSam Leffler return; 21339beb93cSSam Leffler 21439beb93cSSam Leffler FreeLibrary(dll); 21539beb93cSSam Leffler dll = NULL; 21639beb93cSSam Leffler } 21739beb93cSSam Leffler 21839beb93cSSam Leffler #else /* __MINGW32_VERSION */ 21939beb93cSSam Leffler 22039beb93cSSam Leffler #define mingw_load_symbols() 0 22139beb93cSSam Leffler #define mingw_unload_symbols() do { } while (0) 22239beb93cSSam Leffler 22339beb93cSSam Leffler #endif /* __MINGW32_VERSION */ 22439beb93cSSam Leffler 22539beb93cSSam Leffler 22639beb93cSSam Leffler static int _scard_select_file(struct scard_data *scard, unsigned short file_id, 22739beb93cSSam Leffler unsigned char *buf, size_t *buf_len, 22839beb93cSSam Leffler sim_types sim_type, unsigned char *aid, 22939beb93cSSam Leffler size_t aidlen); 23039beb93cSSam Leffler static int scard_select_file(struct scard_data *scard, unsigned short file_id, 23139beb93cSSam Leffler unsigned char *buf, size_t *buf_len); 23239beb93cSSam Leffler static int scard_verify_pin(struct scard_data *scard, const char *pin); 23339beb93cSSam Leffler static int scard_get_record_len(struct scard_data *scard, 23439beb93cSSam Leffler unsigned char recnum, unsigned char mode); 23539beb93cSSam Leffler static int scard_read_record(struct scard_data *scard, 23639beb93cSSam Leffler unsigned char *data, size_t len, 23739beb93cSSam Leffler unsigned char recnum, unsigned char mode); 23839beb93cSSam Leffler 23939beb93cSSam Leffler 24039beb93cSSam Leffler static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, 24139beb93cSSam Leffler int *ps_do, int *file_len) 24239beb93cSSam Leffler { 24339beb93cSSam Leffler unsigned char *pos, *end; 24439beb93cSSam Leffler 24539beb93cSSam Leffler if (ps_do) 24639beb93cSSam Leffler *ps_do = -1; 24739beb93cSSam Leffler if (file_len) 24839beb93cSSam Leffler *file_len = -1; 24939beb93cSSam Leffler 25039beb93cSSam Leffler pos = buf; 25139beb93cSSam Leffler end = pos + buf_len; 25239beb93cSSam Leffler if (*pos != USIM_FSP_TEMPL_TAG) { 25339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: file header did not " 25439beb93cSSam Leffler "start with FSP template tag"); 25539beb93cSSam Leffler return -1; 25639beb93cSSam Leffler } 25739beb93cSSam Leffler pos++; 25839beb93cSSam Leffler if (pos >= end) 25939beb93cSSam Leffler return -1; 26039beb93cSSam Leffler if ((pos + pos[0]) < end) 26139beb93cSSam Leffler end = pos + 1 + pos[0]; 26239beb93cSSam Leffler pos++; 26339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", 26439beb93cSSam Leffler pos, end - pos); 26539beb93cSSam Leffler 26639beb93cSSam Leffler while (pos + 1 < end) { 26739beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV " 26839beb93cSSam Leffler "0x%02x len=%d", pos[0], pos[1]); 26939beb93cSSam Leffler if (pos + 2 + pos[1] > end) 27039beb93cSSam Leffler break; 27139beb93cSSam Leffler 27239beb93cSSam Leffler if (pos[0] == USIM_TLV_FILE_SIZE && 27339beb93cSSam Leffler (pos[1] == 1 || pos[1] == 2) && file_len) { 27439beb93cSSam Leffler if (pos[1] == 1) 27539beb93cSSam Leffler *file_len = (int) pos[2]; 27639beb93cSSam Leffler else 27739beb93cSSam Leffler *file_len = ((int) pos[2] << 8) | 27839beb93cSSam Leffler (int) pos[3]; 27939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", 28039beb93cSSam Leffler *file_len); 28139beb93cSSam Leffler } 28239beb93cSSam Leffler 28339beb93cSSam Leffler if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE && 28439beb93cSSam Leffler pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && 28539beb93cSSam Leffler pos[3] >= 1 && ps_do) { 28639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", 28739beb93cSSam Leffler pos[4]); 28839beb93cSSam Leffler *ps_do = (int) pos[4]; 28939beb93cSSam Leffler } 29039beb93cSSam Leffler 29139beb93cSSam Leffler pos += 2 + pos[1]; 29239beb93cSSam Leffler 29339beb93cSSam Leffler if (pos == end) 29439beb93cSSam Leffler return 0; 29539beb93cSSam Leffler } 29639beb93cSSam Leffler return -1; 29739beb93cSSam Leffler } 29839beb93cSSam Leffler 29939beb93cSSam Leffler 30039beb93cSSam Leffler static int scard_pin_needed(struct scard_data *scard, 30139beb93cSSam Leffler unsigned char *hdr, size_t hlen) 30239beb93cSSam Leffler { 30339beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 30439beb93cSSam Leffler if (hlen > SCARD_CHV1_OFFSET && 30539beb93cSSam Leffler !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) 30639beb93cSSam Leffler return 1; 30739beb93cSSam Leffler return 0; 30839beb93cSSam Leffler } 30939beb93cSSam Leffler 31039beb93cSSam Leffler if (scard->sim_type == SCARD_USIM) { 31139beb93cSSam Leffler int ps_do; 31239beb93cSSam Leffler if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) 31339beb93cSSam Leffler return -1; 31439beb93cSSam Leffler /* TODO: there could be more than one PS_DO entry because of 31539beb93cSSam Leffler * multiple PINs in key reference.. */ 31639beb93cSSam Leffler if (ps_do > 0 && (ps_do & 0x80)) 31739beb93cSSam Leffler return 1; 31839beb93cSSam Leffler return 0; 31939beb93cSSam Leffler } 32039beb93cSSam Leffler 32139beb93cSSam Leffler return -1; 32239beb93cSSam Leffler } 32339beb93cSSam Leffler 32439beb93cSSam Leffler 32539beb93cSSam Leffler static int scard_get_aid(struct scard_data *scard, unsigned char *aid, 32639beb93cSSam Leffler size_t maxlen) 32739beb93cSSam Leffler { 32839beb93cSSam Leffler int rlen, rec; 32939beb93cSSam Leffler struct efdir { 33039beb93cSSam Leffler unsigned char appl_template_tag; /* 0x61 */ 33139beb93cSSam Leffler unsigned char appl_template_len; 33239beb93cSSam Leffler unsigned char appl_id_tag; /* 0x4f */ 33339beb93cSSam Leffler unsigned char aid_len; 33439beb93cSSam Leffler unsigned char rid[5]; 33539beb93cSSam Leffler unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ 33639beb93cSSam Leffler } *efdir; 33739beb93cSSam Leffler unsigned char buf[100]; 33839beb93cSSam Leffler size_t blen; 33939beb93cSSam Leffler 34039beb93cSSam Leffler efdir = (struct efdir *) buf; 34139beb93cSSam Leffler blen = sizeof(buf); 34239beb93cSSam Leffler if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { 34339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); 34439beb93cSSam Leffler return -1; 34539beb93cSSam Leffler } 34639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); 34739beb93cSSam Leffler 34839beb93cSSam Leffler for (rec = 1; rec < 10; rec++) { 34939beb93cSSam Leffler rlen = scard_get_record_len(scard, rec, 35039beb93cSSam Leffler SIM_RECORD_MODE_ABSOLUTE); 35139beb93cSSam Leffler if (rlen < 0) { 35239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " 35339beb93cSSam Leffler "record length"); 35439beb93cSSam Leffler return -1; 35539beb93cSSam Leffler } 35639beb93cSSam Leffler blen = sizeof(buf); 35739beb93cSSam Leffler if (rlen > (int) blen) { 35839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); 35939beb93cSSam Leffler return -1; 36039beb93cSSam Leffler } 36139beb93cSSam Leffler if (scard_read_record(scard, buf, rlen, rec, 36239beb93cSSam Leffler SIM_RECORD_MODE_ABSOLUTE) < 0) { 36339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to read " 36439beb93cSSam Leffler "EF_DIR record %d", rec); 36539beb93cSSam Leffler return -1; 36639beb93cSSam Leffler } 36739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); 36839beb93cSSam Leffler 36939beb93cSSam Leffler if (efdir->appl_template_tag != 0x61) { 37039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 37139beb93cSSam Leffler "template tag 0x%x", 37239beb93cSSam Leffler efdir->appl_template_tag); 37339beb93cSSam Leffler continue; 37439beb93cSSam Leffler } 37539beb93cSSam Leffler 37639beb93cSSam Leffler if (efdir->appl_template_len > rlen - 2) { 37739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Too long application " 37839beb93cSSam Leffler "template (len=%d rlen=%d)", 37939beb93cSSam Leffler efdir->appl_template_len, rlen); 38039beb93cSSam Leffler continue; 38139beb93cSSam Leffler } 38239beb93cSSam Leffler 38339beb93cSSam Leffler if (efdir->appl_id_tag != 0x4f) { 38439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 38539beb93cSSam Leffler "identifier tag 0x%x", efdir->appl_id_tag); 38639beb93cSSam Leffler continue; 38739beb93cSSam Leffler } 38839beb93cSSam Leffler 38939beb93cSSam Leffler if (efdir->aid_len < 1 || efdir->aid_len > 16) { 39039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", 39139beb93cSSam Leffler efdir->aid_len); 39239beb93cSSam Leffler continue; 39339beb93cSSam Leffler } 39439beb93cSSam Leffler 39539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", 39639beb93cSSam Leffler efdir->rid, efdir->aid_len); 39739beb93cSSam Leffler 39839beb93cSSam Leffler if (efdir->appl_code[0] == 0x10 && 39939beb93cSSam Leffler efdir->appl_code[1] == 0x02) { 40039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " 40139beb93cSSam Leffler "EF_DIR record %d", rec); 40239beb93cSSam Leffler break; 40339beb93cSSam Leffler } 40439beb93cSSam Leffler } 40539beb93cSSam Leffler 40639beb93cSSam Leffler if (rec >= 10) { 40739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " 40839beb93cSSam Leffler "from EF_DIR records"); 40939beb93cSSam Leffler return -1; 41039beb93cSSam Leffler } 41139beb93cSSam Leffler 41239beb93cSSam Leffler if (efdir->aid_len > maxlen) { 41339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); 41439beb93cSSam Leffler return -1; 41539beb93cSSam Leffler } 41639beb93cSSam Leffler 41739beb93cSSam Leffler os_memcpy(aid, efdir->rid, efdir->aid_len); 41839beb93cSSam Leffler 41939beb93cSSam Leffler return efdir->aid_len; 42039beb93cSSam Leffler } 42139beb93cSSam Leffler 42239beb93cSSam Leffler 42339beb93cSSam Leffler /** 42439beb93cSSam Leffler * scard_init - Initialize SIM/USIM connection using PC/SC 42539beb93cSSam Leffler * @sim_type: Allowed SIM types (SIM, USIM, or both) 42639beb93cSSam Leffler * Returns: Pointer to private data structure, or %NULL on failure 42739beb93cSSam Leffler * 42839beb93cSSam Leffler * This function is used to initialize SIM/USIM connection. PC/SC is used to 42939beb93cSSam Leffler * open connection to the SIM/USIM card and the card is verified to support the 43039beb93cSSam Leffler * selected sim_type. In addition, local flag is set if a PIN is needed to 43139beb93cSSam Leffler * access some of the card functions. Once the connection is not needed 43239beb93cSSam Leffler * anymore, scard_deinit() can be used to close it. 43339beb93cSSam Leffler */ 43439beb93cSSam Leffler struct scard_data * scard_init(scard_sim_type sim_type) 43539beb93cSSam Leffler { 43639beb93cSSam Leffler long ret; 43739beb93cSSam Leffler unsigned long len; 43839beb93cSSam Leffler struct scard_data *scard; 43939beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS 44039beb93cSSam Leffler TCHAR *readers = NULL; 44139beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */ 44239beb93cSSam Leffler char *readers = NULL; 44339beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 44439beb93cSSam Leffler unsigned char buf[100]; 44539beb93cSSam Leffler size_t blen; 44639beb93cSSam Leffler int transaction = 0; 44739beb93cSSam Leffler int pin_needed; 44839beb93cSSam Leffler 44939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); 45039beb93cSSam Leffler if (mingw_load_symbols()) 45139beb93cSSam Leffler return NULL; 45239beb93cSSam Leffler scard = os_zalloc(sizeof(*scard)); 45339beb93cSSam Leffler if (scard == NULL) 45439beb93cSSam Leffler return NULL; 45539beb93cSSam Leffler 45639beb93cSSam Leffler ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, 45739beb93cSSam Leffler &scard->ctx); 45839beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 45939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " 46039beb93cSSam Leffler "context (err=%ld)", ret); 46139beb93cSSam Leffler goto failed; 46239beb93cSSam Leffler } 46339beb93cSSam Leffler 46439beb93cSSam Leffler ret = SCardListReaders(scard->ctx, NULL, NULL, &len); 46539beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 46639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " 46739beb93cSSam Leffler "(err=%ld)", ret); 46839beb93cSSam Leffler goto failed; 46939beb93cSSam Leffler } 47039beb93cSSam Leffler 47139beb93cSSam Leffler #ifdef UNICODE 47239beb93cSSam Leffler len *= 2; 47339beb93cSSam Leffler #endif /* UNICODE */ 47439beb93cSSam Leffler readers = os_malloc(len); 47539beb93cSSam Leffler if (readers == NULL) { 47639beb93cSSam Leffler wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); 47739beb93cSSam Leffler goto failed; 47839beb93cSSam Leffler } 47939beb93cSSam Leffler 48039beb93cSSam Leffler ret = SCardListReaders(scard->ctx, NULL, readers, &len); 48139beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 48239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " 48339beb93cSSam Leffler "(err=%ld)", ret); 48439beb93cSSam Leffler goto failed; 48539beb93cSSam Leffler } 48639beb93cSSam Leffler if (len < 3) { 48739beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: No smart card readers " 48839beb93cSSam Leffler "available."); 48939beb93cSSam Leffler goto failed; 49039beb93cSSam Leffler } 49139beb93cSSam Leffler /* readers is a list of available reader. Last entry is terminated with 49239beb93cSSam Leffler * double NUL. 49339beb93cSSam Leffler * TODO: add support for selecting the reader; now just use the first 49439beb93cSSam Leffler * one.. */ 49539beb93cSSam Leffler #ifdef UNICODE 49639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); 49739beb93cSSam Leffler #else /* UNICODE */ 49839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); 49939beb93cSSam Leffler #endif /* UNICODE */ 50039beb93cSSam Leffler 50139beb93cSSam Leffler ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, 50239beb93cSSam Leffler SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); 50339beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 50439beb93cSSam Leffler if (ret == (long) SCARD_E_NO_SMARTCARD) 50539beb93cSSam Leffler wpa_printf(MSG_INFO, "No smart card inserted."); 50639beb93cSSam Leffler else 50739beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); 50839beb93cSSam Leffler goto failed; 50939beb93cSSam Leffler } 51039beb93cSSam Leffler 51139beb93cSSam Leffler os_free(readers); 51239beb93cSSam Leffler readers = NULL; 51339beb93cSSam Leffler 51439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", 51539beb93cSSam Leffler (unsigned int) scard->card, scard->protocol, 51639beb93cSSam Leffler scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); 51739beb93cSSam Leffler 51839beb93cSSam Leffler ret = SCardBeginTransaction(scard->card); 51939beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 52039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " 52139beb93cSSam Leffler "0x%x", (unsigned int) ret); 52239beb93cSSam Leffler goto failed; 52339beb93cSSam Leffler } 52439beb93cSSam Leffler transaction = 1; 52539beb93cSSam Leffler 52639beb93cSSam Leffler blen = sizeof(buf); 52739beb93cSSam Leffler 52839beb93cSSam Leffler scard->sim_type = SCARD_GSM_SIM; 52939beb93cSSam Leffler if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { 53039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); 53139beb93cSSam Leffler if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, 53239beb93cSSam Leffler SCARD_USIM, NULL, 0)) { 53339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); 53439beb93cSSam Leffler if (sim_type == SCARD_USIM_ONLY) 53539beb93cSSam Leffler goto failed; 53639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM"); 53739beb93cSSam Leffler scard->sim_type = SCARD_GSM_SIM; 53839beb93cSSam Leffler } else { 53939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); 54039beb93cSSam Leffler scard->sim_type = SCARD_USIM; 54139beb93cSSam Leffler } 54239beb93cSSam Leffler } 54339beb93cSSam Leffler 54439beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 54539beb93cSSam Leffler blen = sizeof(buf); 54639beb93cSSam Leffler if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { 54739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); 54839beb93cSSam Leffler goto failed; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler 55139beb93cSSam Leffler blen = sizeof(buf); 55239beb93cSSam Leffler if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { 55339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); 55439beb93cSSam Leffler goto failed; 55539beb93cSSam Leffler } 55639beb93cSSam Leffler } else { 55739beb93cSSam Leffler unsigned char aid[32]; 55839beb93cSSam Leffler int aid_len; 55939beb93cSSam Leffler 56039beb93cSSam Leffler aid_len = scard_get_aid(scard, aid, sizeof(aid)); 56139beb93cSSam Leffler if (aid_len < 0) { 56239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " 56339beb93cSSam Leffler "3G USIM app - try to use standard 3G RID"); 56439beb93cSSam Leffler os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); 56539beb93cSSam Leffler aid_len = 5; 56639beb93cSSam Leffler } 56739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); 56839beb93cSSam Leffler 56939beb93cSSam Leffler /* Select based on AID = 3G RID from EF_DIR. This is usually 57039beb93cSSam Leffler * starting with A0 00 00 00 87. */ 57139beb93cSSam Leffler blen = sizeof(buf); 57239beb93cSSam Leffler if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, 57339beb93cSSam Leffler aid, aid_len)) { 57439beb93cSSam Leffler wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " 57539beb93cSSam Leffler "app"); 57639beb93cSSam Leffler wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", 57739beb93cSSam Leffler aid, aid_len); 57839beb93cSSam Leffler goto failed; 57939beb93cSSam Leffler } 58039beb93cSSam Leffler } 58139beb93cSSam Leffler 58239beb93cSSam Leffler /* Verify whether CHV1 (PIN1) is needed to access the card. */ 58339beb93cSSam Leffler pin_needed = scard_pin_needed(scard, buf, blen); 58439beb93cSSam Leffler if (pin_needed < 0) { 58539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " 58639beb93cSSam Leffler "is needed"); 58739beb93cSSam Leffler goto failed; 58839beb93cSSam Leffler } 58939beb93cSSam Leffler if (pin_needed) { 59039beb93cSSam Leffler scard->pin1_required = 1; 59139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); 59239beb93cSSam Leffler } 59339beb93cSSam Leffler 59439beb93cSSam Leffler ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 59539beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 59639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " 59739beb93cSSam Leffler "0x%x", (unsigned int) ret); 59839beb93cSSam Leffler } 59939beb93cSSam Leffler 60039beb93cSSam Leffler return scard; 60139beb93cSSam Leffler 60239beb93cSSam Leffler failed: 60339beb93cSSam Leffler if (transaction) 60439beb93cSSam Leffler SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 60539beb93cSSam Leffler os_free(readers); 60639beb93cSSam Leffler scard_deinit(scard); 60739beb93cSSam Leffler return NULL; 60839beb93cSSam Leffler } 60939beb93cSSam Leffler 61039beb93cSSam Leffler 61139beb93cSSam Leffler /** 61239beb93cSSam Leffler * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands 61339beb93cSSam Leffler * @scard: Pointer to private data from scard_init() 61439beb93cSSam Leffler * @pin: PIN code as an ASCII string (e.g., "1234") 61539beb93cSSam Leffler * Returns: 0 on success, -1 on failure 61639beb93cSSam Leffler */ 61739beb93cSSam Leffler int scard_set_pin(struct scard_data *scard, const char *pin) 61839beb93cSSam Leffler { 61939beb93cSSam Leffler if (scard == NULL) 62039beb93cSSam Leffler return -1; 62139beb93cSSam Leffler 62239beb93cSSam Leffler /* Verify whether CHV1 (PIN1) is needed to access the card. */ 62339beb93cSSam Leffler if (scard->pin1_required) { 62439beb93cSSam Leffler if (pin == NULL) { 62539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "No PIN configured for SIM " 62639beb93cSSam Leffler "access"); 62739beb93cSSam Leffler return -1; 62839beb93cSSam Leffler } 62939beb93cSSam Leffler if (scard_verify_pin(scard, pin)) { 63039beb93cSSam Leffler wpa_printf(MSG_INFO, "PIN verification failed for " 63139beb93cSSam Leffler "SIM access"); 63239beb93cSSam Leffler return -1; 63339beb93cSSam Leffler } 63439beb93cSSam Leffler } 63539beb93cSSam Leffler 63639beb93cSSam Leffler return 0; 63739beb93cSSam Leffler } 63839beb93cSSam Leffler 63939beb93cSSam Leffler 64039beb93cSSam Leffler /** 64139beb93cSSam Leffler * scard_deinit - Deinitialize SIM/USIM connection 64239beb93cSSam Leffler * @scard: Pointer to private data from scard_init() 64339beb93cSSam Leffler * 64439beb93cSSam Leffler * This function closes the SIM/USIM connect opened with scard_init(). 64539beb93cSSam Leffler */ 64639beb93cSSam Leffler void scard_deinit(struct scard_data *scard) 64739beb93cSSam Leffler { 64839beb93cSSam Leffler long ret; 64939beb93cSSam Leffler 65039beb93cSSam Leffler if (scard == NULL) 65139beb93cSSam Leffler return; 65239beb93cSSam Leffler 65339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); 65439beb93cSSam Leffler if (scard->card) { 65539beb93cSSam Leffler ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); 65639beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 65739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " 65839beb93cSSam Leffler "smart card (err=%ld)", ret); 65939beb93cSSam Leffler } 66039beb93cSSam Leffler } 66139beb93cSSam Leffler 66239beb93cSSam Leffler if (scard->ctx) { 66339beb93cSSam Leffler ret = SCardReleaseContext(scard->ctx); 66439beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 66539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to release smart card " 66639beb93cSSam Leffler "context (err=%ld)", ret); 66739beb93cSSam Leffler } 66839beb93cSSam Leffler } 66939beb93cSSam Leffler os_free(scard); 67039beb93cSSam Leffler mingw_unload_symbols(); 67139beb93cSSam Leffler } 67239beb93cSSam Leffler 67339beb93cSSam Leffler 67439beb93cSSam Leffler static long scard_transmit(struct scard_data *scard, 67539beb93cSSam Leffler unsigned char *_send, size_t send_len, 67639beb93cSSam Leffler unsigned char *_recv, size_t *recv_len) 67739beb93cSSam Leffler { 67839beb93cSSam Leffler long ret; 67939beb93cSSam Leffler unsigned long rlen; 68039beb93cSSam Leffler 68139beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", 68239beb93cSSam Leffler _send, send_len); 68339beb93cSSam Leffler rlen = *recv_len; 68439beb93cSSam Leffler ret = SCardTransmit(scard->card, 68539beb93cSSam Leffler scard->protocol == SCARD_PROTOCOL_T1 ? 68639beb93cSSam Leffler SCARD_PCI_T1 : SCARD_PCI_T0, 68739beb93cSSam Leffler _send, (unsigned long) send_len, 68839beb93cSSam Leffler NULL, _recv, &rlen); 68939beb93cSSam Leffler *recv_len = rlen; 69039beb93cSSam Leffler if (ret == SCARD_S_SUCCESS) { 69139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", 69239beb93cSSam Leffler _recv, rlen); 69339beb93cSSam Leffler } else { 69439beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 69539beb93cSSam Leffler "(err=0x%lx)", ret); 69639beb93cSSam Leffler } 69739beb93cSSam Leffler return ret; 69839beb93cSSam Leffler } 69939beb93cSSam Leffler 70039beb93cSSam Leffler 70139beb93cSSam Leffler static int _scard_select_file(struct scard_data *scard, unsigned short file_id, 70239beb93cSSam Leffler unsigned char *buf, size_t *buf_len, 70339beb93cSSam Leffler sim_types sim_type, unsigned char *aid, 70439beb93cSSam Leffler size_t aidlen) 70539beb93cSSam Leffler { 70639beb93cSSam Leffler long ret; 70739beb93cSSam Leffler unsigned char resp[3]; 70839beb93cSSam Leffler unsigned char cmd[50] = { SIM_CMD_SELECT }; 70939beb93cSSam Leffler int cmdlen; 71039beb93cSSam Leffler unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 71139beb93cSSam Leffler size_t len, rlen; 71239beb93cSSam Leffler 71339beb93cSSam Leffler if (sim_type == SCARD_USIM) { 71439beb93cSSam Leffler cmd[0] = USIM_CLA; 71539beb93cSSam Leffler cmd[3] = 0x04; 71639beb93cSSam Leffler get_resp[0] = USIM_CLA; 71739beb93cSSam Leffler } 71839beb93cSSam Leffler 71939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); 72039beb93cSSam Leffler if (aid) { 72139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", 72239beb93cSSam Leffler aid, aidlen); 72339beb93cSSam Leffler if (5 + aidlen > sizeof(cmd)) 72439beb93cSSam Leffler return -1; 72539beb93cSSam Leffler cmd[2] = 0x04; /* Select by AID */ 72639beb93cSSam Leffler cmd[4] = aidlen; /* len */ 72739beb93cSSam Leffler os_memcpy(cmd + 5, aid, aidlen); 72839beb93cSSam Leffler cmdlen = 5 + aidlen; 72939beb93cSSam Leffler } else { 73039beb93cSSam Leffler cmd[5] = file_id >> 8; 73139beb93cSSam Leffler cmd[6] = file_id & 0xff; 73239beb93cSSam Leffler cmdlen = 7; 73339beb93cSSam Leffler } 73439beb93cSSam Leffler len = sizeof(resp); 73539beb93cSSam Leffler ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 73639beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 73739beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 73839beb93cSSam Leffler "(err=0x%lx)", ret); 73939beb93cSSam Leffler return -1; 74039beb93cSSam Leffler } 74139beb93cSSam Leffler 74239beb93cSSam Leffler if (len != 2) { 74339beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " 74439beb93cSSam Leffler "%d (expected 2)", (int) len); 74539beb93cSSam Leffler return -1; 74639beb93cSSam Leffler } 74739beb93cSSam Leffler 74839beb93cSSam Leffler if (resp[0] == 0x98 && resp[1] == 0x04) { 74939beb93cSSam Leffler /* Security status not satisfied (PIN_WLAN) */ 75039beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " 75139beb93cSSam Leffler "(PIN_WLAN)"); 75239beb93cSSam Leffler return -1; 75339beb93cSSam Leffler } 75439beb93cSSam Leffler 75539beb93cSSam Leffler if (resp[0] == 0x6e) { 75639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); 75739beb93cSSam Leffler return -1; 75839beb93cSSam Leffler } 75939beb93cSSam Leffler 76039beb93cSSam Leffler if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { 76139beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " 76239beb93cSSam Leffler "(expected 0x61, 0x6c, or 0x9f)", resp[0]); 76339beb93cSSam Leffler return -1; 76439beb93cSSam Leffler } 76539beb93cSSam Leffler /* Normal ending of command; resp[1] bytes available */ 76639beb93cSSam Leffler get_resp[4] = resp[1]; 76739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", 76839beb93cSSam Leffler resp[1]); 76939beb93cSSam Leffler 77039beb93cSSam Leffler rlen = *buf_len; 77139beb93cSSam Leffler ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); 77239beb93cSSam Leffler if (ret == SCARD_S_SUCCESS) { 77339beb93cSSam Leffler *buf_len = resp[1] < rlen ? resp[1] : rlen; 77439beb93cSSam Leffler return 0; 77539beb93cSSam Leffler } 77639beb93cSSam Leffler 77739beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); 77839beb93cSSam Leffler return -1; 77939beb93cSSam Leffler } 78039beb93cSSam Leffler 78139beb93cSSam Leffler 78239beb93cSSam Leffler static int scard_select_file(struct scard_data *scard, unsigned short file_id, 78339beb93cSSam Leffler unsigned char *buf, size_t *buf_len) 78439beb93cSSam Leffler { 78539beb93cSSam Leffler return _scard_select_file(scard, file_id, buf, buf_len, 78639beb93cSSam Leffler scard->sim_type, NULL, 0); 78739beb93cSSam Leffler } 78839beb93cSSam Leffler 78939beb93cSSam Leffler 79039beb93cSSam Leffler static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, 79139beb93cSSam Leffler unsigned char mode) 79239beb93cSSam Leffler { 79339beb93cSSam Leffler unsigned char buf[255]; 79439beb93cSSam Leffler unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 79539beb93cSSam Leffler size_t blen; 79639beb93cSSam Leffler long ret; 79739beb93cSSam Leffler 79839beb93cSSam Leffler if (scard->sim_type == SCARD_USIM) 79939beb93cSSam Leffler cmd[0] = USIM_CLA; 80039beb93cSSam Leffler cmd[2] = recnum; 80139beb93cSSam Leffler cmd[3] = mode; 80239beb93cSSam Leffler cmd[4] = sizeof(buf); 80339beb93cSSam Leffler 80439beb93cSSam Leffler blen = sizeof(buf); 80539beb93cSSam Leffler ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 80639beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 80739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " 80839beb93cSSam Leffler "length for record %d", recnum); 80939beb93cSSam Leffler return -1; 81039beb93cSSam Leffler } 81139beb93cSSam Leffler 81239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", 81339beb93cSSam Leffler buf, blen); 81439beb93cSSam Leffler 81539beb93cSSam Leffler if (blen < 2 || buf[0] != 0x6c) { 81639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " 81739beb93cSSam Leffler "length determination"); 81839beb93cSSam Leffler return -1; 81939beb93cSSam Leffler } 82039beb93cSSam Leffler 82139beb93cSSam Leffler return buf[1]; 82239beb93cSSam Leffler } 82339beb93cSSam Leffler 82439beb93cSSam Leffler 82539beb93cSSam Leffler static int scard_read_record(struct scard_data *scard, 82639beb93cSSam Leffler unsigned char *data, size_t len, 82739beb93cSSam Leffler unsigned char recnum, unsigned char mode) 82839beb93cSSam Leffler { 82939beb93cSSam Leffler unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 83039beb93cSSam Leffler size_t blen = len + 3; 83139beb93cSSam Leffler unsigned char *buf; 83239beb93cSSam Leffler long ret; 83339beb93cSSam Leffler 83439beb93cSSam Leffler if (scard->sim_type == SCARD_USIM) 83539beb93cSSam Leffler cmd[0] = USIM_CLA; 83639beb93cSSam Leffler cmd[2] = recnum; 83739beb93cSSam Leffler cmd[3] = mode; 83839beb93cSSam Leffler cmd[4] = len; 83939beb93cSSam Leffler 84039beb93cSSam Leffler buf = os_malloc(blen); 84139beb93cSSam Leffler if (buf == NULL) 84239beb93cSSam Leffler return -1; 84339beb93cSSam Leffler 84439beb93cSSam Leffler ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 84539beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 84639beb93cSSam Leffler os_free(buf); 84739beb93cSSam Leffler return -2; 84839beb93cSSam Leffler } 84939beb93cSSam Leffler if (blen != len + 2) { 85039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 85139beb93cSSam Leffler "length %ld (expected %ld)", 85239beb93cSSam Leffler (long) blen, (long) len + 2); 85339beb93cSSam Leffler os_free(buf); 85439beb93cSSam Leffler return -3; 85539beb93cSSam Leffler } 85639beb93cSSam Leffler 85739beb93cSSam Leffler if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 85839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 85939beb93cSSam Leffler "status %02x %02x (expected 90 00)", 86039beb93cSSam Leffler buf[len], buf[len + 1]); 86139beb93cSSam Leffler os_free(buf); 86239beb93cSSam Leffler return -4; 86339beb93cSSam Leffler } 86439beb93cSSam Leffler 86539beb93cSSam Leffler os_memcpy(data, buf, len); 86639beb93cSSam Leffler os_free(buf); 86739beb93cSSam Leffler 86839beb93cSSam Leffler return 0; 86939beb93cSSam Leffler } 87039beb93cSSam Leffler 87139beb93cSSam Leffler 87239beb93cSSam Leffler static int scard_read_file(struct scard_data *scard, 87339beb93cSSam Leffler unsigned char *data, size_t len) 87439beb93cSSam Leffler { 87539beb93cSSam Leffler unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; 87639beb93cSSam Leffler size_t blen = len + 3; 87739beb93cSSam Leffler unsigned char *buf; 87839beb93cSSam Leffler long ret; 87939beb93cSSam Leffler 88039beb93cSSam Leffler cmd[4] = len; 88139beb93cSSam Leffler 88239beb93cSSam Leffler buf = os_malloc(blen); 88339beb93cSSam Leffler if (buf == NULL) 88439beb93cSSam Leffler return -1; 88539beb93cSSam Leffler 88639beb93cSSam Leffler if (scard->sim_type == SCARD_USIM) 88739beb93cSSam Leffler cmd[0] = USIM_CLA; 88839beb93cSSam Leffler ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 88939beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) { 89039beb93cSSam Leffler os_free(buf); 89139beb93cSSam Leffler return -2; 89239beb93cSSam Leffler } 89339beb93cSSam Leffler if (blen != len + 2) { 89439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 89539beb93cSSam Leffler "length %ld (expected %ld)", 89639beb93cSSam Leffler (long) blen, (long) len + 2); 89739beb93cSSam Leffler os_free(buf); 89839beb93cSSam Leffler return -3; 89939beb93cSSam Leffler } 90039beb93cSSam Leffler 90139beb93cSSam Leffler if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 90239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 90339beb93cSSam Leffler "status %02x %02x (expected 90 00)", 90439beb93cSSam Leffler buf[len], buf[len + 1]); 90539beb93cSSam Leffler os_free(buf); 90639beb93cSSam Leffler return -4; 90739beb93cSSam Leffler } 90839beb93cSSam Leffler 90939beb93cSSam Leffler os_memcpy(data, buf, len); 91039beb93cSSam Leffler os_free(buf); 91139beb93cSSam Leffler 91239beb93cSSam Leffler return 0; 91339beb93cSSam Leffler } 91439beb93cSSam Leffler 91539beb93cSSam Leffler 91639beb93cSSam Leffler static int scard_verify_pin(struct scard_data *scard, const char *pin) 91739beb93cSSam Leffler { 91839beb93cSSam Leffler long ret; 91939beb93cSSam Leffler unsigned char resp[3]; 92039beb93cSSam Leffler unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; 92139beb93cSSam Leffler size_t len; 92239beb93cSSam Leffler 92339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); 92439beb93cSSam Leffler 92539beb93cSSam Leffler if (pin == NULL || os_strlen(pin) > 8) 92639beb93cSSam Leffler return -1; 92739beb93cSSam Leffler 92839beb93cSSam Leffler if (scard->sim_type == SCARD_USIM) 92939beb93cSSam Leffler cmd[0] = USIM_CLA; 93039beb93cSSam Leffler os_memcpy(cmd + 5, pin, os_strlen(pin)); 93139beb93cSSam Leffler os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); 93239beb93cSSam Leffler 93339beb93cSSam Leffler len = sizeof(resp); 93439beb93cSSam Leffler ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 93539beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) 93639beb93cSSam Leffler return -2; 93739beb93cSSam Leffler 93839beb93cSSam Leffler if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { 93939beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); 94039beb93cSSam Leffler return -1; 94139beb93cSSam Leffler } 94239beb93cSSam Leffler 94339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); 94439beb93cSSam Leffler return 0; 94539beb93cSSam Leffler } 94639beb93cSSam Leffler 94739beb93cSSam Leffler 94839beb93cSSam Leffler /** 94939beb93cSSam Leffler * scard_get_imsi - Read IMSI from SIM/USIM card 95039beb93cSSam Leffler * @scard: Pointer to private data from scard_init() 95139beb93cSSam Leffler * @imsi: Buffer for IMSI 95239beb93cSSam Leffler * @len: Length of imsi buffer; set to IMSI length on success 95339beb93cSSam Leffler * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file 95439beb93cSSam Leffler * selection returns invalid result code, -3 if parsing FSP template file fails 95539beb93cSSam Leffler * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set 95639beb93cSSam Leffler * to needed length), -5 if reading IMSI file fails. 95739beb93cSSam Leffler * 95839beb93cSSam Leffler * This function can be used to read IMSI from the SIM/USIM card. If the IMSI 95939beb93cSSam Leffler * file is PIN protected, scard_set_pin() must have been used to set the 96039beb93cSSam Leffler * correct PIN code before calling scard_get_imsi(). 96139beb93cSSam Leffler */ 96239beb93cSSam Leffler int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) 96339beb93cSSam Leffler { 96439beb93cSSam Leffler unsigned char buf[100]; 96539beb93cSSam Leffler size_t blen, imsilen, i; 96639beb93cSSam Leffler char *pos; 96739beb93cSSam Leffler 96839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); 96939beb93cSSam Leffler blen = sizeof(buf); 97039beb93cSSam Leffler if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) 97139beb93cSSam Leffler return -1; 97239beb93cSSam Leffler if (blen < 4) { 97339beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " 97439beb93cSSam Leffler "header (len=%ld)", (long) blen); 97539beb93cSSam Leffler return -2; 97639beb93cSSam Leffler } 97739beb93cSSam Leffler 97839beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 97939beb93cSSam Leffler blen = (buf[2] << 8) | buf[3]; 98039beb93cSSam Leffler } else { 98139beb93cSSam Leffler int file_size; 98239beb93cSSam Leffler if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) 98339beb93cSSam Leffler return -3; 98439beb93cSSam Leffler blen = file_size; 98539beb93cSSam Leffler } 98639beb93cSSam Leffler if (blen < 2 || blen > sizeof(buf)) { 98739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", 98839beb93cSSam Leffler (long) blen); 98939beb93cSSam Leffler return -3; 99039beb93cSSam Leffler } 99139beb93cSSam Leffler 99239beb93cSSam Leffler imsilen = (blen - 2) * 2 + 1; 99339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", 99439beb93cSSam Leffler (long) blen, (long) imsilen); 99539beb93cSSam Leffler if (blen < 2 || imsilen > *len) { 99639beb93cSSam Leffler *len = imsilen; 99739beb93cSSam Leffler return -4; 99839beb93cSSam Leffler } 99939beb93cSSam Leffler 100039beb93cSSam Leffler if (scard_read_file(scard, buf, blen)) 100139beb93cSSam Leffler return -5; 100239beb93cSSam Leffler 100339beb93cSSam Leffler pos = imsi; 100439beb93cSSam Leffler *pos++ = '0' + (buf[1] >> 4 & 0x0f); 100539beb93cSSam Leffler for (i = 2; i < blen; i++) { 100639beb93cSSam Leffler unsigned char digit; 100739beb93cSSam Leffler 100839beb93cSSam Leffler digit = buf[i] & 0x0f; 100939beb93cSSam Leffler if (digit < 10) 101039beb93cSSam Leffler *pos++ = '0' + digit; 101139beb93cSSam Leffler else 101239beb93cSSam Leffler imsilen--; 101339beb93cSSam Leffler 101439beb93cSSam Leffler digit = buf[i] >> 4 & 0x0f; 101539beb93cSSam Leffler if (digit < 10) 101639beb93cSSam Leffler *pos++ = '0' + digit; 101739beb93cSSam Leffler else 101839beb93cSSam Leffler imsilen--; 101939beb93cSSam Leffler } 102039beb93cSSam Leffler *len = imsilen; 102139beb93cSSam Leffler 102239beb93cSSam Leffler return 0; 102339beb93cSSam Leffler } 102439beb93cSSam Leffler 102539beb93cSSam Leffler 102639beb93cSSam Leffler /** 102739beb93cSSam Leffler * scard_gsm_auth - Run GSM authentication command on SIM card 102839beb93cSSam Leffler * @scard: Pointer to private data from scard_init() 102939beb93cSSam Leffler * @_rand: 16-byte RAND value from HLR/AuC 103039beb93cSSam Leffler * @sres: 4-byte buffer for SRES 103139beb93cSSam Leffler * @kc: 8-byte buffer for Kc 103239beb93cSSam Leffler * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, 103339beb93cSSam Leffler * -2 if authentication command execution fails, -3 if unknown response code 103439beb93cSSam Leffler * for authentication command is received, -4 if reading of response fails, 103539beb93cSSam Leffler * -5 if if response data is of unexpected length 103639beb93cSSam Leffler * 103739beb93cSSam Leffler * This function performs GSM authentication using SIM/USIM card and the 103839beb93cSSam Leffler * provided RAND value from HLR/AuC. If authentication command can be completed 103939beb93cSSam Leffler * successfully, SRES and Kc values will be written into sres and kc buffers. 104039beb93cSSam Leffler */ 104139beb93cSSam Leffler int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, 104239beb93cSSam Leffler unsigned char *sres, unsigned char *kc) 104339beb93cSSam Leffler { 104439beb93cSSam Leffler unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; 104539beb93cSSam Leffler int cmdlen; 104639beb93cSSam Leffler unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 104739beb93cSSam Leffler unsigned char resp[3], buf[12 + 3 + 2]; 104839beb93cSSam Leffler size_t len; 104939beb93cSSam Leffler long ret; 105039beb93cSSam Leffler 105139beb93cSSam Leffler if (scard == NULL) 105239beb93cSSam Leffler return -1; 105339beb93cSSam Leffler 105439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); 105539beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 105639beb93cSSam Leffler cmdlen = 5 + 16; 105739beb93cSSam Leffler os_memcpy(cmd + 5, _rand, 16); 105839beb93cSSam Leffler } else { 105939beb93cSSam Leffler cmdlen = 5 + 1 + 16; 106039beb93cSSam Leffler cmd[0] = USIM_CLA; 106139beb93cSSam Leffler cmd[3] = 0x80; 106239beb93cSSam Leffler cmd[4] = 17; 106339beb93cSSam Leffler cmd[5] = 16; 106439beb93cSSam Leffler os_memcpy(cmd + 6, _rand, 16); 106539beb93cSSam Leffler } 106639beb93cSSam Leffler len = sizeof(resp); 106739beb93cSSam Leffler ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 106839beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) 106939beb93cSSam Leffler return -2; 107039beb93cSSam Leffler 107139beb93cSSam Leffler if ((scard->sim_type == SCARD_GSM_SIM && 107239beb93cSSam Leffler (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || 107339beb93cSSam Leffler (scard->sim_type == SCARD_USIM && 107439beb93cSSam Leffler (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { 107539beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " 107639beb93cSSam Leffler "auth request (len=%ld resp=%02x %02x)", 107739beb93cSSam Leffler (long) len, resp[0], resp[1]); 107839beb93cSSam Leffler return -3; 107939beb93cSSam Leffler } 108039beb93cSSam Leffler get_resp[4] = resp[1]; 108139beb93cSSam Leffler 108239beb93cSSam Leffler len = sizeof(buf); 108339beb93cSSam Leffler ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 108439beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) 108539beb93cSSam Leffler return -4; 108639beb93cSSam Leffler 108739beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 108839beb93cSSam Leffler if (len != 4 + 8 + 2) { 108939beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected data " 109039beb93cSSam Leffler "length for GSM auth (len=%ld, expected 14)", 109139beb93cSSam Leffler (long) len); 109239beb93cSSam Leffler return -5; 109339beb93cSSam Leffler } 109439beb93cSSam Leffler os_memcpy(sres, buf, 4); 109539beb93cSSam Leffler os_memcpy(kc, buf + 4, 8); 109639beb93cSSam Leffler } else { 109739beb93cSSam Leffler if (len != 1 + 4 + 1 + 8 + 2) { 109839beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected data " 109939beb93cSSam Leffler "length for USIM auth (len=%ld, " 110039beb93cSSam Leffler "expected 16)", (long) len); 110139beb93cSSam Leffler return -5; 110239beb93cSSam Leffler } 110339beb93cSSam Leffler if (buf[0] != 4 || buf[5] != 8) { 110439beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " 110539beb93cSSam Leffler "length (%d %d, expected 4 8)", 110639beb93cSSam Leffler buf[0], buf[5]); 110739beb93cSSam Leffler } 110839beb93cSSam Leffler os_memcpy(sres, buf + 1, 4); 110939beb93cSSam Leffler os_memcpy(kc, buf + 6, 8); 111039beb93cSSam Leffler } 111139beb93cSSam Leffler 111239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); 111339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); 111439beb93cSSam Leffler 111539beb93cSSam Leffler return 0; 111639beb93cSSam Leffler } 111739beb93cSSam Leffler 111839beb93cSSam Leffler 111939beb93cSSam Leffler /** 112039beb93cSSam Leffler * scard_umts_auth - Run UMTS authentication command on USIM card 112139beb93cSSam Leffler * @scard: Pointer to private data from scard_init() 112239beb93cSSam Leffler * @_rand: 16-byte RAND value from HLR/AuC 112339beb93cSSam Leffler * @autn: 16-byte AUTN value from HLR/AuC 112439beb93cSSam Leffler * @res: 16-byte buffer for RES 112539beb93cSSam Leffler * @res_len: Variable that will be set to RES length 112639beb93cSSam Leffler * @ik: 16-byte buffer for IK 112739beb93cSSam Leffler * @ck: 16-byte buffer for CK 112839beb93cSSam Leffler * @auts: 14-byte buffer for AUTS 112939beb93cSSam Leffler * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization 113039beb93cSSam Leffler * failure 113139beb93cSSam Leffler * 113239beb93cSSam Leffler * This function performs AKA authentication using USIM card and the provided 113339beb93cSSam Leffler * RAND and AUTN values from HLR/AuC. If authentication command can be 113439beb93cSSam Leffler * completed successfully, RES, IK, and CK values will be written into provided 113539beb93cSSam Leffler * buffers and res_len is set to length of received RES value. If USIM reports 113639beb93cSSam Leffler * synchronization failure, the received AUTS value will be written into auts 113739beb93cSSam Leffler * buffer. In this case, RES, IK, and CK are not valid. 113839beb93cSSam Leffler */ 113939beb93cSSam Leffler int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, 114039beb93cSSam Leffler const unsigned char *autn, 114139beb93cSSam Leffler unsigned char *res, size_t *res_len, 114239beb93cSSam Leffler unsigned char *ik, unsigned char *ck, unsigned char *auts) 114339beb93cSSam Leffler { 114439beb93cSSam Leffler unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = 114539beb93cSSam Leffler { USIM_CMD_RUN_UMTS_ALG }; 114639beb93cSSam Leffler unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; 114739beb93cSSam Leffler unsigned char resp[3], buf[64], *pos, *end; 114839beb93cSSam Leffler size_t len; 114939beb93cSSam Leffler long ret; 115039beb93cSSam Leffler 115139beb93cSSam Leffler if (scard == NULL) 115239beb93cSSam Leffler return -1; 115339beb93cSSam Leffler 115439beb93cSSam Leffler if (scard->sim_type == SCARD_GSM_SIM) { 115539beb93cSSam Leffler wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " 115639beb93cSSam Leffler "auth"); 115739beb93cSSam Leffler return -1; 115839beb93cSSam Leffler } 115939beb93cSSam Leffler 116039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); 116139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); 116239beb93cSSam Leffler cmd[5] = AKA_RAND_LEN; 116339beb93cSSam Leffler os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); 116439beb93cSSam Leffler cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; 116539beb93cSSam Leffler os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); 116639beb93cSSam Leffler 116739beb93cSSam Leffler len = sizeof(resp); 116839beb93cSSam Leffler ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 116939beb93cSSam Leffler if (ret != SCARD_S_SUCCESS) 117039beb93cSSam Leffler return -1; 117139beb93cSSam Leffler 117239beb93cSSam Leffler if (len <= sizeof(resp)) 117339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); 117439beb93cSSam Leffler 117539beb93cSSam Leffler if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { 117639beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " 117739beb93cSSam Leffler "MAC != XMAC"); 117839beb93cSSam Leffler return -1; 117939beb93cSSam Leffler } else if (len != 2 || resp[0] != 0x61) { 118039beb93cSSam Leffler wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " 118139beb93cSSam Leffler "auth request (len=%ld resp=%02x %02x)", 118239beb93cSSam Leffler (long) len, resp[0], resp[1]); 118339beb93cSSam Leffler return -1; 118439beb93cSSam Leffler } 118539beb93cSSam Leffler get_resp[4] = resp[1]; 118639beb93cSSam Leffler 118739beb93cSSam Leffler len = sizeof(buf); 118839beb93cSSam Leffler ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 118939beb93cSSam Leffler if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) 119039beb93cSSam Leffler return -1; 119139beb93cSSam Leffler 119239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); 119339beb93cSSam Leffler if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && 119439beb93cSSam Leffler buf[1] == AKA_AUTS_LEN) { 119539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); 119639beb93cSSam Leffler os_memcpy(auts, buf + 2, AKA_AUTS_LEN); 119739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); 119839beb93cSSam Leffler return -2; 119939beb93cSSam Leffler } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { 120039beb93cSSam Leffler pos = buf + 1; 120139beb93cSSam Leffler end = buf + len; 120239beb93cSSam Leffler 120339beb93cSSam Leffler /* RES */ 120439beb93cSSam Leffler if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { 120539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); 120639beb93cSSam Leffler return -1; 120739beb93cSSam Leffler } 120839beb93cSSam Leffler *res_len = *pos++; 120939beb93cSSam Leffler os_memcpy(res, pos, *res_len); 121039beb93cSSam Leffler pos += *res_len; 121139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); 121239beb93cSSam Leffler 121339beb93cSSam Leffler /* CK */ 121439beb93cSSam Leffler if (pos[0] != CK_LEN || pos + CK_LEN > end) { 121539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); 121639beb93cSSam Leffler return -1; 121739beb93cSSam Leffler } 121839beb93cSSam Leffler pos++; 121939beb93cSSam Leffler os_memcpy(ck, pos, CK_LEN); 122039beb93cSSam Leffler pos += CK_LEN; 122139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); 122239beb93cSSam Leffler 122339beb93cSSam Leffler /* IK */ 122439beb93cSSam Leffler if (pos[0] != IK_LEN || pos + IK_LEN > end) { 122539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); 122639beb93cSSam Leffler return -1; 122739beb93cSSam Leffler } 122839beb93cSSam Leffler pos++; 122939beb93cSSam Leffler os_memcpy(ik, pos, IK_LEN); 123039beb93cSSam Leffler pos += IK_LEN; 123139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); 123239beb93cSSam Leffler 123339beb93cSSam Leffler return 0; 123439beb93cSSam Leffler } 123539beb93cSSam Leffler 123639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); 123739beb93cSSam Leffler return -1; 123839beb93cSSam Leffler } 1239