xref: /freebsd/contrib/wpa/src/utils/pcsc_funcs.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
3f05cddf9SRui Paulo  * Copyright (c) 2004-2007, 2012, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  *
839beb93cSSam Leffler  * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
939beb93cSSam Leffler  * cards through PC/SC smartcard library. These functions are used to implement
1039beb93cSSam Leffler  * authentication routines for EAP-SIM and EAP-AKA.
1139beb93cSSam Leffler  */
1239beb93cSSam Leffler 
1339beb93cSSam Leffler #include "includes.h"
1439beb93cSSam Leffler #include <winscard.h>
1539beb93cSSam Leffler 
1639beb93cSSam Leffler #include "common.h"
1739beb93cSSam Leffler #include "pcsc_funcs.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler 
2039beb93cSSam Leffler /* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
2139beb93cSSam Leffler  * SIM commands:
2239beb93cSSam Leffler  * Command APDU: CLA INS P1 P2 P3 Data
2339beb93cSSam Leffler  *   CLA (class of instruction): A0 for GSM, 00 for USIM
2439beb93cSSam Leffler  *   INS (instruction)
2539beb93cSSam Leffler  *   P1 P2 P3 (parameters, P3 = length of Data)
2639beb93cSSam Leffler  * Response APDU: Data SW1 SW2
2739beb93cSSam Leffler  *   SW1 SW2 (Status words)
2839beb93cSSam Leffler  * Commands (INS P1 P2 P3):
2939beb93cSSam Leffler  *   SELECT: A4 00 00 02 <file_id, 2 bytes>
3039beb93cSSam Leffler  *   GET RESPONSE: C0 00 00 <len>
3139beb93cSSam Leffler  *   RUN GSM ALG: 88 00 00 00 <RAND len = 10>
3239beb93cSSam Leffler  *   RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
3339beb93cSSam Leffler  *	P1 = ID of alg in card
3439beb93cSSam Leffler  *	P2 = ID of secret key
3539beb93cSSam Leffler  *   READ BINARY: B0 <offset high> <offset low> <len>
3639beb93cSSam Leffler  *   READ RECORD: B2 <record number> <mode> <len>
3739beb93cSSam Leffler  *	P2 (mode) = '02' (next record), '03' (previous record),
3839beb93cSSam Leffler  *		    '04' (absolute mode)
3939beb93cSSam Leffler  *   VERIFY CHV: 20 00 <CHV number> 08
4039beb93cSSam Leffler  *   CHANGE CHV: 24 00 <CHV number> 10
4139beb93cSSam Leffler  *   DISABLE CHV: 26 00 01 08
4239beb93cSSam Leffler  *   ENABLE CHV: 28 00 01 08
4339beb93cSSam Leffler  *   UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
4439beb93cSSam Leffler  *   SLEEP: FA 00 00 00
4539beb93cSSam Leffler  */
4639beb93cSSam Leffler 
4739beb93cSSam Leffler /* GSM SIM commands */
4839beb93cSSam Leffler #define SIM_CMD_SELECT			0xa0, 0xa4, 0x00, 0x00, 0x02
4939beb93cSSam Leffler #define SIM_CMD_RUN_GSM_ALG		0xa0, 0x88, 0x00, 0x00, 0x10
5039beb93cSSam Leffler #define SIM_CMD_GET_RESPONSE		0xa0, 0xc0, 0x00, 0x00
5139beb93cSSam Leffler #define SIM_CMD_READ_BIN		0xa0, 0xb0, 0x00, 0x00
5239beb93cSSam Leffler #define SIM_CMD_READ_RECORD		0xa0, 0xb2, 0x00, 0x00
5339beb93cSSam Leffler #define SIM_CMD_VERIFY_CHV1		0xa0, 0x20, 0x00, 0x01, 0x08
5439beb93cSSam Leffler 
5539beb93cSSam Leffler /* USIM commands */
5639beb93cSSam Leffler #define USIM_CLA			0x00
5739beb93cSSam Leffler #define USIM_CMD_RUN_UMTS_ALG		0x00, 0x88, 0x00, 0x81, 0x22
5839beb93cSSam Leffler #define USIM_CMD_GET_RESPONSE		0x00, 0xc0, 0x00, 0x00
5939beb93cSSam Leffler 
6039beb93cSSam Leffler #define SIM_RECORD_MODE_ABSOLUTE 0x04
6139beb93cSSam Leffler 
6239beb93cSSam Leffler #define USIM_FSP_TEMPL_TAG		0x62
6339beb93cSSam Leffler 
6439beb93cSSam Leffler #define USIM_TLV_FILE_DESC		0x82
6539beb93cSSam Leffler #define USIM_TLV_FILE_ID		0x83
6639beb93cSSam Leffler #define USIM_TLV_DF_NAME		0x84
6739beb93cSSam Leffler #define USIM_TLV_PROPR_INFO		0xA5
6839beb93cSSam Leffler #define USIM_TLV_LIFE_CYCLE_STATUS	0x8A
6939beb93cSSam Leffler #define USIM_TLV_FILE_SIZE		0x80
7039beb93cSSam Leffler #define USIM_TLV_TOTAL_FILE_SIZE	0x81
7139beb93cSSam Leffler #define USIM_TLV_PIN_STATUS_TEMPLATE	0xC6
7239beb93cSSam Leffler #define USIM_TLV_SHORT_FILE_ID		0x88
73f05cddf9SRui Paulo #define USIM_TLV_SECURITY_ATTR_8B	0x8B
74f05cddf9SRui Paulo #define USIM_TLV_SECURITY_ATTR_8C	0x8C
75f05cddf9SRui Paulo #define USIM_TLV_SECURITY_ATTR_AB	0xAB
7639beb93cSSam Leffler 
7739beb93cSSam Leffler #define USIM_PS_DO_TAG			0x90
7839beb93cSSam Leffler 
7939beb93cSSam Leffler #define AKA_RAND_LEN 16
8039beb93cSSam Leffler #define AKA_AUTN_LEN 16
8139beb93cSSam Leffler #define AKA_AUTS_LEN 14
8239beb93cSSam Leffler #define RES_MAX_LEN 16
8339beb93cSSam Leffler #define IK_LEN 16
8439beb93cSSam Leffler #define CK_LEN 16
8539beb93cSSam Leffler 
8639beb93cSSam Leffler 
87f05cddf9SRui Paulo /* GSM files
88f05cddf9SRui Paulo  * File type in first octet:
89f05cddf9SRui Paulo  * 3F = Master File
90f05cddf9SRui Paulo  * 7F = Dedicated File
91f05cddf9SRui Paulo  * 2F = Elementary File under the Master File
92f05cddf9SRui Paulo  * 6F = Elementary File under a Dedicated File
93f05cddf9SRui Paulo  */
94f05cddf9SRui Paulo #define SCARD_FILE_MF		0x3F00
95f05cddf9SRui Paulo #define SCARD_FILE_GSM_DF	0x7F20
96f05cddf9SRui Paulo #define SCARD_FILE_UMTS_DF	0x7F50
97f05cddf9SRui Paulo #define SCARD_FILE_GSM_EF_IMSI	0x6F07
98f05cddf9SRui Paulo #define SCARD_FILE_GSM_EF_AD	0x6FAD
99f05cddf9SRui Paulo #define SCARD_FILE_EF_DIR	0x2F00
100f05cddf9SRui Paulo #define SCARD_FILE_EF_ICCID	0x2FE2
101f05cddf9SRui Paulo #define SCARD_FILE_EF_CK	0x6FE1
102f05cddf9SRui Paulo #define SCARD_FILE_EF_IK	0x6FE2
103f05cddf9SRui Paulo 
104f05cddf9SRui Paulo #define SCARD_CHV1_OFFSET	13
105f05cddf9SRui Paulo #define SCARD_CHV1_FLAG		0x80
106f05cddf9SRui Paulo 
107f05cddf9SRui Paulo 
10839beb93cSSam Leffler typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
10939beb93cSSam Leffler 
11039beb93cSSam Leffler struct scard_data {
11139beb93cSSam Leffler 	SCARDCONTEXT ctx;
11239beb93cSSam Leffler 	SCARDHANDLE card;
11339beb93cSSam Leffler 	DWORD protocol;
11439beb93cSSam Leffler 	sim_types sim_type;
11539beb93cSSam Leffler 	int pin1_required;
11639beb93cSSam Leffler };
11739beb93cSSam Leffler 
11839beb93cSSam Leffler #ifdef __MINGW32_VERSION
11939beb93cSSam Leffler /* MinGW does not yet support WinScard, so load the needed functions
12039beb93cSSam Leffler  * dynamically from winscard.dll for now. */
12139beb93cSSam Leffler 
12239beb93cSSam Leffler static HINSTANCE dll = NULL; /* winscard.dll */
12339beb93cSSam Leffler 
12439beb93cSSam Leffler static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
12539beb93cSSam Leffler #undef SCARD_PCI_T0
12639beb93cSSam Leffler #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
12739beb93cSSam Leffler #undef SCARD_PCI_T1
12839beb93cSSam Leffler #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
12939beb93cSSam Leffler 
13039beb93cSSam Leffler 
13139beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
13239beb93cSSam Leffler (*dll_SCardEstablishContext)(IN DWORD dwScope,
13339beb93cSSam Leffler 			     IN LPCVOID pvReserved1,
13439beb93cSSam Leffler 			     IN LPCVOID pvReserved2,
13539beb93cSSam Leffler 			     OUT LPSCARDCONTEXT phContext);
13639beb93cSSam Leffler #define SCardEstablishContext dll_SCardEstablishContext
13739beb93cSSam Leffler 
13839beb93cSSam Leffler static long (*dll_SCardReleaseContext)(long hContext);
13939beb93cSSam Leffler #define SCardReleaseContext dll_SCardReleaseContext
14039beb93cSSam Leffler 
14139beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
14239beb93cSSam Leffler (*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
14339beb93cSSam Leffler 			 IN LPCSTR mszGroups,
14439beb93cSSam Leffler 			 OUT LPSTR mszReaders,
14539beb93cSSam Leffler 			 IN OUT LPDWORD pcchReaders);
14639beb93cSSam Leffler #undef SCardListReaders
14739beb93cSSam Leffler #define SCardListReaders dll_SCardListReadersA
14839beb93cSSam Leffler 
14939beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
15039beb93cSSam Leffler (*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
15139beb93cSSam Leffler 		     IN LPCSTR szReader,
15239beb93cSSam Leffler 		     IN DWORD dwShareMode,
15339beb93cSSam Leffler 		     IN DWORD dwPreferredProtocols,
15439beb93cSSam Leffler 		     OUT LPSCARDHANDLE phCard,
15539beb93cSSam Leffler 		     OUT LPDWORD pdwActiveProtocol);
15639beb93cSSam Leffler #undef SCardConnect
15739beb93cSSam Leffler #define SCardConnect dll_SCardConnectA
15839beb93cSSam Leffler 
15939beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
16039beb93cSSam Leffler (*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
16139beb93cSSam Leffler 		       IN DWORD dwDisposition);
16239beb93cSSam Leffler #define SCardDisconnect dll_SCardDisconnect
16339beb93cSSam Leffler 
16439beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
16539beb93cSSam Leffler (*dll_SCardTransmit)(IN SCARDHANDLE hCard,
16639beb93cSSam Leffler 		     IN LPCSCARD_IO_REQUEST pioSendPci,
16739beb93cSSam Leffler 		     IN LPCBYTE pbSendBuffer,
16839beb93cSSam Leffler 		     IN DWORD cbSendLength,
16939beb93cSSam Leffler 		     IN OUT LPSCARD_IO_REQUEST pioRecvPci,
17039beb93cSSam Leffler 		     OUT LPBYTE pbRecvBuffer,
17139beb93cSSam Leffler 		     IN OUT LPDWORD pcbRecvLength);
17239beb93cSSam Leffler #define SCardTransmit dll_SCardTransmit
17339beb93cSSam Leffler 
17439beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
17539beb93cSSam Leffler (*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
17639beb93cSSam Leffler #define SCardBeginTransaction dll_SCardBeginTransaction
17739beb93cSSam Leffler 
17839beb93cSSam Leffler static WINSCARDAPI LONG WINAPI
17939beb93cSSam Leffler (*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
18039beb93cSSam Leffler #define SCardEndTransaction dll_SCardEndTransaction
18139beb93cSSam Leffler 
18239beb93cSSam Leffler 
18339beb93cSSam Leffler static int mingw_load_symbols(void)
18439beb93cSSam Leffler {
18539beb93cSSam Leffler 	char *sym;
18639beb93cSSam Leffler 
18739beb93cSSam Leffler 	if (dll)
18839beb93cSSam Leffler 		return 0;
18939beb93cSSam Leffler 
19039beb93cSSam Leffler 	dll = LoadLibrary("winscard");
19139beb93cSSam Leffler 	if (dll == NULL) {
19239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
19339beb93cSSam Leffler 			   "library");
19439beb93cSSam Leffler 		return -1;
19539beb93cSSam Leffler 	}
19639beb93cSSam Leffler 
19739beb93cSSam Leffler #define LOADSYM(s) \
19839beb93cSSam Leffler 	sym = #s; \
19939beb93cSSam Leffler 	dll_ ## s = (void *) GetProcAddress(dll, sym); \
20039beb93cSSam Leffler 	if (dll_ ## s == NULL) \
20139beb93cSSam Leffler 		goto fail;
20239beb93cSSam Leffler 
20339beb93cSSam Leffler 	LOADSYM(SCardEstablishContext);
20439beb93cSSam Leffler 	LOADSYM(SCardReleaseContext);
20539beb93cSSam Leffler 	LOADSYM(SCardListReadersA);
20639beb93cSSam Leffler 	LOADSYM(SCardConnectA);
20739beb93cSSam Leffler 	LOADSYM(SCardDisconnect);
20839beb93cSSam Leffler 	LOADSYM(SCardTransmit);
20939beb93cSSam Leffler 	LOADSYM(SCardBeginTransaction);
21039beb93cSSam Leffler 	LOADSYM(SCardEndTransaction);
21139beb93cSSam Leffler 	LOADSYM(g_rgSCardT0Pci);
21239beb93cSSam Leffler 	LOADSYM(g_rgSCardT1Pci);
21339beb93cSSam Leffler 
21439beb93cSSam Leffler #undef LOADSYM
21539beb93cSSam Leffler 
21639beb93cSSam Leffler 	return 0;
21739beb93cSSam Leffler 
21839beb93cSSam Leffler fail:
21939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
22039beb93cSSam Leffler 		   "winscard.dll", sym);
22139beb93cSSam Leffler 	FreeLibrary(dll);
22239beb93cSSam Leffler 	dll = NULL;
22339beb93cSSam Leffler 	return -1;
22439beb93cSSam Leffler }
22539beb93cSSam Leffler 
22639beb93cSSam Leffler 
22739beb93cSSam Leffler static void mingw_unload_symbols(void)
22839beb93cSSam Leffler {
22939beb93cSSam Leffler 	if (dll == NULL)
23039beb93cSSam Leffler 		return;
23139beb93cSSam Leffler 
23239beb93cSSam Leffler 	FreeLibrary(dll);
23339beb93cSSam Leffler 	dll = NULL;
23439beb93cSSam Leffler }
23539beb93cSSam Leffler 
23639beb93cSSam Leffler #else /* __MINGW32_VERSION */
23739beb93cSSam Leffler 
23839beb93cSSam Leffler #define mingw_load_symbols() 0
23939beb93cSSam Leffler #define mingw_unload_symbols() do { } while (0)
24039beb93cSSam Leffler 
24139beb93cSSam Leffler #endif /* __MINGW32_VERSION */
24239beb93cSSam Leffler 
24339beb93cSSam Leffler 
24439beb93cSSam Leffler static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
24539beb93cSSam Leffler 			      unsigned char *buf, size_t *buf_len,
24639beb93cSSam Leffler 			      sim_types sim_type, unsigned char *aid,
24739beb93cSSam Leffler 			      size_t aidlen);
24839beb93cSSam Leffler static int scard_select_file(struct scard_data *scard, unsigned short file_id,
24939beb93cSSam Leffler 			     unsigned char *buf, size_t *buf_len);
25039beb93cSSam Leffler static int scard_verify_pin(struct scard_data *scard, const char *pin);
25139beb93cSSam Leffler static int scard_get_record_len(struct scard_data *scard,
25239beb93cSSam Leffler 				unsigned char recnum, unsigned char mode);
25339beb93cSSam Leffler static int scard_read_record(struct scard_data *scard,
25439beb93cSSam Leffler 			     unsigned char *data, size_t len,
25539beb93cSSam Leffler 			     unsigned char recnum, unsigned char mode);
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 
25839beb93cSSam Leffler static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
25939beb93cSSam Leffler 				 int *ps_do, int *file_len)
26039beb93cSSam Leffler {
26139beb93cSSam Leffler 	unsigned char *pos, *end;
26239beb93cSSam Leffler 
26339beb93cSSam Leffler 	if (ps_do)
26439beb93cSSam Leffler 		*ps_do = -1;
26539beb93cSSam Leffler 	if (file_len)
26639beb93cSSam Leffler 		*file_len = -1;
26739beb93cSSam Leffler 
26839beb93cSSam Leffler 	pos = buf;
26939beb93cSSam Leffler 	end = pos + buf_len;
27039beb93cSSam Leffler 	if (*pos != USIM_FSP_TEMPL_TAG) {
27139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: file header did not "
27239beb93cSSam Leffler 			   "start with FSP template tag");
27339beb93cSSam Leffler 		return -1;
27439beb93cSSam Leffler 	}
27539beb93cSSam Leffler 	pos++;
27639beb93cSSam Leffler 	if (pos >= end)
27739beb93cSSam Leffler 		return -1;
27839beb93cSSam Leffler 	if ((pos + pos[0]) < end)
27939beb93cSSam Leffler 		end = pos + 1 + pos[0];
28039beb93cSSam Leffler 	pos++;
28139beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
28239beb93cSSam Leffler 		    pos, end - pos);
28339beb93cSSam Leffler 
284*5b9c547cSRui Paulo 	while (end - pos >= 2) {
285*5b9c547cSRui Paulo 		unsigned char type, len;
286*5b9c547cSRui Paulo 
287*5b9c547cSRui Paulo 		type = pos[0];
288*5b9c547cSRui Paulo 		len = pos[1];
289f05cddf9SRui Paulo 		wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
290*5b9c547cSRui Paulo 			   type, len);
291*5b9c547cSRui Paulo 		pos += 2;
292*5b9c547cSRui Paulo 
293*5b9c547cSRui Paulo 		if (len > (unsigned int) (end - pos))
29439beb93cSSam Leffler 			break;
29539beb93cSSam Leffler 
296*5b9c547cSRui Paulo 		switch (type) {
297f05cddf9SRui Paulo 		case USIM_TLV_FILE_DESC:
298f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
299*5b9c547cSRui Paulo 				    pos, len);
300f05cddf9SRui Paulo 			break;
301f05cddf9SRui Paulo 		case USIM_TLV_FILE_ID:
302f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
303*5b9c547cSRui Paulo 				    pos, len);
304f05cddf9SRui Paulo 			break;
305f05cddf9SRui Paulo 		case USIM_TLV_DF_NAME:
306f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
307*5b9c547cSRui Paulo 				    pos, len);
308f05cddf9SRui Paulo 			break;
309f05cddf9SRui Paulo 		case USIM_TLV_PROPR_INFO:
310f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
311*5b9c547cSRui Paulo 				    "information TLV", pos, len);
312f05cddf9SRui Paulo 			break;
313f05cddf9SRui Paulo 		case USIM_TLV_LIFE_CYCLE_STATUS:
314f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
315*5b9c547cSRui Paulo 				    "Integer TLV", pos, len);
316f05cddf9SRui Paulo 			break;
317f05cddf9SRui Paulo 		case USIM_TLV_FILE_SIZE:
318f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
319*5b9c547cSRui Paulo 				    pos, len);
320*5b9c547cSRui Paulo 			if ((len == 1 || len == 2) && file_len) {
321*5b9c547cSRui Paulo 				if (len == 1)
322*5b9c547cSRui Paulo 					*file_len = (int) pos[0];
32339beb93cSSam Leffler 				else
324*5b9c547cSRui Paulo 					*file_len = WPA_GET_BE16(pos);
32539beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
32639beb93cSSam Leffler 					   *file_len);
32739beb93cSSam Leffler 			}
328f05cddf9SRui Paulo 			break;
329f05cddf9SRui Paulo 		case USIM_TLV_TOTAL_FILE_SIZE:
330f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
331*5b9c547cSRui Paulo 				    pos, len);
332f05cddf9SRui Paulo 			break;
333f05cddf9SRui Paulo 		case USIM_TLV_PIN_STATUS_TEMPLATE:
334f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
335*5b9c547cSRui Paulo 				    "DO TLV", pos, len);
336*5b9c547cSRui Paulo 			if (len >= 2 && pos[0] == USIM_PS_DO_TAG &&
337*5b9c547cSRui Paulo 			    pos[1] >= 1 && ps_do) {
33839beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
339*5b9c547cSRui Paulo 					   pos[2]);
340*5b9c547cSRui Paulo 				*ps_do = (int) pos[2];
34139beb93cSSam Leffler 			}
342f05cddf9SRui Paulo 			break;
343f05cddf9SRui Paulo 		case USIM_TLV_SHORT_FILE_ID:
344f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
345*5b9c547cSRui Paulo 				    "Identifier (SFI) TLV", pos, len);
346f05cddf9SRui Paulo 			break;
347f05cddf9SRui Paulo 		case USIM_TLV_SECURITY_ATTR_8B:
348f05cddf9SRui Paulo 		case USIM_TLV_SECURITY_ATTR_8C:
349f05cddf9SRui Paulo 		case USIM_TLV_SECURITY_ATTR_AB:
350f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
351*5b9c547cSRui Paulo 				    "TLV", pos, len);
352f05cddf9SRui Paulo 			break;
353f05cddf9SRui Paulo 		default:
354f05cddf9SRui Paulo 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
355*5b9c547cSRui Paulo 				    pos, len);
356f05cddf9SRui Paulo 			break;
357f05cddf9SRui Paulo 		}
35839beb93cSSam Leffler 
359*5b9c547cSRui Paulo 		pos += len;
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 		if (pos == end)
36239beb93cSSam Leffler 			return 0;
36339beb93cSSam Leffler 	}
36439beb93cSSam Leffler 	return -1;
36539beb93cSSam Leffler }
36639beb93cSSam Leffler 
36739beb93cSSam Leffler 
36839beb93cSSam Leffler static int scard_pin_needed(struct scard_data *scard,
36939beb93cSSam Leffler 			    unsigned char *hdr, size_t hlen)
37039beb93cSSam Leffler {
37139beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
37239beb93cSSam Leffler 		if (hlen > SCARD_CHV1_OFFSET &&
37339beb93cSSam Leffler 		    !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
37439beb93cSSam Leffler 			return 1;
37539beb93cSSam Leffler 		return 0;
37639beb93cSSam Leffler 	}
37739beb93cSSam Leffler 
37839beb93cSSam Leffler 	if (scard->sim_type == SCARD_USIM) {
37939beb93cSSam Leffler 		int ps_do;
38039beb93cSSam Leffler 		if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
38139beb93cSSam Leffler 			return -1;
38239beb93cSSam Leffler 		/* TODO: there could be more than one PS_DO entry because of
38339beb93cSSam Leffler 		 * multiple PINs in key reference.. */
38439beb93cSSam Leffler 		if (ps_do > 0 && (ps_do & 0x80))
38539beb93cSSam Leffler 			return 1;
38639beb93cSSam Leffler 		return 0;
38739beb93cSSam Leffler 	}
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 	return -1;
39039beb93cSSam Leffler }
39139beb93cSSam Leffler 
39239beb93cSSam Leffler 
39339beb93cSSam Leffler static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
39439beb93cSSam Leffler 			 size_t maxlen)
39539beb93cSSam Leffler {
39639beb93cSSam Leffler 	int rlen, rec;
39739beb93cSSam Leffler 	struct efdir {
39839beb93cSSam Leffler 		unsigned char appl_template_tag; /* 0x61 */
39939beb93cSSam Leffler 		unsigned char appl_template_len;
40039beb93cSSam Leffler 		unsigned char appl_id_tag; /* 0x4f */
40139beb93cSSam Leffler 		unsigned char aid_len;
40239beb93cSSam Leffler 		unsigned char rid[5];
40339beb93cSSam Leffler 		unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
40439beb93cSSam Leffler 	} *efdir;
405*5b9c547cSRui Paulo 	unsigned char buf[127], *aid_pos;
40639beb93cSSam Leffler 	size_t blen;
407*5b9c547cSRui Paulo 	unsigned int aid_len = 0;
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 	efdir = (struct efdir *) buf;
410*5b9c547cSRui Paulo 	aid_pos = &buf[4];
41139beb93cSSam Leffler 	blen = sizeof(buf);
41239beb93cSSam Leffler 	if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
41339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
41439beb93cSSam Leffler 		return -1;
41539beb93cSSam Leffler 	}
41639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 	for (rec = 1; rec < 10; rec++) {
41939beb93cSSam Leffler 		rlen = scard_get_record_len(scard, rec,
42039beb93cSSam Leffler 					    SIM_RECORD_MODE_ABSOLUTE);
42139beb93cSSam Leffler 		if (rlen < 0) {
42239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
42339beb93cSSam Leffler 				   "record length");
42439beb93cSSam Leffler 			return -1;
42539beb93cSSam Leffler 		}
42639beb93cSSam Leffler 		blen = sizeof(buf);
42739beb93cSSam Leffler 		if (rlen > (int) blen) {
42839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
42939beb93cSSam Leffler 			return -1;
43039beb93cSSam Leffler 		}
43139beb93cSSam Leffler 		if (scard_read_record(scard, buf, rlen, rec,
43239beb93cSSam Leffler 				      SIM_RECORD_MODE_ABSOLUTE) < 0) {
43339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
43439beb93cSSam Leffler 				   "EF_DIR record %d", rec);
43539beb93cSSam Leffler 			return -1;
43639beb93cSSam Leffler 		}
43739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
43839beb93cSSam Leffler 
43939beb93cSSam Leffler 		if (efdir->appl_template_tag != 0x61) {
44039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
44139beb93cSSam Leffler 				   "template tag 0x%x",
44239beb93cSSam Leffler 				   efdir->appl_template_tag);
44339beb93cSSam Leffler 			continue;
44439beb93cSSam Leffler 		}
44539beb93cSSam Leffler 
44639beb93cSSam Leffler 		if (efdir->appl_template_len > rlen - 2) {
44739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Too long application "
44839beb93cSSam Leffler 				   "template (len=%d rlen=%d)",
44939beb93cSSam Leffler 				   efdir->appl_template_len, rlen);
45039beb93cSSam Leffler 			continue;
45139beb93cSSam Leffler 		}
45239beb93cSSam Leffler 
45339beb93cSSam Leffler 		if (efdir->appl_id_tag != 0x4f) {
45439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
45539beb93cSSam Leffler 				   "identifier tag 0x%x", efdir->appl_id_tag);
45639beb93cSSam Leffler 			continue;
45739beb93cSSam Leffler 		}
45839beb93cSSam Leffler 
459*5b9c547cSRui Paulo 		aid_len = efdir->aid_len;
460*5b9c547cSRui Paulo 		if (aid_len < 1 || aid_len > 16) {
461*5b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %u",
462*5b9c547cSRui Paulo 				   aid_len);
46339beb93cSSam Leffler 			continue;
46439beb93cSSam Leffler 		}
46539beb93cSSam Leffler 
46639beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
467*5b9c547cSRui Paulo 			    aid_pos, aid_len);
46839beb93cSSam Leffler 
46939beb93cSSam Leffler 		if (efdir->appl_code[0] == 0x10 &&
47039beb93cSSam Leffler 		    efdir->appl_code[1] == 0x02) {
47139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
47239beb93cSSam Leffler 				   "EF_DIR record %d", rec);
47339beb93cSSam Leffler 			break;
47439beb93cSSam Leffler 		}
47539beb93cSSam Leffler 	}
47639beb93cSSam Leffler 
47739beb93cSSam Leffler 	if (rec >= 10) {
47839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
47939beb93cSSam Leffler 			   "from EF_DIR records");
48039beb93cSSam Leffler 		return -1;
48139beb93cSSam Leffler 	}
48239beb93cSSam Leffler 
483*5b9c547cSRui Paulo 	if (aid_len > maxlen) {
48439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
48539beb93cSSam Leffler 		return -1;
48639beb93cSSam Leffler 	}
48739beb93cSSam Leffler 
488*5b9c547cSRui Paulo 	os_memcpy(aid, aid_pos, aid_len);
48939beb93cSSam Leffler 
490*5b9c547cSRui Paulo 	return aid_len;
49139beb93cSSam Leffler }
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 
49439beb93cSSam Leffler /**
49539beb93cSSam Leffler  * scard_init - Initialize SIM/USIM connection using PC/SC
496f05cddf9SRui Paulo  * @reader: Reader name prefix to search for
49739beb93cSSam Leffler  * Returns: Pointer to private data structure, or %NULL on failure
49839beb93cSSam Leffler  *
49939beb93cSSam Leffler  * This function is used to initialize SIM/USIM connection. PC/SC is used to
500*5b9c547cSRui Paulo  * open connection to the SIM/USIM card. In addition, local flag is set if a
501*5b9c547cSRui Paulo  * PIN is needed to access some of the card functions. Once the connection is
502*5b9c547cSRui Paulo  * not needed anymore, scard_deinit() can be used to close it.
50339beb93cSSam Leffler  */
504*5b9c547cSRui Paulo struct scard_data * scard_init(const char *reader)
50539beb93cSSam Leffler {
50639beb93cSSam Leffler 	long ret;
507f05cddf9SRui Paulo 	unsigned long len, pos;
50839beb93cSSam Leffler 	struct scard_data *scard;
50939beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
51039beb93cSSam Leffler 	TCHAR *readers = NULL;
51139beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
51239beb93cSSam Leffler 	char *readers = NULL;
51339beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
51439beb93cSSam Leffler 	unsigned char buf[100];
51539beb93cSSam Leffler 	size_t blen;
51639beb93cSSam Leffler 	int transaction = 0;
51739beb93cSSam Leffler 	int pin_needed;
51839beb93cSSam Leffler 
51939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
52039beb93cSSam Leffler 	if (mingw_load_symbols())
52139beb93cSSam Leffler 		return NULL;
52239beb93cSSam Leffler 	scard = os_zalloc(sizeof(*scard));
52339beb93cSSam Leffler 	if (scard == NULL)
52439beb93cSSam Leffler 		return NULL;
52539beb93cSSam Leffler 
52639beb93cSSam Leffler 	ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
52739beb93cSSam Leffler 				    &scard->ctx);
52839beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
52939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
53039beb93cSSam Leffler 			   "context (err=%ld)", ret);
53139beb93cSSam Leffler 		goto failed;
53239beb93cSSam Leffler 	}
53339beb93cSSam Leffler 
53439beb93cSSam Leffler 	ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
53539beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
53639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
53739beb93cSSam Leffler 			   "(err=%ld)", ret);
53839beb93cSSam Leffler 		goto failed;
53939beb93cSSam Leffler 	}
54039beb93cSSam Leffler 
54139beb93cSSam Leffler #ifdef UNICODE
54239beb93cSSam Leffler 	len *= 2;
54339beb93cSSam Leffler #endif /* UNICODE */
54439beb93cSSam Leffler 	readers = os_malloc(len);
54539beb93cSSam Leffler 	if (readers == NULL) {
54639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
54739beb93cSSam Leffler 		goto failed;
54839beb93cSSam Leffler 	}
54939beb93cSSam Leffler 
55039beb93cSSam Leffler 	ret = SCardListReaders(scard->ctx, NULL, readers, &len);
55139beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
55239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
55339beb93cSSam Leffler 			   "(err=%ld)", ret);
55439beb93cSSam Leffler 		goto failed;
55539beb93cSSam Leffler 	}
55639beb93cSSam Leffler 	if (len < 3) {
55739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
55839beb93cSSam Leffler 			   "available.");
55939beb93cSSam Leffler 		goto failed;
56039beb93cSSam Leffler 	}
561f05cddf9SRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len);
562f05cddf9SRui Paulo 	/*
563f05cddf9SRui Paulo 	 * readers is a list of available readers. The last entry is terminated
564f05cddf9SRui Paulo 	 * with double null.
565f05cddf9SRui Paulo 	 */
566f05cddf9SRui Paulo 	pos = 0;
56739beb93cSSam Leffler #ifdef UNICODE
568f05cddf9SRui Paulo 	/* TODO */
56939beb93cSSam Leffler #else /* UNICODE */
570f05cddf9SRui Paulo 	while (pos < len) {
571f05cddf9SRui Paulo 		if (reader == NULL ||
572f05cddf9SRui Paulo 		    os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0)
573f05cddf9SRui Paulo 			break;
574f05cddf9SRui Paulo 		while (pos < len && readers[pos])
575f05cddf9SRui Paulo 			pos++;
576f05cddf9SRui Paulo 		pos++; /* skip separating null */
577f05cddf9SRui Paulo 		if (pos < len && readers[pos] == '\0')
578f05cddf9SRui Paulo 			pos = len; /* double null terminates list */
579f05cddf9SRui Paulo 	}
580f05cddf9SRui Paulo #endif /* UNICODE */
581f05cddf9SRui Paulo 	if (pos >= len) {
582f05cddf9SRui Paulo 		wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' "
583f05cddf9SRui Paulo 			   "found", reader);
584f05cddf9SRui Paulo 		goto failed;
585f05cddf9SRui Paulo 	}
586f05cddf9SRui Paulo 
587f05cddf9SRui Paulo #ifdef UNICODE
588f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]);
589f05cddf9SRui Paulo #else /* UNICODE */
590f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]);
59139beb93cSSam Leffler #endif /* UNICODE */
59239beb93cSSam Leffler 
593f05cddf9SRui Paulo 	ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED,
594f05cddf9SRui Paulo 			   SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
595f05cddf9SRui Paulo 			   &scard->card, &scard->protocol);
59639beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
59739beb93cSSam Leffler 		if (ret == (long) SCARD_E_NO_SMARTCARD)
59839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "No smart card inserted.");
59939beb93cSSam Leffler 		else
60039beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
60139beb93cSSam Leffler 		goto failed;
60239beb93cSSam Leffler 	}
60339beb93cSSam Leffler 
60439beb93cSSam Leffler 	os_free(readers);
60539beb93cSSam Leffler 	readers = NULL;
60639beb93cSSam Leffler 
60739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
60839beb93cSSam Leffler 		   (unsigned int) scard->card, scard->protocol,
60939beb93cSSam Leffler 		   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 	ret = SCardBeginTransaction(scard->card);
61239beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
61339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
61439beb93cSSam Leffler 			   "0x%x", (unsigned int) ret);
61539beb93cSSam Leffler 		goto failed;
61639beb93cSSam Leffler 	}
61739beb93cSSam Leffler 	transaction = 1;
61839beb93cSSam Leffler 
61939beb93cSSam Leffler 	blen = sizeof(buf);
62039beb93cSSam Leffler 
62139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
62239beb93cSSam Leffler 	if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
62339beb93cSSam Leffler 			       SCARD_USIM, NULL, 0)) {
624*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported. Trying to use GSM SIM");
62539beb93cSSam Leffler 		scard->sim_type = SCARD_GSM_SIM;
62639beb93cSSam Leffler 	} else {
62739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
62839beb93cSSam Leffler 		scard->sim_type = SCARD_USIM;
62939beb93cSSam Leffler 	}
63039beb93cSSam Leffler 
63139beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
63239beb93cSSam Leffler 		blen = sizeof(buf);
63339beb93cSSam Leffler 		if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
63439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
63539beb93cSSam Leffler 			goto failed;
63639beb93cSSam Leffler 		}
63739beb93cSSam Leffler 
63839beb93cSSam Leffler 		blen = sizeof(buf);
63939beb93cSSam Leffler 		if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
64039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
64139beb93cSSam Leffler 			goto failed;
64239beb93cSSam Leffler 		}
64339beb93cSSam Leffler 	} else {
64439beb93cSSam Leffler 		unsigned char aid[32];
64539beb93cSSam Leffler 		int aid_len;
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 		aid_len = scard_get_aid(scard, aid, sizeof(aid));
64839beb93cSSam Leffler 		if (aid_len < 0) {
64939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
65039beb93cSSam Leffler 				   "3G USIM app - try to use standard 3G RID");
65139beb93cSSam Leffler 			os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
65239beb93cSSam Leffler 			aid_len = 5;
65339beb93cSSam Leffler 		}
65439beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
65539beb93cSSam Leffler 
65639beb93cSSam Leffler 		/* Select based on AID = 3G RID from EF_DIR. This is usually
65739beb93cSSam Leffler 		 * starting with A0 00 00 00 87. */
65839beb93cSSam Leffler 		blen = sizeof(buf);
65939beb93cSSam Leffler 		if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
66039beb93cSSam Leffler 				       aid, aid_len)) {
66139beb93cSSam Leffler 			wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
66239beb93cSSam Leffler 				   "app");
66339beb93cSSam Leffler 			wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
66439beb93cSSam Leffler 				    aid, aid_len);
66539beb93cSSam Leffler 			goto failed;
66639beb93cSSam Leffler 		}
66739beb93cSSam Leffler 	}
66839beb93cSSam Leffler 
66939beb93cSSam Leffler 	/* Verify whether CHV1 (PIN1) is needed to access the card. */
67039beb93cSSam Leffler 	pin_needed = scard_pin_needed(scard, buf, blen);
67139beb93cSSam Leffler 	if (pin_needed < 0) {
67239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
67339beb93cSSam Leffler 			   "is needed");
67439beb93cSSam Leffler 		goto failed;
67539beb93cSSam Leffler 	}
67639beb93cSSam Leffler 	if (pin_needed) {
67739beb93cSSam Leffler 		scard->pin1_required = 1;
678f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access (retry "
679f05cddf9SRui Paulo 			   "counter=%d)", scard_get_pin_retry_counter(scard));
68039beb93cSSam Leffler 	}
68139beb93cSSam Leffler 
68239beb93cSSam Leffler 	ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
68339beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
68439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
68539beb93cSSam Leffler 			   "0x%x", (unsigned int) ret);
68639beb93cSSam Leffler 	}
68739beb93cSSam Leffler 
68839beb93cSSam Leffler 	return scard;
68939beb93cSSam Leffler 
69039beb93cSSam Leffler failed:
69139beb93cSSam Leffler 	if (transaction)
69239beb93cSSam Leffler 		SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
69339beb93cSSam Leffler 	os_free(readers);
69439beb93cSSam Leffler 	scard_deinit(scard);
69539beb93cSSam Leffler 	return NULL;
69639beb93cSSam Leffler }
69739beb93cSSam Leffler 
69839beb93cSSam Leffler 
69939beb93cSSam Leffler /**
70039beb93cSSam Leffler  * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
70139beb93cSSam Leffler  * @scard: Pointer to private data from scard_init()
70239beb93cSSam Leffler  * @pin: PIN code as an ASCII string (e.g., "1234")
70339beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
70439beb93cSSam Leffler  */
70539beb93cSSam Leffler int scard_set_pin(struct scard_data *scard, const char *pin)
70639beb93cSSam Leffler {
70739beb93cSSam Leffler 	if (scard == NULL)
70839beb93cSSam Leffler 		return -1;
70939beb93cSSam Leffler 
71039beb93cSSam Leffler 	/* Verify whether CHV1 (PIN1) is needed to access the card. */
71139beb93cSSam Leffler 	if (scard->pin1_required) {
71239beb93cSSam Leffler 		if (pin == NULL) {
71339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
71439beb93cSSam Leffler 				   "access");
71539beb93cSSam Leffler 			return -1;
71639beb93cSSam Leffler 		}
71739beb93cSSam Leffler 		if (scard_verify_pin(scard, pin)) {
71839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "PIN verification failed for "
71939beb93cSSam Leffler 				"SIM access");
72039beb93cSSam Leffler 			return -1;
72139beb93cSSam Leffler 		}
72239beb93cSSam Leffler 	}
72339beb93cSSam Leffler 
72439beb93cSSam Leffler 	return 0;
72539beb93cSSam Leffler }
72639beb93cSSam Leffler 
72739beb93cSSam Leffler 
72839beb93cSSam Leffler /**
72939beb93cSSam Leffler  * scard_deinit - Deinitialize SIM/USIM connection
73039beb93cSSam Leffler  * @scard: Pointer to private data from scard_init()
73139beb93cSSam Leffler  *
73239beb93cSSam Leffler  * This function closes the SIM/USIM connect opened with scard_init().
73339beb93cSSam Leffler  */
73439beb93cSSam Leffler void scard_deinit(struct scard_data *scard)
73539beb93cSSam Leffler {
73639beb93cSSam Leffler 	long ret;
73739beb93cSSam Leffler 
73839beb93cSSam Leffler 	if (scard == NULL)
73939beb93cSSam Leffler 		return;
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
74239beb93cSSam Leffler 	if (scard->card) {
74339beb93cSSam Leffler 		ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
74439beb93cSSam Leffler 		if (ret != SCARD_S_SUCCESS) {
74539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
74639beb93cSSam Leffler 				   "smart card (err=%ld)", ret);
74739beb93cSSam Leffler 		}
74839beb93cSSam Leffler 	}
74939beb93cSSam Leffler 
75039beb93cSSam Leffler 	if (scard->ctx) {
75139beb93cSSam Leffler 		ret = SCardReleaseContext(scard->ctx);
75239beb93cSSam Leffler 		if (ret != SCARD_S_SUCCESS) {
75339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to release smart card "
75439beb93cSSam Leffler 				   "context (err=%ld)", ret);
75539beb93cSSam Leffler 		}
75639beb93cSSam Leffler 	}
75739beb93cSSam Leffler 	os_free(scard);
75839beb93cSSam Leffler 	mingw_unload_symbols();
75939beb93cSSam Leffler }
76039beb93cSSam Leffler 
76139beb93cSSam Leffler 
76239beb93cSSam Leffler static long scard_transmit(struct scard_data *scard,
76339beb93cSSam Leffler 			   unsigned char *_send, size_t send_len,
76439beb93cSSam Leffler 			   unsigned char *_recv, size_t *recv_len)
76539beb93cSSam Leffler {
76639beb93cSSam Leffler 	long ret;
76739beb93cSSam Leffler 	unsigned long rlen;
76839beb93cSSam Leffler 
76939beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
77039beb93cSSam Leffler 			_send, send_len);
77139beb93cSSam Leffler 	rlen = *recv_len;
77239beb93cSSam Leffler 	ret = SCardTransmit(scard->card,
77339beb93cSSam Leffler 			    scard->protocol == SCARD_PROTOCOL_T1 ?
77439beb93cSSam Leffler 			    SCARD_PCI_T1 : SCARD_PCI_T0,
77539beb93cSSam Leffler 			    _send, (unsigned long) send_len,
77639beb93cSSam Leffler 			    NULL, _recv, &rlen);
77739beb93cSSam Leffler 	*recv_len = rlen;
77839beb93cSSam Leffler 	if (ret == SCARD_S_SUCCESS) {
77939beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
78039beb93cSSam Leffler 			    _recv, rlen);
78139beb93cSSam Leffler 	} else {
78239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
78339beb93cSSam Leffler 			   "(err=0x%lx)", ret);
78439beb93cSSam Leffler 	}
78539beb93cSSam Leffler 	return ret;
78639beb93cSSam Leffler }
78739beb93cSSam Leffler 
78839beb93cSSam Leffler 
78939beb93cSSam Leffler static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
79039beb93cSSam Leffler 			      unsigned char *buf, size_t *buf_len,
79139beb93cSSam Leffler 			      sim_types sim_type, unsigned char *aid,
79239beb93cSSam Leffler 			      size_t aidlen)
79339beb93cSSam Leffler {
79439beb93cSSam Leffler 	long ret;
79539beb93cSSam Leffler 	unsigned char resp[3];
79639beb93cSSam Leffler 	unsigned char cmd[50] = { SIM_CMD_SELECT };
79739beb93cSSam Leffler 	int cmdlen;
79839beb93cSSam Leffler 	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
79939beb93cSSam Leffler 	size_t len, rlen;
80039beb93cSSam Leffler 
80139beb93cSSam Leffler 	if (sim_type == SCARD_USIM) {
80239beb93cSSam Leffler 		cmd[0] = USIM_CLA;
80339beb93cSSam Leffler 		cmd[3] = 0x04;
80439beb93cSSam Leffler 		get_resp[0] = USIM_CLA;
80539beb93cSSam Leffler 	}
80639beb93cSSam Leffler 
80739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
80839beb93cSSam Leffler 	if (aid) {
80939beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
81039beb93cSSam Leffler 			    aid, aidlen);
81139beb93cSSam Leffler 		if (5 + aidlen > sizeof(cmd))
81239beb93cSSam Leffler 			return -1;
81339beb93cSSam Leffler 		cmd[2] = 0x04; /* Select by AID */
81439beb93cSSam Leffler 		cmd[4] = aidlen; /* len */
81539beb93cSSam Leffler 		os_memcpy(cmd + 5, aid, aidlen);
81639beb93cSSam Leffler 		cmdlen = 5 + aidlen;
81739beb93cSSam Leffler 	} else {
81839beb93cSSam Leffler 		cmd[5] = file_id >> 8;
81939beb93cSSam Leffler 		cmd[6] = file_id & 0xff;
82039beb93cSSam Leffler 		cmdlen = 7;
82139beb93cSSam Leffler 	}
82239beb93cSSam Leffler 	len = sizeof(resp);
82339beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
82439beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
82539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
82639beb93cSSam Leffler 			   "(err=0x%lx)", ret);
82739beb93cSSam Leffler 		return -1;
82839beb93cSSam Leffler 	}
82939beb93cSSam Leffler 
83039beb93cSSam Leffler 	if (len != 2) {
83139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
83239beb93cSSam Leffler 			   "%d (expected 2)", (int) len);
83339beb93cSSam Leffler 		return -1;
83439beb93cSSam Leffler 	}
83539beb93cSSam Leffler 
83639beb93cSSam Leffler 	if (resp[0] == 0x98 && resp[1] == 0x04) {
83739beb93cSSam Leffler 		/* Security status not satisfied (PIN_WLAN) */
83839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
83939beb93cSSam Leffler 			   "(PIN_WLAN)");
84039beb93cSSam Leffler 		return -1;
84139beb93cSSam Leffler 	}
84239beb93cSSam Leffler 
84339beb93cSSam Leffler 	if (resp[0] == 0x6e) {
84439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
84539beb93cSSam Leffler 		return -1;
84639beb93cSSam Leffler 	}
84739beb93cSSam Leffler 
84839beb93cSSam Leffler 	if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
84939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
85039beb93cSSam Leffler 			   "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
85139beb93cSSam Leffler 		return -1;
85239beb93cSSam Leffler 	}
85339beb93cSSam Leffler 	/* Normal ending of command; resp[1] bytes available */
85439beb93cSSam Leffler 	get_resp[4] = resp[1];
85539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
85639beb93cSSam Leffler 		   resp[1]);
85739beb93cSSam Leffler 
85839beb93cSSam Leffler 	rlen = *buf_len;
85939beb93cSSam Leffler 	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
86039beb93cSSam Leffler 	if (ret == SCARD_S_SUCCESS) {
86139beb93cSSam Leffler 		*buf_len = resp[1] < rlen ? resp[1] : rlen;
86239beb93cSSam Leffler 		return 0;
86339beb93cSSam Leffler 	}
86439beb93cSSam Leffler 
86539beb93cSSam Leffler 	wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
86639beb93cSSam Leffler 	return -1;
86739beb93cSSam Leffler }
86839beb93cSSam Leffler 
86939beb93cSSam Leffler 
87039beb93cSSam Leffler static int scard_select_file(struct scard_data *scard, unsigned short file_id,
87139beb93cSSam Leffler 			     unsigned char *buf, size_t *buf_len)
87239beb93cSSam Leffler {
87339beb93cSSam Leffler 	return _scard_select_file(scard, file_id, buf, buf_len,
87439beb93cSSam Leffler 				  scard->sim_type, NULL, 0);
87539beb93cSSam Leffler }
87639beb93cSSam Leffler 
87739beb93cSSam Leffler 
87839beb93cSSam Leffler static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
87939beb93cSSam Leffler 				unsigned char mode)
88039beb93cSSam Leffler {
88139beb93cSSam Leffler 	unsigned char buf[255];
88239beb93cSSam Leffler 	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
88339beb93cSSam Leffler 	size_t blen;
88439beb93cSSam Leffler 	long ret;
88539beb93cSSam Leffler 
88639beb93cSSam Leffler 	if (scard->sim_type == SCARD_USIM)
88739beb93cSSam Leffler 		cmd[0] = USIM_CLA;
88839beb93cSSam Leffler 	cmd[2] = recnum;
88939beb93cSSam Leffler 	cmd[3] = mode;
89039beb93cSSam Leffler 	cmd[4] = sizeof(buf);
89139beb93cSSam Leffler 
89239beb93cSSam Leffler 	blen = sizeof(buf);
89339beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
89439beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
89539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
89639beb93cSSam Leffler 			   "length for record %d", recnum);
89739beb93cSSam Leffler 		return -1;
89839beb93cSSam Leffler 	}
89939beb93cSSam Leffler 
90039beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
90139beb93cSSam Leffler 		    buf, blen);
90239beb93cSSam Leffler 
903f05cddf9SRui Paulo 	if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
90439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
90539beb93cSSam Leffler 			   "length determination");
90639beb93cSSam Leffler 		return -1;
90739beb93cSSam Leffler 	}
90839beb93cSSam Leffler 
90939beb93cSSam Leffler 	return buf[1];
91039beb93cSSam Leffler }
91139beb93cSSam Leffler 
91239beb93cSSam Leffler 
91339beb93cSSam Leffler static int scard_read_record(struct scard_data *scard,
91439beb93cSSam Leffler 			     unsigned char *data, size_t len,
91539beb93cSSam Leffler 			     unsigned char recnum, unsigned char mode)
91639beb93cSSam Leffler {
91739beb93cSSam Leffler 	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
91839beb93cSSam Leffler 	size_t blen = len + 3;
91939beb93cSSam Leffler 	unsigned char *buf;
92039beb93cSSam Leffler 	long ret;
92139beb93cSSam Leffler 
92239beb93cSSam Leffler 	if (scard->sim_type == SCARD_USIM)
92339beb93cSSam Leffler 		cmd[0] = USIM_CLA;
92439beb93cSSam Leffler 	cmd[2] = recnum;
92539beb93cSSam Leffler 	cmd[3] = mode;
92639beb93cSSam Leffler 	cmd[4] = len;
92739beb93cSSam Leffler 
92839beb93cSSam Leffler 	buf = os_malloc(blen);
92939beb93cSSam Leffler 	if (buf == NULL)
93039beb93cSSam Leffler 		return -1;
93139beb93cSSam Leffler 
93239beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
93339beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
93439beb93cSSam Leffler 		os_free(buf);
93539beb93cSSam Leffler 		return -2;
93639beb93cSSam Leffler 	}
93739beb93cSSam Leffler 	if (blen != len + 2) {
93839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
93939beb93cSSam Leffler 			   "length %ld (expected %ld)",
94039beb93cSSam Leffler 			   (long) blen, (long) len + 2);
94139beb93cSSam Leffler 		os_free(buf);
94239beb93cSSam Leffler 		return -3;
94339beb93cSSam Leffler 	}
94439beb93cSSam Leffler 
94539beb93cSSam Leffler 	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
94639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
94739beb93cSSam Leffler 			   "status %02x %02x (expected 90 00)",
94839beb93cSSam Leffler 			   buf[len], buf[len + 1]);
94939beb93cSSam Leffler 		os_free(buf);
95039beb93cSSam Leffler 		return -4;
95139beb93cSSam Leffler 	}
95239beb93cSSam Leffler 
95339beb93cSSam Leffler 	os_memcpy(data, buf, len);
95439beb93cSSam Leffler 	os_free(buf);
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	return 0;
95739beb93cSSam Leffler }
95839beb93cSSam Leffler 
95939beb93cSSam Leffler 
96039beb93cSSam Leffler static int scard_read_file(struct scard_data *scard,
96139beb93cSSam Leffler 			   unsigned char *data, size_t len)
96239beb93cSSam Leffler {
96339beb93cSSam Leffler 	unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
96439beb93cSSam Leffler 	size_t blen = len + 3;
96539beb93cSSam Leffler 	unsigned char *buf;
96639beb93cSSam Leffler 	long ret;
96739beb93cSSam Leffler 
96839beb93cSSam Leffler 	cmd[4] = len;
96939beb93cSSam Leffler 
97039beb93cSSam Leffler 	buf = os_malloc(blen);
97139beb93cSSam Leffler 	if (buf == NULL)
97239beb93cSSam Leffler 		return -1;
97339beb93cSSam Leffler 
97439beb93cSSam Leffler 	if (scard->sim_type == SCARD_USIM)
97539beb93cSSam Leffler 		cmd[0] = USIM_CLA;
97639beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
97739beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS) {
97839beb93cSSam Leffler 		os_free(buf);
97939beb93cSSam Leffler 		return -2;
98039beb93cSSam Leffler 	}
98139beb93cSSam Leffler 	if (blen != len + 2) {
98239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
98339beb93cSSam Leffler 			   "length %ld (expected %ld)",
98439beb93cSSam Leffler 			   (long) blen, (long) len + 2);
98539beb93cSSam Leffler 		os_free(buf);
98639beb93cSSam Leffler 		return -3;
98739beb93cSSam Leffler 	}
98839beb93cSSam Leffler 
98939beb93cSSam Leffler 	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
99039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
99139beb93cSSam Leffler 			   "status %02x %02x (expected 90 00)",
99239beb93cSSam Leffler 			   buf[len], buf[len + 1]);
99339beb93cSSam Leffler 		os_free(buf);
99439beb93cSSam Leffler 		return -4;
99539beb93cSSam Leffler 	}
99639beb93cSSam Leffler 
99739beb93cSSam Leffler 	os_memcpy(data, buf, len);
99839beb93cSSam Leffler 	os_free(buf);
99939beb93cSSam Leffler 
100039beb93cSSam Leffler 	return 0;
100139beb93cSSam Leffler }
100239beb93cSSam Leffler 
100339beb93cSSam Leffler 
100439beb93cSSam Leffler static int scard_verify_pin(struct scard_data *scard, const char *pin)
100539beb93cSSam Leffler {
100639beb93cSSam Leffler 	long ret;
100739beb93cSSam Leffler 	unsigned char resp[3];
100839beb93cSSam Leffler 	unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
100939beb93cSSam Leffler 	size_t len;
101039beb93cSSam Leffler 
101139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
101239beb93cSSam Leffler 
101339beb93cSSam Leffler 	if (pin == NULL || os_strlen(pin) > 8)
101439beb93cSSam Leffler 		return -1;
101539beb93cSSam Leffler 
101639beb93cSSam Leffler 	if (scard->sim_type == SCARD_USIM)
101739beb93cSSam Leffler 		cmd[0] = USIM_CLA;
101839beb93cSSam Leffler 	os_memcpy(cmd + 5, pin, os_strlen(pin));
101939beb93cSSam Leffler 	os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
102039beb93cSSam Leffler 
102139beb93cSSam Leffler 	len = sizeof(resp);
102239beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
102339beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS)
102439beb93cSSam Leffler 		return -2;
102539beb93cSSam Leffler 
102639beb93cSSam Leffler 	if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
102739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
102839beb93cSSam Leffler 		return -1;
102939beb93cSSam Leffler 	}
103039beb93cSSam Leffler 
103139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
103239beb93cSSam Leffler 	return 0;
103339beb93cSSam Leffler }
103439beb93cSSam Leffler 
103539beb93cSSam Leffler 
1036f05cddf9SRui Paulo int scard_get_pin_retry_counter(struct scard_data *scard)
1037f05cddf9SRui Paulo {
1038f05cddf9SRui Paulo 	long ret;
1039f05cddf9SRui Paulo 	unsigned char resp[3];
1040f05cddf9SRui Paulo 	unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 };
1041f05cddf9SRui Paulo 	size_t len;
1042f05cddf9SRui Paulo 	u16 val;
1043f05cddf9SRui Paulo 
1044f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: fetching PIN retry counter");
1045f05cddf9SRui Paulo 
1046f05cddf9SRui Paulo 	if (scard->sim_type == SCARD_USIM)
1047f05cddf9SRui Paulo 		cmd[0] = USIM_CLA;
1048f05cddf9SRui Paulo 	cmd[4] = 0; /* Empty data */
1049f05cddf9SRui Paulo 
1050f05cddf9SRui Paulo 	len = sizeof(resp);
1051f05cddf9SRui Paulo 	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
1052f05cddf9SRui Paulo 	if (ret != SCARD_S_SUCCESS)
1053f05cddf9SRui Paulo 		return -2;
1054f05cddf9SRui Paulo 
1055f05cddf9SRui Paulo 	if (len != 2) {
1056f05cddf9SRui Paulo 		wpa_printf(MSG_WARNING, "SCARD: failed to fetch PIN retry "
1057f05cddf9SRui Paulo 			   "counter");
1058f05cddf9SRui Paulo 		return -1;
1059f05cddf9SRui Paulo 	}
1060f05cddf9SRui Paulo 
1061f05cddf9SRui Paulo 	val = WPA_GET_BE16(resp);
1062f05cddf9SRui Paulo 	if (val == 0x63c0 || val == 0x6983) {
1063f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "SCARD: PIN has been blocked");
1064f05cddf9SRui Paulo 		return 0;
1065f05cddf9SRui Paulo 	}
1066f05cddf9SRui Paulo 
1067f05cddf9SRui Paulo 	if (val >= 0x63c0 && val <= 0x63cf)
1068f05cddf9SRui Paulo 		return val & 0x000f;
1069f05cddf9SRui Paulo 
1070f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: Unexpected PIN retry counter response "
1071f05cddf9SRui Paulo 		   "value 0x%x", val);
1072f05cddf9SRui Paulo 	return 0;
1073f05cddf9SRui Paulo }
1074f05cddf9SRui Paulo 
1075f05cddf9SRui Paulo 
107639beb93cSSam Leffler /**
107739beb93cSSam Leffler  * scard_get_imsi - Read IMSI from SIM/USIM card
107839beb93cSSam Leffler  * @scard: Pointer to private data from scard_init()
107939beb93cSSam Leffler  * @imsi: Buffer for IMSI
108039beb93cSSam Leffler  * @len: Length of imsi buffer; set to IMSI length on success
108139beb93cSSam Leffler  * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
108239beb93cSSam Leffler  * selection returns invalid result code, -3 if parsing FSP template file fails
108339beb93cSSam Leffler  * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
108439beb93cSSam Leffler  * to needed length), -5 if reading IMSI file fails.
108539beb93cSSam Leffler  *
108639beb93cSSam Leffler  * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
108739beb93cSSam Leffler  * file is PIN protected, scard_set_pin() must have been used to set the
108839beb93cSSam Leffler  * correct PIN code before calling scard_get_imsi().
108939beb93cSSam Leffler  */
109039beb93cSSam Leffler int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
109139beb93cSSam Leffler {
109239beb93cSSam Leffler 	unsigned char buf[100];
109339beb93cSSam Leffler 	size_t blen, imsilen, i;
109439beb93cSSam Leffler 	char *pos;
109539beb93cSSam Leffler 
109639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
109739beb93cSSam Leffler 	blen = sizeof(buf);
109839beb93cSSam Leffler 	if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
109939beb93cSSam Leffler 		return -1;
110039beb93cSSam Leffler 	if (blen < 4) {
110139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
110239beb93cSSam Leffler 			   "header (len=%ld)", (long) blen);
110339beb93cSSam Leffler 		return -2;
110439beb93cSSam Leffler 	}
110539beb93cSSam Leffler 
110639beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
1107*5b9c547cSRui Paulo 		blen = WPA_GET_BE16(&buf[2]);
110839beb93cSSam Leffler 	} else {
110939beb93cSSam Leffler 		int file_size;
111039beb93cSSam Leffler 		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
111139beb93cSSam Leffler 			return -3;
111239beb93cSSam Leffler 		blen = file_size;
111339beb93cSSam Leffler 	}
111439beb93cSSam Leffler 	if (blen < 2 || blen > sizeof(buf)) {
111539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
111639beb93cSSam Leffler 			   (long) blen);
111739beb93cSSam Leffler 		return -3;
111839beb93cSSam Leffler 	}
111939beb93cSSam Leffler 
112039beb93cSSam Leffler 	imsilen = (blen - 2) * 2 + 1;
112139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
112239beb93cSSam Leffler 		   (long) blen, (long) imsilen);
112339beb93cSSam Leffler 	if (blen < 2 || imsilen > *len) {
112439beb93cSSam Leffler 		*len = imsilen;
112539beb93cSSam Leffler 		return -4;
112639beb93cSSam Leffler 	}
112739beb93cSSam Leffler 
112839beb93cSSam Leffler 	if (scard_read_file(scard, buf, blen))
112939beb93cSSam Leffler 		return -5;
113039beb93cSSam Leffler 
113139beb93cSSam Leffler 	pos = imsi;
113239beb93cSSam Leffler 	*pos++ = '0' + (buf[1] >> 4 & 0x0f);
113339beb93cSSam Leffler 	for (i = 2; i < blen; i++) {
113439beb93cSSam Leffler 		unsigned char digit;
113539beb93cSSam Leffler 
113639beb93cSSam Leffler 		digit = buf[i] & 0x0f;
113739beb93cSSam Leffler 		if (digit < 10)
113839beb93cSSam Leffler 			*pos++ = '0' + digit;
113939beb93cSSam Leffler 		else
114039beb93cSSam Leffler 			imsilen--;
114139beb93cSSam Leffler 
114239beb93cSSam Leffler 		digit = buf[i] >> 4 & 0x0f;
114339beb93cSSam Leffler 		if (digit < 10)
114439beb93cSSam Leffler 			*pos++ = '0' + digit;
114539beb93cSSam Leffler 		else
114639beb93cSSam Leffler 			imsilen--;
114739beb93cSSam Leffler 	}
114839beb93cSSam Leffler 	*len = imsilen;
114939beb93cSSam Leffler 
115039beb93cSSam Leffler 	return 0;
115139beb93cSSam Leffler }
115239beb93cSSam Leffler 
115339beb93cSSam Leffler 
115439beb93cSSam Leffler /**
1155f05cddf9SRui Paulo  * scard_get_mnc_len - Read length of MNC in the IMSI from SIM/USIM card
1156f05cddf9SRui Paulo  * @scard: Pointer to private data from scard_init()
1157f05cddf9SRui Paulo  * Returns: length (>0) on success, -1 if administrative data file cannot be
1158f05cddf9SRui Paulo  * selected, -2 if administrative data file selection returns invalid result
1159f05cddf9SRui Paulo  * code, -3 if parsing FSP template file fails (USIM only), -4 if length of
1160f05cddf9SRui Paulo  * the file is unexpected, -5 if reading file fails, -6 if MNC length is not
1161f05cddf9SRui Paulo  * in range (i.e. 2 or 3), -7 if MNC length is not available.
1162f05cddf9SRui Paulo  *
1163f05cddf9SRui Paulo  */
1164f05cddf9SRui Paulo int scard_get_mnc_len(struct scard_data *scard)
1165f05cddf9SRui Paulo {
1166f05cddf9SRui Paulo 	unsigned char buf[100];
1167f05cddf9SRui Paulo 	size_t blen;
1168f05cddf9SRui Paulo 	int file_size;
1169f05cddf9SRui Paulo 
1170f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: reading MNC len from (GSM) EF-AD");
1171f05cddf9SRui Paulo 	blen = sizeof(buf);
1172f05cddf9SRui Paulo 	if (scard_select_file(scard, SCARD_FILE_GSM_EF_AD, buf, &blen))
1173f05cddf9SRui Paulo 		return -1;
1174f05cddf9SRui Paulo 	if (blen < 4) {
1175f05cddf9SRui Paulo 		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-AD "
1176f05cddf9SRui Paulo 			   "header (len=%ld)", (long) blen);
1177f05cddf9SRui Paulo 		return -2;
1178f05cddf9SRui Paulo 	}
1179f05cddf9SRui Paulo 
1180f05cddf9SRui Paulo 	if (scard->sim_type == SCARD_GSM_SIM) {
1181*5b9c547cSRui Paulo 		file_size = WPA_GET_BE16(&buf[2]);
1182f05cddf9SRui Paulo 	} else {
1183f05cddf9SRui Paulo 		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
1184f05cddf9SRui Paulo 			return -3;
1185f05cddf9SRui Paulo 	}
1186f05cddf9SRui Paulo 	if (file_size == 3) {
1187f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "SCARD: MNC length not available");
1188f05cddf9SRui Paulo 		return -7;
1189f05cddf9SRui Paulo 	}
1190f05cddf9SRui Paulo 	if (file_size < 4 || file_size > (int) sizeof(buf)) {
1191f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "SCARD: invalid file length=%ld",
1192f05cddf9SRui Paulo 			   (long) file_size);
1193f05cddf9SRui Paulo 		return -4;
1194f05cddf9SRui Paulo 	}
1195f05cddf9SRui Paulo 
1196f05cddf9SRui Paulo 	if (scard_read_file(scard, buf, file_size))
1197f05cddf9SRui Paulo 		return -5;
1198f05cddf9SRui Paulo 	buf[3] = buf[3] & 0x0f; /* upper nibble reserved for future use  */
1199f05cddf9SRui Paulo 	if (buf[3] < 2 || buf[3] > 3) {
1200f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "SCARD: invalid MNC length=%ld",
1201f05cddf9SRui Paulo 			   (long) buf[3]);
1202f05cddf9SRui Paulo 		return -6;
1203f05cddf9SRui Paulo 	}
1204f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "SCARD: MNC length=%ld", (long) buf[3]);
1205f05cddf9SRui Paulo 	return buf[3];
1206f05cddf9SRui Paulo }
1207f05cddf9SRui Paulo 
1208f05cddf9SRui Paulo 
1209f05cddf9SRui Paulo /**
121039beb93cSSam Leffler  * scard_gsm_auth - Run GSM authentication command on SIM card
121139beb93cSSam Leffler  * @scard: Pointer to private data from scard_init()
121239beb93cSSam Leffler  * @_rand: 16-byte RAND value from HLR/AuC
121339beb93cSSam Leffler  * @sres: 4-byte buffer for SRES
121439beb93cSSam Leffler  * @kc: 8-byte buffer for Kc
121539beb93cSSam Leffler  * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
121639beb93cSSam Leffler  * -2 if authentication command execution fails, -3 if unknown response code
121739beb93cSSam Leffler  * for authentication command is received, -4 if reading of response fails,
121839beb93cSSam Leffler  * -5 if if response data is of unexpected length
121939beb93cSSam Leffler  *
122039beb93cSSam Leffler  * This function performs GSM authentication using SIM/USIM card and the
122139beb93cSSam Leffler  * provided RAND value from HLR/AuC. If authentication command can be completed
122239beb93cSSam Leffler  * successfully, SRES and Kc values will be written into sres and kc buffers.
122339beb93cSSam Leffler  */
122439beb93cSSam Leffler int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
122539beb93cSSam Leffler 		   unsigned char *sres, unsigned char *kc)
122639beb93cSSam Leffler {
122739beb93cSSam Leffler 	unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
122839beb93cSSam Leffler 	int cmdlen;
122939beb93cSSam Leffler 	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
123039beb93cSSam Leffler 	unsigned char resp[3], buf[12 + 3 + 2];
123139beb93cSSam Leffler 	size_t len;
123239beb93cSSam Leffler 	long ret;
123339beb93cSSam Leffler 
123439beb93cSSam Leffler 	if (scard == NULL)
123539beb93cSSam Leffler 		return -1;
123639beb93cSSam Leffler 
123739beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
123839beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
123939beb93cSSam Leffler 		cmdlen = 5 + 16;
124039beb93cSSam Leffler 		os_memcpy(cmd + 5, _rand, 16);
124139beb93cSSam Leffler 	} else {
124239beb93cSSam Leffler 		cmdlen = 5 + 1 + 16;
124339beb93cSSam Leffler 		cmd[0] = USIM_CLA;
124439beb93cSSam Leffler 		cmd[3] = 0x80;
124539beb93cSSam Leffler 		cmd[4] = 17;
124639beb93cSSam Leffler 		cmd[5] = 16;
124739beb93cSSam Leffler 		os_memcpy(cmd + 6, _rand, 16);
1248*5b9c547cSRui Paulo 		get_resp[0] = USIM_CLA;
124939beb93cSSam Leffler 	}
125039beb93cSSam Leffler 	len = sizeof(resp);
125139beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
125239beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS)
125339beb93cSSam Leffler 		return -2;
125439beb93cSSam Leffler 
125539beb93cSSam Leffler 	if ((scard->sim_type == SCARD_GSM_SIM &&
125639beb93cSSam Leffler 	     (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
125739beb93cSSam Leffler 	    (scard->sim_type == SCARD_USIM &&
125839beb93cSSam Leffler 	     (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
125939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
126039beb93cSSam Leffler 			   "auth request (len=%ld resp=%02x %02x)",
126139beb93cSSam Leffler 			   (long) len, resp[0], resp[1]);
126239beb93cSSam Leffler 		return -3;
126339beb93cSSam Leffler 	}
126439beb93cSSam Leffler 	get_resp[4] = resp[1];
126539beb93cSSam Leffler 
126639beb93cSSam Leffler 	len = sizeof(buf);
126739beb93cSSam Leffler 	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
126839beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS)
126939beb93cSSam Leffler 		return -4;
127039beb93cSSam Leffler 
127139beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
127239beb93cSSam Leffler 		if (len != 4 + 8 + 2) {
127339beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
127439beb93cSSam Leffler 				   "length for GSM auth (len=%ld, expected 14)",
127539beb93cSSam Leffler 				   (long) len);
127639beb93cSSam Leffler 			return -5;
127739beb93cSSam Leffler 		}
127839beb93cSSam Leffler 		os_memcpy(sres, buf, 4);
127939beb93cSSam Leffler 		os_memcpy(kc, buf + 4, 8);
128039beb93cSSam Leffler 	} else {
128139beb93cSSam Leffler 		if (len != 1 + 4 + 1 + 8 + 2) {
128239beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
128339beb93cSSam Leffler 				   "length for USIM auth (len=%ld, "
128439beb93cSSam Leffler 				   "expected 16)", (long) len);
128539beb93cSSam Leffler 			return -5;
128639beb93cSSam Leffler 		}
128739beb93cSSam Leffler 		if (buf[0] != 4 || buf[5] != 8) {
128839beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
128939beb93cSSam Leffler 				   "length (%d %d, expected 4 8)",
129039beb93cSSam Leffler 				   buf[0], buf[5]);
129139beb93cSSam Leffler 		}
129239beb93cSSam Leffler 		os_memcpy(sres, buf + 1, 4);
129339beb93cSSam Leffler 		os_memcpy(kc, buf + 6, 8);
129439beb93cSSam Leffler 	}
129539beb93cSSam Leffler 
129639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
129739beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
129839beb93cSSam Leffler 
129939beb93cSSam Leffler 	return 0;
130039beb93cSSam Leffler }
130139beb93cSSam Leffler 
130239beb93cSSam Leffler 
130339beb93cSSam Leffler /**
130439beb93cSSam Leffler  * scard_umts_auth - Run UMTS authentication command on USIM card
130539beb93cSSam Leffler  * @scard: Pointer to private data from scard_init()
130639beb93cSSam Leffler  * @_rand: 16-byte RAND value from HLR/AuC
130739beb93cSSam Leffler  * @autn: 16-byte AUTN value from HLR/AuC
130839beb93cSSam Leffler  * @res: 16-byte buffer for RES
130939beb93cSSam Leffler  * @res_len: Variable that will be set to RES length
131039beb93cSSam Leffler  * @ik: 16-byte buffer for IK
131139beb93cSSam Leffler  * @ck: 16-byte buffer for CK
131239beb93cSSam Leffler  * @auts: 14-byte buffer for AUTS
131339beb93cSSam Leffler  * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
131439beb93cSSam Leffler  * failure
131539beb93cSSam Leffler  *
131639beb93cSSam Leffler  * This function performs AKA authentication using USIM card and the provided
131739beb93cSSam Leffler  * RAND and AUTN values from HLR/AuC. If authentication command can be
131839beb93cSSam Leffler  * completed successfully, RES, IK, and CK values will be written into provided
131939beb93cSSam Leffler  * buffers and res_len is set to length of received RES value. If USIM reports
132039beb93cSSam Leffler  * synchronization failure, the received AUTS value will be written into auts
132139beb93cSSam Leffler  * buffer. In this case, RES, IK, and CK are not valid.
132239beb93cSSam Leffler  */
132339beb93cSSam Leffler int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
132439beb93cSSam Leffler 		    const unsigned char *autn,
132539beb93cSSam Leffler 		    unsigned char *res, size_t *res_len,
132639beb93cSSam Leffler 		    unsigned char *ik, unsigned char *ck, unsigned char *auts)
132739beb93cSSam Leffler {
132839beb93cSSam Leffler 	unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
132939beb93cSSam Leffler 		{ USIM_CMD_RUN_UMTS_ALG };
133039beb93cSSam Leffler 	unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
133139beb93cSSam Leffler 	unsigned char resp[3], buf[64], *pos, *end;
133239beb93cSSam Leffler 	size_t len;
133339beb93cSSam Leffler 	long ret;
133439beb93cSSam Leffler 
133539beb93cSSam Leffler 	if (scard == NULL)
133639beb93cSSam Leffler 		return -1;
133739beb93cSSam Leffler 
133839beb93cSSam Leffler 	if (scard->sim_type == SCARD_GSM_SIM) {
133939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
134039beb93cSSam Leffler 			   "auth");
134139beb93cSSam Leffler 		return -1;
134239beb93cSSam Leffler 	}
134339beb93cSSam Leffler 
134439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
134539beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
134639beb93cSSam Leffler 	cmd[5] = AKA_RAND_LEN;
134739beb93cSSam Leffler 	os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
134839beb93cSSam Leffler 	cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
134939beb93cSSam Leffler 	os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
135039beb93cSSam Leffler 
135139beb93cSSam Leffler 	len = sizeof(resp);
135239beb93cSSam Leffler 	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
135339beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS)
135439beb93cSSam Leffler 		return -1;
135539beb93cSSam Leffler 
135639beb93cSSam Leffler 	if (len <= sizeof(resp))
135739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
135839beb93cSSam Leffler 
135939beb93cSSam Leffler 	if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
136039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
136139beb93cSSam Leffler 			   "MAC != XMAC");
136239beb93cSSam Leffler 		return -1;
136339beb93cSSam Leffler 	} else if (len != 2 || resp[0] != 0x61) {
136439beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
136539beb93cSSam Leffler 			   "auth request (len=%ld resp=%02x %02x)",
136639beb93cSSam Leffler 			   (long) len, resp[0], resp[1]);
136739beb93cSSam Leffler 		return -1;
136839beb93cSSam Leffler 	}
136939beb93cSSam Leffler 	get_resp[4] = resp[1];
137039beb93cSSam Leffler 
137139beb93cSSam Leffler 	len = sizeof(buf);
137239beb93cSSam Leffler 	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
137339beb93cSSam Leffler 	if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
137439beb93cSSam Leffler 		return -1;
137539beb93cSSam Leffler 
137639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
137739beb93cSSam Leffler 	if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
137839beb93cSSam Leffler 	    buf[1] == AKA_AUTS_LEN) {
137939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
138039beb93cSSam Leffler 		os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
138139beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
138239beb93cSSam Leffler 		return -2;
138339beb93cSSam Leffler 	} else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
138439beb93cSSam Leffler 		pos = buf + 1;
138539beb93cSSam Leffler 		end = buf + len;
138639beb93cSSam Leffler 
138739beb93cSSam Leffler 		/* RES */
138839beb93cSSam Leffler 		if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
138939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
139039beb93cSSam Leffler 			return -1;
139139beb93cSSam Leffler 		}
139239beb93cSSam Leffler 		*res_len = *pos++;
139339beb93cSSam Leffler 		os_memcpy(res, pos, *res_len);
139439beb93cSSam Leffler 		pos += *res_len;
139539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
139639beb93cSSam Leffler 
139739beb93cSSam Leffler 		/* CK */
139839beb93cSSam Leffler 		if (pos[0] != CK_LEN || pos + CK_LEN > end) {
139939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
140039beb93cSSam Leffler 			return -1;
140139beb93cSSam Leffler 		}
140239beb93cSSam Leffler 		pos++;
140339beb93cSSam Leffler 		os_memcpy(ck, pos, CK_LEN);
140439beb93cSSam Leffler 		pos += CK_LEN;
140539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
140639beb93cSSam Leffler 
140739beb93cSSam Leffler 		/* IK */
140839beb93cSSam Leffler 		if (pos[0] != IK_LEN || pos + IK_LEN > end) {
140939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
141039beb93cSSam Leffler 			return -1;
141139beb93cSSam Leffler 		}
141239beb93cSSam Leffler 		pos++;
141339beb93cSSam Leffler 		os_memcpy(ik, pos, IK_LEN);
141439beb93cSSam Leffler 		pos += IK_LEN;
141539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
141639beb93cSSam Leffler 
1417*5b9c547cSRui Paulo 		if (end > pos) {
1418*5b9c547cSRui Paulo 			wpa_hexdump(MSG_DEBUG,
1419*5b9c547cSRui Paulo 				    "SCARD: Ignore extra data in end",
1420*5b9c547cSRui Paulo 				    pos, end - pos);
1421*5b9c547cSRui Paulo 		}
1422*5b9c547cSRui Paulo 
142339beb93cSSam Leffler 		return 0;
142439beb93cSSam Leffler 	}
142539beb93cSSam Leffler 
142639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
142739beb93cSSam Leffler 	return -1;
142839beb93cSSam Leffler }
1429f05cddf9SRui Paulo 
1430f05cddf9SRui Paulo 
1431f05cddf9SRui Paulo int scard_supports_umts(struct scard_data *scard)
1432f05cddf9SRui Paulo {
1433f05cddf9SRui Paulo 	return scard->sim_type == SCARD_USIM;
1434f05cddf9SRui Paulo }
1435