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