pcsc_funcs.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1/*
2 * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 *
14 * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
15 * cards through PC/SC smartcard library. These functions are used to implement
16 * authentication routines for EAP-SIM and EAP-AKA.
17 */
18
19#include "includes.h"
20#include <winscard.h>
21
22#include "common.h"
23#include "pcsc_funcs.h"
24
25
26/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
27 * SIM commands:
28 * Command APDU: CLA INS P1 P2 P3 Data
29 *   CLA (class of instruction): A0 for GSM, 00 for USIM
30 *   INS (instruction)
31 *   P1 P2 P3 (parameters, P3 = length of Data)
32 * Response APDU: Data SW1 SW2
33 *   SW1 SW2 (Status words)
34 * Commands (INS P1 P2 P3):
35 *   SELECT: A4 00 00 02 <file_id, 2 bytes>
36 *   GET RESPONSE: C0 00 00 <len>
37 *   RUN GSM ALG: 88 00 00 00 <RAND len = 10>
38 *   RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
39 *	P1 = ID of alg in card
40 *	P2 = ID of secret key
41 *   READ BINARY: B0 <offset high> <offset low> <len>
42 *   READ RECORD: B2 <record number> <mode> <len>
43 *	P2 (mode) = '02' (next record), '03' (previous record),
44 *		    '04' (absolute mode)
45 *   VERIFY CHV: 20 00 <CHV number> 08
46 *   CHANGE CHV: 24 00 <CHV number> 10
47 *   DISABLE CHV: 26 00 01 08
48 *   ENABLE CHV: 28 00 01 08
49 *   UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
50 *   SLEEP: FA 00 00 00
51 */
52
53/* GSM SIM commands */
54#define SIM_CMD_SELECT			0xa0, 0xa4, 0x00, 0x00, 0x02
55#define SIM_CMD_RUN_GSM_ALG		0xa0, 0x88, 0x00, 0x00, 0x10
56#define SIM_CMD_GET_RESPONSE		0xa0, 0xc0, 0x00, 0x00
57#define SIM_CMD_READ_BIN		0xa0, 0xb0, 0x00, 0x00
58#define SIM_CMD_READ_RECORD		0xa0, 0xb2, 0x00, 0x00
59#define SIM_CMD_VERIFY_CHV1		0xa0, 0x20, 0x00, 0x01, 0x08
60
61/* USIM commands */
62#define USIM_CLA			0x00
63#define USIM_CMD_RUN_UMTS_ALG		0x00, 0x88, 0x00, 0x81, 0x22
64#define USIM_CMD_GET_RESPONSE		0x00, 0xc0, 0x00, 0x00
65
66#define SIM_RECORD_MODE_ABSOLUTE 0x04
67
68#define USIM_FSP_TEMPL_TAG		0x62
69
70#define USIM_TLV_FILE_DESC		0x82
71#define USIM_TLV_FILE_ID		0x83
72#define USIM_TLV_DF_NAME		0x84
73#define USIM_TLV_PROPR_INFO		0xA5
74#define USIM_TLV_LIFE_CYCLE_STATUS	0x8A
75#define USIM_TLV_FILE_SIZE		0x80
76#define USIM_TLV_TOTAL_FILE_SIZE	0x81
77#define USIM_TLV_PIN_STATUS_TEMPLATE	0xC6
78#define USIM_TLV_SHORT_FILE_ID		0x88
79
80#define USIM_PS_DO_TAG			0x90
81
82#define AKA_RAND_LEN 16
83#define AKA_AUTN_LEN 16
84#define AKA_AUTS_LEN 14
85#define RES_MAX_LEN 16
86#define IK_LEN 16
87#define CK_LEN 16
88
89
90typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
91
92struct scard_data {
93	SCARDCONTEXT ctx;
94	SCARDHANDLE card;
95	DWORD protocol;
96	sim_types sim_type;
97	int pin1_required;
98};
99
100#ifdef __MINGW32_VERSION
101/* MinGW does not yet support WinScard, so load the needed functions
102 * dynamically from winscard.dll for now. */
103
104static HINSTANCE dll = NULL; /* winscard.dll */
105
106static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
107#undef SCARD_PCI_T0
108#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
109#undef SCARD_PCI_T1
110#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
111
112
113static WINSCARDAPI LONG WINAPI
114(*dll_SCardEstablishContext)(IN DWORD dwScope,
115			     IN LPCVOID pvReserved1,
116			     IN LPCVOID pvReserved2,
117			     OUT LPSCARDCONTEXT phContext);
118#define SCardEstablishContext dll_SCardEstablishContext
119
120static long (*dll_SCardReleaseContext)(long hContext);
121#define SCardReleaseContext dll_SCardReleaseContext
122
123static WINSCARDAPI LONG WINAPI
124(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
125			 IN LPCSTR mszGroups,
126			 OUT LPSTR mszReaders,
127			 IN OUT LPDWORD pcchReaders);
128#undef SCardListReaders
129#define SCardListReaders dll_SCardListReadersA
130
131static WINSCARDAPI LONG WINAPI
132(*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
133		     IN LPCSTR szReader,
134		     IN DWORD dwShareMode,
135		     IN DWORD dwPreferredProtocols,
136		     OUT LPSCARDHANDLE phCard,
137		     OUT LPDWORD pdwActiveProtocol);
138#undef SCardConnect
139#define SCardConnect dll_SCardConnectA
140
141static WINSCARDAPI LONG WINAPI
142(*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
143		       IN DWORD dwDisposition);
144#define SCardDisconnect dll_SCardDisconnect
145
146static WINSCARDAPI LONG WINAPI
147(*dll_SCardTransmit)(IN SCARDHANDLE hCard,
148		     IN LPCSCARD_IO_REQUEST pioSendPci,
149		     IN LPCBYTE pbSendBuffer,
150		     IN DWORD cbSendLength,
151		     IN OUT LPSCARD_IO_REQUEST pioRecvPci,
152		     OUT LPBYTE pbRecvBuffer,
153		     IN OUT LPDWORD pcbRecvLength);
154#define SCardTransmit dll_SCardTransmit
155
156static WINSCARDAPI LONG WINAPI
157(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
158#define SCardBeginTransaction dll_SCardBeginTransaction
159
160static WINSCARDAPI LONG WINAPI
161(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
162#define SCardEndTransaction dll_SCardEndTransaction
163
164
165static int mingw_load_symbols(void)
166{
167	char *sym;
168
169	if (dll)
170		return 0;
171
172	dll = LoadLibrary("winscard");
173	if (dll == NULL) {
174		wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
175			   "library");
176		return -1;
177	}
178
179#define LOADSYM(s) \
180	sym = #s; \
181	dll_ ## s = (void *) GetProcAddress(dll, sym); \
182	if (dll_ ## s == NULL) \
183		goto fail;
184
185	LOADSYM(SCardEstablishContext);
186	LOADSYM(SCardReleaseContext);
187	LOADSYM(SCardListReadersA);
188	LOADSYM(SCardConnectA);
189	LOADSYM(SCardDisconnect);
190	LOADSYM(SCardTransmit);
191	LOADSYM(SCardBeginTransaction);
192	LOADSYM(SCardEndTransaction);
193	LOADSYM(g_rgSCardT0Pci);
194	LOADSYM(g_rgSCardT1Pci);
195
196#undef LOADSYM
197
198	return 0;
199
200fail:
201	wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
202		   "winscard.dll", sym);
203	FreeLibrary(dll);
204	dll = NULL;
205	return -1;
206}
207
208
209static void mingw_unload_symbols(void)
210{
211	if (dll == NULL)
212		return;
213
214	FreeLibrary(dll);
215	dll = NULL;
216}
217
218#else /* __MINGW32_VERSION */
219
220#define mingw_load_symbols() 0
221#define mingw_unload_symbols() do { } while (0)
222
223#endif /* __MINGW32_VERSION */
224
225
226static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
227			      unsigned char *buf, size_t *buf_len,
228			      sim_types sim_type, unsigned char *aid,
229			      size_t aidlen);
230static int scard_select_file(struct scard_data *scard, unsigned short file_id,
231			     unsigned char *buf, size_t *buf_len);
232static int scard_verify_pin(struct scard_data *scard, const char *pin);
233static int scard_get_record_len(struct scard_data *scard,
234				unsigned char recnum, unsigned char mode);
235static int scard_read_record(struct scard_data *scard,
236			     unsigned char *data, size_t len,
237			     unsigned char recnum, unsigned char mode);
238
239
240static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
241				 int *ps_do, int *file_len)
242{
243		unsigned char *pos, *end;
244
245		if (ps_do)
246			*ps_do = -1;
247		if (file_len)
248			*file_len = -1;
249
250		pos = buf;
251		end = pos + buf_len;
252		if (*pos != USIM_FSP_TEMPL_TAG) {
253			wpa_printf(MSG_DEBUG, "SCARD: file header did not "
254				   "start with FSP template tag");
255			return -1;
256		}
257		pos++;
258		if (pos >= end)
259			return -1;
260		if ((pos + pos[0]) < end)
261			end = pos + 1 + pos[0];
262		pos++;
263		wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
264			    pos, end - pos);
265
266		while (pos + 1 < end) {
267			wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
268				   "0x%02x len=%d", pos[0], pos[1]);
269			if (pos + 2 + pos[1] > end)
270				break;
271
272			if (pos[0] == USIM_TLV_FILE_SIZE &&
273			    (pos[1] == 1 || pos[1] == 2) && file_len) {
274				if (pos[1] == 1)
275					*file_len = (int) pos[2];
276				else
277					*file_len = ((int) pos[2] << 8) |
278						(int) pos[3];
279				wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
280					   *file_len);
281			}
282
283			if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
284			    pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
285			    pos[3] >= 1 && ps_do) {
286				wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
287					   pos[4]);
288				*ps_do = (int) pos[4];
289			}
290
291			pos += 2 + pos[1];
292
293			if (pos == end)
294				return 0;
295		}
296		return -1;
297}
298
299
300static int scard_pin_needed(struct scard_data *scard,
301			    unsigned char *hdr, size_t hlen)
302{
303	if (scard->sim_type == SCARD_GSM_SIM) {
304		if (hlen > SCARD_CHV1_OFFSET &&
305		    !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
306			return 1;
307		return 0;
308	}
309
310	if (scard->sim_type == SCARD_USIM) {
311		int ps_do;
312		if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
313			return -1;
314		/* TODO: there could be more than one PS_DO entry because of
315		 * multiple PINs in key reference.. */
316		if (ps_do > 0 && (ps_do & 0x80))
317			return 1;
318		return 0;
319	}
320
321	return -1;
322}
323
324
325static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
326			 size_t maxlen)
327{
328	int rlen, rec;
329	struct efdir {
330		unsigned char appl_template_tag; /* 0x61 */
331		unsigned char appl_template_len;
332		unsigned char appl_id_tag; /* 0x4f */
333		unsigned char aid_len;
334		unsigned char rid[5];
335		unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
336	} *efdir;
337	unsigned char buf[100];
338	size_t blen;
339
340	efdir = (struct efdir *) buf;
341	blen = sizeof(buf);
342	if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
343		wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
344		return -1;
345	}
346	wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
347
348	for (rec = 1; rec < 10; rec++) {
349		rlen = scard_get_record_len(scard, rec,
350					    SIM_RECORD_MODE_ABSOLUTE);
351		if (rlen < 0) {
352			wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
353				   "record length");
354			return -1;
355		}
356		blen = sizeof(buf);
357		if (rlen > (int) blen) {
358			wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
359			return -1;
360		}
361		if (scard_read_record(scard, buf, rlen, rec,
362				      SIM_RECORD_MODE_ABSOLUTE) < 0) {
363			wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
364				   "EF_DIR record %d", rec);
365			return -1;
366		}
367		wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
368
369		if (efdir->appl_template_tag != 0x61) {
370			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
371				   "template tag 0x%x",
372				   efdir->appl_template_tag);
373			continue;
374		}
375
376		if (efdir->appl_template_len > rlen - 2) {
377			wpa_printf(MSG_DEBUG, "SCARD: Too long application "
378				   "template (len=%d rlen=%d)",
379				   efdir->appl_template_len, rlen);
380			continue;
381		}
382
383		if (efdir->appl_id_tag != 0x4f) {
384			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
385				   "identifier tag 0x%x", efdir->appl_id_tag);
386			continue;
387		}
388
389		if (efdir->aid_len < 1 || efdir->aid_len > 16) {
390			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
391				   efdir->aid_len);
392			continue;
393		}
394
395		wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
396			    efdir->rid, efdir->aid_len);
397
398		if (efdir->appl_code[0] == 0x10 &&
399		    efdir->appl_code[1] == 0x02) {
400			wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
401				   "EF_DIR record %d", rec);
402			break;
403		}
404	}
405
406	if (rec >= 10) {
407		wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
408			   "from EF_DIR records");
409		return -1;
410	}
411
412	if (efdir->aid_len > maxlen) {
413		wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
414		return -1;
415	}
416
417	os_memcpy(aid, efdir->rid, efdir->aid_len);
418
419	return efdir->aid_len;
420}
421
422
423/**
424 * scard_init - Initialize SIM/USIM connection using PC/SC
425 * @sim_type: Allowed SIM types (SIM, USIM, or both)
426 * Returns: Pointer to private data structure, or %NULL on failure
427 *
428 * This function is used to initialize SIM/USIM connection. PC/SC is used to
429 * open connection to the SIM/USIM card and the card is verified to support the
430 * selected sim_type. In addition, local flag is set if a PIN is needed to
431 * access some of the card functions. Once the connection is not needed
432 * anymore, scard_deinit() can be used to close it.
433 */
434struct scard_data * scard_init(scard_sim_type sim_type)
435{
436	long ret;
437	unsigned long len;
438	struct scard_data *scard;
439#ifdef CONFIG_NATIVE_WINDOWS
440	TCHAR *readers = NULL;
441#else /* CONFIG_NATIVE_WINDOWS */
442	char *readers = NULL;
443#endif /* CONFIG_NATIVE_WINDOWS */
444	unsigned char buf[100];
445	size_t blen;
446	int transaction = 0;
447	int pin_needed;
448
449	wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
450	if (mingw_load_symbols())
451		return NULL;
452	scard = os_zalloc(sizeof(*scard));
453	if (scard == NULL)
454		return NULL;
455
456	ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
457				    &scard->ctx);
458	if (ret != SCARD_S_SUCCESS) {
459		wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
460			   "context (err=%ld)", ret);
461		goto failed;
462	}
463
464	ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
465	if (ret != SCARD_S_SUCCESS) {
466		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
467			   "(err=%ld)", ret);
468		goto failed;
469	}
470
471#ifdef UNICODE
472	len *= 2;
473#endif /* UNICODE */
474	readers = os_malloc(len);
475	if (readers == NULL) {
476		wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
477		goto failed;
478	}
479
480	ret = SCardListReaders(scard->ctx, NULL, readers, &len);
481	if (ret != SCARD_S_SUCCESS) {
482		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
483			   "(err=%ld)", ret);
484		goto failed;
485	}
486	if (len < 3) {
487		wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
488			   "available.");
489		goto failed;
490	}
491	/* readers is a list of available reader. Last entry is terminated with
492	 * double NUL.
493	 * TODO: add support for selecting the reader; now just use the first
494	 * one.. */
495#ifdef UNICODE
496	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
497#else /* UNICODE */
498	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
499#endif /* UNICODE */
500
501	ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
502			   SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
503	if (ret != SCARD_S_SUCCESS) {
504		if (ret == (long) SCARD_E_NO_SMARTCARD)
505			wpa_printf(MSG_INFO, "No smart card inserted.");
506		else
507			wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
508		goto failed;
509	}
510
511	os_free(readers);
512	readers = NULL;
513
514	wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
515		   (unsigned int) scard->card, scard->protocol,
516		   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
517
518	ret = SCardBeginTransaction(scard->card);
519	if (ret != SCARD_S_SUCCESS) {
520		wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
521			   "0x%x", (unsigned int) ret);
522		goto failed;
523	}
524	transaction = 1;
525
526	blen = sizeof(buf);
527
528	scard->sim_type = SCARD_GSM_SIM;
529	if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
530		wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
531		if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
532				       SCARD_USIM, NULL, 0)) {
533			wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
534			if (sim_type == SCARD_USIM_ONLY)
535				goto failed;
536			wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
537			scard->sim_type = SCARD_GSM_SIM;
538		} else {
539			wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
540			scard->sim_type = SCARD_USIM;
541		}
542	}
543
544	if (scard->sim_type == SCARD_GSM_SIM) {
545		blen = sizeof(buf);
546		if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
547			wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
548			goto failed;
549		}
550
551		blen = sizeof(buf);
552		if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
553			wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
554			goto failed;
555		}
556	} else {
557		unsigned char aid[32];
558		int aid_len;
559
560		aid_len = scard_get_aid(scard, aid, sizeof(aid));
561		if (aid_len < 0) {
562			wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
563				   "3G USIM app - try to use standard 3G RID");
564			os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
565			aid_len = 5;
566		}
567		wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
568
569		/* Select based on AID = 3G RID from EF_DIR. This is usually
570		 * starting with A0 00 00 00 87. */
571		blen = sizeof(buf);
572		if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
573				       aid, aid_len)) {
574			wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
575				   "app");
576			wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
577				    aid, aid_len);
578			goto failed;
579		}
580	}
581
582	/* Verify whether CHV1 (PIN1) is needed to access the card. */
583	pin_needed = scard_pin_needed(scard, buf, blen);
584	if (pin_needed < 0) {
585		wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
586			   "is needed");
587		goto failed;
588	}
589	if (pin_needed) {
590		scard->pin1_required = 1;
591		wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
592	}
593
594	ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
595	if (ret != SCARD_S_SUCCESS) {
596		wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
597			   "0x%x", (unsigned int) ret);
598	}
599
600	return scard;
601
602failed:
603	if (transaction)
604		SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
605	os_free(readers);
606	scard_deinit(scard);
607	return NULL;
608}
609
610
611/**
612 * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
613 * @scard: Pointer to private data from scard_init()
614 * @pin: PIN code as an ASCII string (e.g., "1234")
615 * Returns: 0 on success, -1 on failure
616 */
617int scard_set_pin(struct scard_data *scard, const char *pin)
618{
619	if (scard == NULL)
620		return -1;
621
622	/* Verify whether CHV1 (PIN1) is needed to access the card. */
623	if (scard->pin1_required) {
624		if (pin == NULL) {
625			wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
626				   "access");
627			return -1;
628		}
629		if (scard_verify_pin(scard, pin)) {
630			wpa_printf(MSG_INFO, "PIN verification failed for "
631				"SIM access");
632			return -1;
633		}
634	}
635
636	return 0;
637}
638
639
640/**
641 * scard_deinit - Deinitialize SIM/USIM connection
642 * @scard: Pointer to private data from scard_init()
643 *
644 * This function closes the SIM/USIM connect opened with scard_init().
645 */
646void scard_deinit(struct scard_data *scard)
647{
648	long ret;
649
650	if (scard == NULL)
651		return;
652
653	wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
654	if (scard->card) {
655		ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
656		if (ret != SCARD_S_SUCCESS) {
657			wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
658				   "smart card (err=%ld)", ret);
659		}
660	}
661
662	if (scard->ctx) {
663		ret = SCardReleaseContext(scard->ctx);
664		if (ret != SCARD_S_SUCCESS) {
665			wpa_printf(MSG_DEBUG, "Failed to release smart card "
666				   "context (err=%ld)", ret);
667		}
668	}
669	os_free(scard);
670	mingw_unload_symbols();
671}
672
673
674static long scard_transmit(struct scard_data *scard,
675			   unsigned char *_send, size_t send_len,
676			   unsigned char *_recv, size_t *recv_len)
677{
678	long ret;
679	unsigned long rlen;
680
681	wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
682			_send, send_len);
683	rlen = *recv_len;
684	ret = SCardTransmit(scard->card,
685			    scard->protocol == SCARD_PROTOCOL_T1 ?
686			    SCARD_PCI_T1 : SCARD_PCI_T0,
687			    _send, (unsigned long) send_len,
688			    NULL, _recv, &rlen);
689	*recv_len = rlen;
690	if (ret == SCARD_S_SUCCESS) {
691		wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
692			    _recv, rlen);
693	} else {
694		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
695			   "(err=0x%lx)", ret);
696	}
697	return ret;
698}
699
700
701static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
702			      unsigned char *buf, size_t *buf_len,
703			      sim_types sim_type, unsigned char *aid,
704			      size_t aidlen)
705{
706	long ret;
707	unsigned char resp[3];
708	unsigned char cmd[50] = { SIM_CMD_SELECT };
709	int cmdlen;
710	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
711	size_t len, rlen;
712
713	if (sim_type == SCARD_USIM) {
714		cmd[0] = USIM_CLA;
715		cmd[3] = 0x04;
716		get_resp[0] = USIM_CLA;
717	}
718
719	wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
720	if (aid) {
721		wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
722			    aid, aidlen);
723		if (5 + aidlen > sizeof(cmd))
724			return -1;
725		cmd[2] = 0x04; /* Select by AID */
726		cmd[4] = aidlen; /* len */
727		os_memcpy(cmd + 5, aid, aidlen);
728		cmdlen = 5 + aidlen;
729	} else {
730		cmd[5] = file_id >> 8;
731		cmd[6] = file_id & 0xff;
732		cmdlen = 7;
733	}
734	len = sizeof(resp);
735	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
736	if (ret != SCARD_S_SUCCESS) {
737		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
738			   "(err=0x%lx)", ret);
739		return -1;
740	}
741
742	if (len != 2) {
743		wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
744			   "%d (expected 2)", (int) len);
745		return -1;
746	}
747
748	if (resp[0] == 0x98 && resp[1] == 0x04) {
749		/* Security status not satisfied (PIN_WLAN) */
750		wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
751			   "(PIN_WLAN)");
752		return -1;
753	}
754
755	if (resp[0] == 0x6e) {
756		wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
757		return -1;
758	}
759
760	if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
761		wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
762			   "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
763		return -1;
764	}
765	/* Normal ending of command; resp[1] bytes available */
766	get_resp[4] = resp[1];
767	wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
768		   resp[1]);
769
770	rlen = *buf_len;
771	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
772	if (ret == SCARD_S_SUCCESS) {
773		*buf_len = resp[1] < rlen ? resp[1] : rlen;
774		return 0;
775	}
776
777	wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
778	return -1;
779}
780
781
782static int scard_select_file(struct scard_data *scard, unsigned short file_id,
783			     unsigned char *buf, size_t *buf_len)
784{
785	return _scard_select_file(scard, file_id, buf, buf_len,
786				  scard->sim_type, NULL, 0);
787}
788
789
790static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
791				unsigned char mode)
792{
793	unsigned char buf[255];
794	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
795	size_t blen;
796	long ret;
797
798	if (scard->sim_type == SCARD_USIM)
799		cmd[0] = USIM_CLA;
800	cmd[2] = recnum;
801	cmd[3] = mode;
802	cmd[4] = sizeof(buf);
803
804	blen = sizeof(buf);
805	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
806	if (ret != SCARD_S_SUCCESS) {
807		wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
808			   "length for record %d", recnum);
809		return -1;
810	}
811
812	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
813		    buf, blen);
814
815	if (blen < 2 || buf[0] != 0x6c) {
816		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
817			   "length determination");
818		return -1;
819	}
820
821	return buf[1];
822}
823
824
825static int scard_read_record(struct scard_data *scard,
826			     unsigned char *data, size_t len,
827			     unsigned char recnum, unsigned char mode)
828{
829	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
830	size_t blen = len + 3;
831	unsigned char *buf;
832	long ret;
833
834	if (scard->sim_type == SCARD_USIM)
835		cmd[0] = USIM_CLA;
836	cmd[2] = recnum;
837	cmd[3] = mode;
838	cmd[4] = len;
839
840	buf = os_malloc(blen);
841	if (buf == NULL)
842		return -1;
843
844	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
845	if (ret != SCARD_S_SUCCESS) {
846		os_free(buf);
847		return -2;
848	}
849	if (blen != len + 2) {
850		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
851			   "length %ld (expected %ld)",
852			   (long) blen, (long) len + 2);
853		os_free(buf);
854		return -3;
855	}
856
857	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
858		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
859			   "status %02x %02x (expected 90 00)",
860			   buf[len], buf[len + 1]);
861		os_free(buf);
862		return -4;
863	}
864
865	os_memcpy(data, buf, len);
866	os_free(buf);
867
868	return 0;
869}
870
871
872static int scard_read_file(struct scard_data *scard,
873			   unsigned char *data, size_t len)
874{
875	unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
876	size_t blen = len + 3;
877	unsigned char *buf;
878	long ret;
879
880	cmd[4] = len;
881
882	buf = os_malloc(blen);
883	if (buf == NULL)
884		return -1;
885
886	if (scard->sim_type == SCARD_USIM)
887		cmd[0] = USIM_CLA;
888	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
889	if (ret != SCARD_S_SUCCESS) {
890		os_free(buf);
891		return -2;
892	}
893	if (blen != len + 2) {
894		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
895			   "length %ld (expected %ld)",
896			   (long) blen, (long) len + 2);
897		os_free(buf);
898		return -3;
899	}
900
901	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
902		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
903			   "status %02x %02x (expected 90 00)",
904			   buf[len], buf[len + 1]);
905		os_free(buf);
906		return -4;
907	}
908
909	os_memcpy(data, buf, len);
910	os_free(buf);
911
912	return 0;
913}
914
915
916static int scard_verify_pin(struct scard_data *scard, const char *pin)
917{
918	long ret;
919	unsigned char resp[3];
920	unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
921	size_t len;
922
923	wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
924
925	if (pin == NULL || os_strlen(pin) > 8)
926		return -1;
927
928	if (scard->sim_type == SCARD_USIM)
929		cmd[0] = USIM_CLA;
930	os_memcpy(cmd + 5, pin, os_strlen(pin));
931	os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
932
933	len = sizeof(resp);
934	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
935	if (ret != SCARD_S_SUCCESS)
936		return -2;
937
938	if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
939		wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
940		return -1;
941	}
942
943	wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
944	return 0;
945}
946
947
948/**
949 * scard_get_imsi - Read IMSI from SIM/USIM card
950 * @scard: Pointer to private data from scard_init()
951 * @imsi: Buffer for IMSI
952 * @len: Length of imsi buffer; set to IMSI length on success
953 * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
954 * selection returns invalid result code, -3 if parsing FSP template file fails
955 * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
956 * to needed length), -5 if reading IMSI file fails.
957 *
958 * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
959 * file is PIN protected, scard_set_pin() must have been used to set the
960 * correct PIN code before calling scard_get_imsi().
961 */
962int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
963{
964	unsigned char buf[100];
965	size_t blen, imsilen, i;
966	char *pos;
967
968	wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
969	blen = sizeof(buf);
970	if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
971		return -1;
972	if (blen < 4) {
973		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
974			   "header (len=%ld)", (long) blen);
975		return -2;
976	}
977
978	if (scard->sim_type == SCARD_GSM_SIM) {
979		blen = (buf[2] << 8) | buf[3];
980	} else {
981		int file_size;
982		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
983			return -3;
984		blen = file_size;
985	}
986	if (blen < 2 || blen > sizeof(buf)) {
987		wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
988			   (long) blen);
989		return -3;
990	}
991
992	imsilen = (blen - 2) * 2 + 1;
993	wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
994		   (long) blen, (long) imsilen);
995	if (blen < 2 || imsilen > *len) {
996		*len = imsilen;
997		return -4;
998	}
999
1000	if (scard_read_file(scard, buf, blen))
1001		return -5;
1002
1003	pos = imsi;
1004	*pos++ = '0' + (buf[1] >> 4 & 0x0f);
1005	for (i = 2; i < blen; i++) {
1006		unsigned char digit;
1007
1008		digit = buf[i] & 0x0f;
1009		if (digit < 10)
1010			*pos++ = '0' + digit;
1011		else
1012			imsilen--;
1013
1014		digit = buf[i] >> 4 & 0x0f;
1015		if (digit < 10)
1016			*pos++ = '0' + digit;
1017		else
1018			imsilen--;
1019	}
1020	*len = imsilen;
1021
1022	return 0;
1023}
1024
1025
1026/**
1027 * scard_gsm_auth - Run GSM authentication command on SIM card
1028 * @scard: Pointer to private data from scard_init()
1029 * @_rand: 16-byte RAND value from HLR/AuC
1030 * @sres: 4-byte buffer for SRES
1031 * @kc: 8-byte buffer for Kc
1032 * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
1033 * -2 if authentication command execution fails, -3 if unknown response code
1034 * for authentication command is received, -4 if reading of response fails,
1035 * -5 if if response data is of unexpected length
1036 *
1037 * This function performs GSM authentication using SIM/USIM card and the
1038 * provided RAND value from HLR/AuC. If authentication command can be completed
1039 * successfully, SRES and Kc values will be written into sres and kc buffers.
1040 */
1041int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
1042		   unsigned char *sres, unsigned char *kc)
1043{
1044	unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
1045	int cmdlen;
1046	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
1047	unsigned char resp[3], buf[12 + 3 + 2];
1048	size_t len;
1049	long ret;
1050
1051	if (scard == NULL)
1052		return -1;
1053
1054	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
1055	if (scard->sim_type == SCARD_GSM_SIM) {
1056		cmdlen = 5 + 16;
1057		os_memcpy(cmd + 5, _rand, 16);
1058	} else {
1059		cmdlen = 5 + 1 + 16;
1060		cmd[0] = USIM_CLA;
1061		cmd[3] = 0x80;
1062		cmd[4] = 17;
1063		cmd[5] = 16;
1064		os_memcpy(cmd + 6, _rand, 16);
1065	}
1066	len = sizeof(resp);
1067	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
1068	if (ret != SCARD_S_SUCCESS)
1069		return -2;
1070
1071	if ((scard->sim_type == SCARD_GSM_SIM &&
1072	     (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
1073	    (scard->sim_type == SCARD_USIM &&
1074	     (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
1075		wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
1076			   "auth request (len=%ld resp=%02x %02x)",
1077			   (long) len, resp[0], resp[1]);
1078		return -3;
1079	}
1080	get_resp[4] = resp[1];
1081
1082	len = sizeof(buf);
1083	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
1084	if (ret != SCARD_S_SUCCESS)
1085		return -4;
1086
1087	if (scard->sim_type == SCARD_GSM_SIM) {
1088		if (len != 4 + 8 + 2) {
1089			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
1090				   "length for GSM auth (len=%ld, expected 14)",
1091				   (long) len);
1092			return -5;
1093		}
1094		os_memcpy(sres, buf, 4);
1095		os_memcpy(kc, buf + 4, 8);
1096	} else {
1097		if (len != 1 + 4 + 1 + 8 + 2) {
1098			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
1099				   "length for USIM auth (len=%ld, "
1100				   "expected 16)", (long) len);
1101			return -5;
1102		}
1103		if (buf[0] != 4 || buf[5] != 8) {
1104			wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
1105				   "length (%d %d, expected 4 8)",
1106				   buf[0], buf[5]);
1107		}
1108		os_memcpy(sres, buf + 1, 4);
1109		os_memcpy(kc, buf + 6, 8);
1110	}
1111
1112	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
1113	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
1114
1115	return 0;
1116}
1117
1118
1119/**
1120 * scard_umts_auth - Run UMTS authentication command on USIM card
1121 * @scard: Pointer to private data from scard_init()
1122 * @_rand: 16-byte RAND value from HLR/AuC
1123 * @autn: 16-byte AUTN value from HLR/AuC
1124 * @res: 16-byte buffer for RES
1125 * @res_len: Variable that will be set to RES length
1126 * @ik: 16-byte buffer for IK
1127 * @ck: 16-byte buffer for CK
1128 * @auts: 14-byte buffer for AUTS
1129 * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
1130 * failure
1131 *
1132 * This function performs AKA authentication using USIM card and the provided
1133 * RAND and AUTN values from HLR/AuC. If authentication command can be
1134 * completed successfully, RES, IK, and CK values will be written into provided
1135 * buffers and res_len is set to length of received RES value. If USIM reports
1136 * synchronization failure, the received AUTS value will be written into auts
1137 * buffer. In this case, RES, IK, and CK are not valid.
1138 */
1139int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
1140		    const unsigned char *autn,
1141		    unsigned char *res, size_t *res_len,
1142		    unsigned char *ik, unsigned char *ck, unsigned char *auts)
1143{
1144	unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
1145		{ USIM_CMD_RUN_UMTS_ALG };
1146	unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
1147	unsigned char resp[3], buf[64], *pos, *end;
1148	size_t len;
1149	long ret;
1150
1151	if (scard == NULL)
1152		return -1;
1153
1154	if (scard->sim_type == SCARD_GSM_SIM) {
1155		wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
1156			   "auth");
1157		return -1;
1158	}
1159
1160	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
1161	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
1162	cmd[5] = AKA_RAND_LEN;
1163	os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
1164	cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
1165	os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
1166
1167	len = sizeof(resp);
1168	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
1169	if (ret != SCARD_S_SUCCESS)
1170		return -1;
1171
1172	if (len <= sizeof(resp))
1173		wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
1174
1175	if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
1176		wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
1177			   "MAC != XMAC");
1178		return -1;
1179	} else if (len != 2 || resp[0] != 0x61) {
1180		wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
1181			   "auth request (len=%ld resp=%02x %02x)",
1182			   (long) len, resp[0], resp[1]);
1183		return -1;
1184	}
1185	get_resp[4] = resp[1];
1186
1187	len = sizeof(buf);
1188	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
1189	if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
1190		return -1;
1191
1192	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
1193	if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
1194	    buf[1] == AKA_AUTS_LEN) {
1195		wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
1196		os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
1197		wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
1198		return -2;
1199	} else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
1200		pos = buf + 1;
1201		end = buf + len;
1202
1203		/* RES */
1204		if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
1205			wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
1206			return -1;
1207		}
1208		*res_len = *pos++;
1209		os_memcpy(res, pos, *res_len);
1210		pos += *res_len;
1211		wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
1212
1213		/* CK */
1214		if (pos[0] != CK_LEN || pos + CK_LEN > end) {
1215			wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
1216			return -1;
1217		}
1218		pos++;
1219		os_memcpy(ck, pos, CK_LEN);
1220		pos += CK_LEN;
1221		wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
1222
1223		/* IK */
1224		if (pos[0] != IK_LEN || pos + IK_LEN > end) {
1225			wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
1226			return -1;
1227		}
1228		pos++;
1229		os_memcpy(ik, pos, IK_LEN);
1230		pos += IK_LEN;
1231		wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
1232
1233		return 0;
1234	}
1235
1236	wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
1237	return -1;
1238}
1239