2 * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
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.
23 #include "pcsc_funcs.h"
26 /* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
28 * Command APDU: CLA INS P1 P2 P3 Data
29 * CLA (class of instruction): A0 for GSM, 00 for USIM
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
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
63 #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
64 #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
66 #define SIM_RECORD_MODE_ABSOLUTE 0x04
68 #define USIM_FSP_TEMPL_TAG 0x62
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
80 #define USIM_PS_DO_TAG 0x90
82 #define AKA_RAND_LEN 16
83 #define AKA_AUTN_LEN 16
84 #define AKA_AUTS_LEN 14
85 #define RES_MAX_LEN 16
90 typedef enum { SCARD_GSM_SIM
, SCARD_USIM
} sim_types
;
100 #ifdef __MINGW32_VERSION
101 /* MinGW does not yet support WinScard, so load the needed functions
102 * dynamically from winscard.dll for now. */
104 static HINSTANCE dll
= NULL
; /* winscard.dll */
106 static const SCARD_IO_REQUEST
*dll_g_rgSCardT0Pci
, *dll_g_rgSCardT1Pci
;
108 #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
110 #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
113 static 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
120 static long (*dll_SCardReleaseContext
)(long hContext
);
121 #define SCardReleaseContext dll_SCardReleaseContext
123 static WINSCARDAPI LONG WINAPI
124 (*dll_SCardListReadersA
)(IN SCARDCONTEXT hContext
,
126 OUT LPSTR mszReaders
,
127 IN OUT LPDWORD pcchReaders
);
128 #undef SCardListReaders
129 #define SCardListReaders dll_SCardListReadersA
131 static WINSCARDAPI LONG WINAPI
132 (*dll_SCardConnectA
)(IN SCARDCONTEXT hContext
,
134 IN DWORD dwShareMode
,
135 IN DWORD dwPreferredProtocols
,
136 OUT LPSCARDHANDLE phCard
,
137 OUT LPDWORD pdwActiveProtocol
);
139 #define SCardConnect dll_SCardConnectA
141 static WINSCARDAPI LONG WINAPI
142 (*dll_SCardDisconnect
)(IN SCARDHANDLE hCard
,
143 IN DWORD dwDisposition
);
144 #define SCardDisconnect dll_SCardDisconnect
146 static 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
156 static WINSCARDAPI LONG WINAPI
157 (*dll_SCardBeginTransaction
)(IN SCARDHANDLE hCard
);
158 #define SCardBeginTransaction dll_SCardBeginTransaction
160 static WINSCARDAPI LONG WINAPI
161 (*dll_SCardEndTransaction
)(IN SCARDHANDLE hCard
, IN DWORD dwDisposition
);
162 #define SCardEndTransaction dll_SCardEndTransaction
165 static int mingw_load_symbols(void)
172 dll
= LoadLibrary("winscard");
174 wpa_printf(MSG_DEBUG
, "WinSCard: Could not load winscard.dll "
181 dll_ ## s = (void *) GetProcAddress(dll, sym); \
182 if (dll_ ## s == NULL) \
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
);
201 wpa_printf(MSG_DEBUG
, "WinSCard: Could not get address for %s from "
202 "winscard.dll", sym
);
209 static void mingw_unload_symbols(void)
218 #else /* __MINGW32_VERSION */
220 #define mingw_load_symbols() 0
221 #define mingw_unload_symbols() do { } while (0)
223 #endif /* __MINGW32_VERSION */
226 static 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
,
230 static int scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
231 unsigned char *buf
, size_t *buf_len
);
232 static int scard_verify_pin(struct scard_data
*scard
, const char *pin
);
233 static int scard_get_record_len(struct scard_data
*scard
,
234 unsigned char recnum
, unsigned char mode
);
235 static int scard_read_record(struct scard_data
*scard
,
236 unsigned char *data
, size_t len
,
237 unsigned char recnum
, unsigned char mode
);
240 static int scard_parse_fsp_templ(unsigned char *buf
, size_t buf_len
,
241 int *ps_do
, int *file_len
)
243 unsigned char *pos
, *end
;
252 if (*pos
!= USIM_FSP_TEMPL_TAG
) {
253 wpa_printf(MSG_DEBUG
, "SCARD: file header did not "
254 "start with FSP template tag");
260 if ((pos
+ pos
[0]) < end
)
261 end
= pos
+ 1 + pos
[0];
263 wpa_hexdump(MSG_DEBUG
, "SCARD: file header FSP template",
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
)
272 if (pos
[0] == USIM_TLV_FILE_SIZE
&&
273 (pos
[1] == 1 || pos
[1] == 2) && file_len
) {
275 *file_len
= (int) pos
[2];
277 *file_len
= ((int) pos
[2] << 8) |
279 wpa_printf(MSG_DEBUG
, "SCARD: file_size=%d",
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",
288 *ps_do
= (int) pos
[4];
300 static int scard_pin_needed(struct scard_data
*scard
,
301 unsigned char *hdr
, size_t hlen
)
303 if (scard
->sim_type
== SCARD_GSM_SIM
) {
304 if (hlen
> SCARD_CHV1_OFFSET
&&
305 !(hdr
[SCARD_CHV1_OFFSET
] & SCARD_CHV1_FLAG
))
310 if (scard
->sim_type
== SCARD_USIM
) {
312 if (scard_parse_fsp_templ(hdr
, hlen
, &ps_do
, NULL
))
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))
325 static int scard_get_aid(struct scard_data
*scard
, unsigned char *aid
,
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 */
337 unsigned char buf
[100];
340 efdir
= (struct efdir
*) buf
;
342 if (scard_select_file(scard
, SCARD_FILE_EF_DIR
, buf
, &blen
)) {
343 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read EF_DIR");
346 wpa_hexdump(MSG_DEBUG
, "SCARD: EF_DIR select", buf
, blen
);
348 for (rec
= 1; rec
< 10; rec
++) {
349 rlen
= scard_get_record_len(scard
, rec
,
350 SIM_RECORD_MODE_ABSOLUTE
);
352 wpa_printf(MSG_DEBUG
, "SCARD: Failed to get EF_DIR "
357 if (rlen
> (int) blen
) {
358 wpa_printf(MSG_DEBUG
, "SCARD: Too long EF_DIR record");
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
);
367 wpa_hexdump(MSG_DEBUG
, "SCARD: EF_DIR record", buf
, rlen
);
369 if (efdir
->appl_template_tag
!= 0x61) {
370 wpa_printf(MSG_DEBUG
, "SCARD: Unexpected application "
372 efdir
->appl_template_tag
);
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
);
383 if (efdir
->appl_id_tag
!= 0x4f) {
384 wpa_printf(MSG_DEBUG
, "SCARD: Unexpected application "
385 "identifier tag 0x%x", efdir
->appl_id_tag
);
389 if (efdir
->aid_len
< 1 || efdir
->aid_len
> 16) {
390 wpa_printf(MSG_DEBUG
, "SCARD: Invalid AID length %d",
395 wpa_hexdump(MSG_DEBUG
, "SCARD: AID from EF_DIR record",
396 efdir
->rid
, efdir
->aid_len
);
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
);
407 wpa_printf(MSG_DEBUG
, "SCARD: 3G USIM app not found "
408 "from EF_DIR records");
412 if (efdir
->aid_len
> maxlen
) {
413 wpa_printf(MSG_DEBUG
, "SCARD: Too long AID");
417 os_memcpy(aid
, efdir
->rid
, efdir
->aid_len
);
419 return efdir
->aid_len
;
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
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.
434 struct scard_data
* scard_init(scard_sim_type sim_type
)
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];
449 wpa_printf(MSG_DEBUG
, "SCARD: initializing smart card interface");
450 if (mingw_load_symbols())
452 scard
= os_zalloc(sizeof(*scard
));
456 ret
= SCardEstablishContext(SCARD_SCOPE_SYSTEM
, NULL
, NULL
,
458 if (ret
!= SCARD_S_SUCCESS
) {
459 wpa_printf(MSG_DEBUG
, "SCARD: Could not establish smart card "
460 "context (err=%ld)", ret
);
464 ret
= SCardListReaders(scard
->ctx
, NULL
, NULL
, &len
);
465 if (ret
!= SCARD_S_SUCCESS
) {
466 wpa_printf(MSG_DEBUG
, "SCARD: SCardListReaders failed "
474 readers
= os_malloc(len
);
475 if (readers
== NULL
) {
476 wpa_printf(MSG_INFO
, "SCARD: malloc failed\n");
480 ret
= SCardListReaders(scard
->ctx
, NULL
, readers
, &len
);
481 if (ret
!= SCARD_S_SUCCESS
) {
482 wpa_printf(MSG_DEBUG
, "SCARD: SCardListReaders failed(2) "
487 wpa_printf(MSG_WARNING
, "SCARD: No smart card readers "
491 /* readers is a list of available reader. Last entry is terminated with
493 * TODO: add support for selecting the reader; now just use the first
496 wpa_printf(MSG_DEBUG
, "SCARD: Selected reader='%S'", readers
);
498 wpa_printf(MSG_DEBUG
, "SCARD: Selected reader='%s'", readers
);
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.");
507 wpa_printf(MSG_WARNING
, "SCardConnect err=%lx", ret
);
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");
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
);
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
)
536 wpa_printf(MSG_DEBUG
, "SCARD: Trying to use GSM SIM");
537 scard
->sim_type
= SCARD_GSM_SIM
;
539 wpa_printf(MSG_DEBUG
, "SCARD: USIM is supported");
540 scard
->sim_type
= SCARD_USIM
;
544 if (scard
->sim_type
== SCARD_GSM_SIM
) {
546 if (scard_select_file(scard
, SCARD_FILE_MF
, buf
, &blen
)) {
547 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read MF");
552 if (scard_select_file(scard
, SCARD_FILE_GSM_DF
, buf
, &blen
)) {
553 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read GSM DF");
557 unsigned char aid
[32];
560 aid_len
= scard_get_aid(scard
, aid
, sizeof(aid
));
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);
567 wpa_hexdump(MSG_DEBUG
, "SCARD: 3G USIM AID", aid
, aid_len
);
569 /* Select based on AID = 3G RID from EF_DIR. This is usually
570 * starting with A0 00 00 00 87. */
572 if (_scard_select_file(scard
, 0, buf
, &blen
, scard
->sim_type
,
574 wpa_printf(MSG_INFO
, "SCARD: Failed to read 3G USIM "
576 wpa_hexdump(MSG_INFO
, "SCARD: 3G USIM AID",
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 "
590 scard
->pin1_required
= 1;
591 wpa_printf(MSG_DEBUG
, "PIN1 needed for SIM access");
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
);
604 SCardEndTransaction(scard
->card
, SCARD_LEAVE_CARD
);
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
617 int scard_set_pin(struct scard_data
*scard
, const char *pin
)
622 /* Verify whether CHV1 (PIN1) is needed to access the card. */
623 if (scard
->pin1_required
) {
625 wpa_printf(MSG_DEBUG
, "No PIN configured for SIM "
629 if (scard_verify_pin(scard
, pin
)) {
630 wpa_printf(MSG_INFO
, "PIN verification failed for "
641 * scard_deinit - Deinitialize SIM/USIM connection
642 * @scard: Pointer to private data from scard_init()
644 * This function closes the SIM/USIM connect opened with scard_init().
646 void scard_deinit(struct scard_data
*scard
)
653 wpa_printf(MSG_DEBUG
, "SCARD: deinitializing smart card interface");
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
);
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
);
670 mingw_unload_symbols();
674 static long scard_transmit(struct scard_data
*scard
,
675 unsigned char *_send
, size_t send_len
,
676 unsigned char *_recv
, size_t *recv_len
)
681 wpa_hexdump_key(MSG_DEBUG
, "SCARD: scard_transmit: send",
684 ret
= SCardTransmit(scard
->card
,
685 scard
->protocol
== SCARD_PROTOCOL_T1
?
686 SCARD_PCI_T1
: SCARD_PCI_T0
,
687 _send
, (unsigned long) send_len
,
690 if (ret
== SCARD_S_SUCCESS
) {
691 wpa_hexdump(MSG_DEBUG
, "SCARD: scard_transmit: recv",
694 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit failed "
701 static 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
,
707 unsigned char resp
[3];
708 unsigned char cmd
[50] = { SIM_CMD_SELECT
};
710 unsigned char get_resp
[5] = { SIM_CMD_GET_RESPONSE
};
713 if (sim_type
== SCARD_USIM
) {
716 get_resp
[0] = USIM_CLA
;
719 wpa_printf(MSG_DEBUG
, "SCARD: select file %04x", file_id
);
721 wpa_hexdump(MSG_DEBUG
, "SCARD: select file by AID",
723 if (5 + aidlen
> sizeof(cmd
))
725 cmd
[2] = 0x04; /* Select by AID */
726 cmd
[4] = aidlen
; /* len */
727 os_memcpy(cmd
+ 5, aid
, aidlen
);
730 cmd
[5] = file_id
>> 8;
731 cmd
[6] = file_id
& 0xff;
735 ret
= scard_transmit(scard
, cmd
, cmdlen
, resp
, &len
);
736 if (ret
!= SCARD_S_SUCCESS
) {
737 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit failed "
743 wpa_printf(MSG_WARNING
, "SCARD: unexpected resp len "
744 "%d (expected 2)", (int) len
);
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 "
755 if (resp
[0] == 0x6e) {
756 wpa_printf(MSG_DEBUG
, "SCARD: used CLA not supported");
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]);
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)",
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
;
777 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit err=0x%lx\n", ret
);
782 static int scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
783 unsigned char *buf
, size_t *buf_len
)
785 return _scard_select_file(scard
, file_id
, buf
, buf_len
,
786 scard
->sim_type
, NULL
, 0);
790 static int scard_get_record_len(struct scard_data
*scard
, unsigned char recnum
,
793 unsigned char buf
[255];
794 unsigned char cmd
[5] = { SIM_CMD_READ_RECORD
/* , len */ };
798 if (scard
->sim_type
== SCARD_USIM
)
802 cmd
[4] = 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
);
812 wpa_hexdump(MSG_DEBUG
, "SCARD: file length determination response",
815 if (blen
< 2 || buf
[0] != 0x6c) {
816 wpa_printf(MSG_DEBUG
, "SCARD: unexpected response to file "
817 "length determination");
825 static int scard_read_record(struct scard_data
*scard
,
826 unsigned char *data
, size_t len
,
827 unsigned char recnum
, unsigned char mode
)
829 unsigned char cmd
[5] = { SIM_CMD_READ_RECORD
/* , len */ };
830 size_t blen
= len
+ 3;
834 if (scard
->sim_type
== SCARD_USIM
)
840 buf
= os_malloc(blen
);
844 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), buf
, &blen
);
845 if (ret
!= SCARD_S_SUCCESS
) {
849 if (blen
!= len
+ 2) {
850 wpa_printf(MSG_DEBUG
, "SCARD: record read returned unexpected "
851 "length %d (expected %d)", blen
, len
+ 2);
856 if (buf
[len
] != 0x90 || buf
[len
+ 1] != 0x00) {
857 wpa_printf(MSG_DEBUG
, "SCARD: record read returned unexpected "
858 "status %02x %02x (expected 90 00)",
859 buf
[len
], buf
[len
+ 1]);
864 os_memcpy(data
, buf
, len
);
871 static int scard_read_file(struct scard_data
*scard
,
872 unsigned char *data
, size_t len
)
874 unsigned char cmd
[5] = { SIM_CMD_READ_BIN
/* , len */ };
875 size_t blen
= len
+ 3;
881 buf
= os_malloc(blen
);
885 if (scard
->sim_type
== SCARD_USIM
)
887 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), buf
, &blen
);
888 if (ret
!= SCARD_S_SUCCESS
) {
892 if (blen
!= len
+ 2) {
893 wpa_printf(MSG_DEBUG
, "SCARD: file read returned unexpected "
894 "length %d (expected %d)", blen
, len
+ 2);
899 if (buf
[len
] != 0x90 || buf
[len
+ 1] != 0x00) {
900 wpa_printf(MSG_DEBUG
, "SCARD: file read returned unexpected "
901 "status %02x %02x (expected 90 00)",
902 buf
[len
], buf
[len
+ 1]);
907 os_memcpy(data
, buf
, len
);
914 static int scard_verify_pin(struct scard_data
*scard
, const char *pin
)
917 unsigned char resp
[3];
918 unsigned char cmd
[5 + 8] = { SIM_CMD_VERIFY_CHV1
};
921 wpa_printf(MSG_DEBUG
, "SCARD: verifying PIN");
923 if (pin
== NULL
|| os_strlen(pin
) > 8)
926 if (scard
->sim_type
== SCARD_USIM
)
928 os_memcpy(cmd
+ 5, pin
, os_strlen(pin
));
929 os_memset(cmd
+ 5 + os_strlen(pin
), 0xff, 8 - os_strlen(pin
));
932 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), resp
, &len
);
933 if (ret
!= SCARD_S_SUCCESS
)
936 if (len
!= 2 || resp
[0] != 0x90 || resp
[1] != 0x00) {
937 wpa_printf(MSG_WARNING
, "SCARD: PIN verification failed");
941 wpa_printf(MSG_DEBUG
, "SCARD: PIN verified successfully");
947 * scard_get_imsi - Read IMSI from SIM/USIM card
948 * @scard: Pointer to private data from scard_init()
949 * @imsi: Buffer for IMSI
950 * @len: Length of imsi buffer; set to IMSI length on success
951 * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
952 * selection returns invalid result code, -3 if parsing FSP template file fails
953 * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
954 * to needed length), -5 if reading IMSI file fails.
956 * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
957 * file is PIN protected, scard_set_pin() must have been used to set the
958 * correct PIN code before calling scard_get_imsi().
960 int scard_get_imsi(struct scard_data
*scard
, char *imsi
, size_t *len
)
962 unsigned char buf
[100];
963 size_t blen
, imsilen
, i
;
966 wpa_printf(MSG_DEBUG
, "SCARD: reading IMSI from (GSM) EF-IMSI");
968 if (scard_select_file(scard
, SCARD_FILE_GSM_EF_IMSI
, buf
, &blen
))
971 wpa_printf(MSG_WARNING
, "SCARD: too short (GSM) EF-IMSI "
972 "header (len=%d)", blen
);
976 if (scard
->sim_type
== SCARD_GSM_SIM
) {
977 blen
= (buf
[2] << 8) | buf
[3];
980 if (scard_parse_fsp_templ(buf
, blen
, NULL
, &file_size
))
984 if (blen
< 2 || blen
> sizeof(buf
)) {
985 wpa_printf(MSG_DEBUG
, "SCARD: invalid IMSI file length=%d",
990 imsilen
= (blen
- 2) * 2 + 1;
991 wpa_printf(MSG_DEBUG
, "SCARD: IMSI file length=%d imsilen=%d",
993 if (blen
< 2 || imsilen
> *len
) {
998 if (scard_read_file(scard
, buf
, blen
))
1002 *pos
++ = '0' + (buf
[1] >> 4 & 0x0f);
1003 for (i
= 2; i
< blen
; i
++) {
1004 unsigned char digit
;
1006 digit
= buf
[i
] & 0x0f;
1008 *pos
++ = '0' + digit
;
1012 digit
= buf
[i
] >> 4 & 0x0f;
1014 *pos
++ = '0' + digit
;
1025 * scard_gsm_auth - Run GSM authentication command on SIM card
1026 * @scard: Pointer to private data from scard_init()
1027 * @_rand: 16-byte RAND value from HLR/AuC
1028 * @sres: 4-byte buffer for SRES
1029 * @kc: 8-byte buffer for Kc
1030 * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
1031 * -2 if authentication command execution fails, -3 if unknown response code
1032 * for authentication command is received, -4 if reading of response fails,
1033 * -5 if if response data is of unexpected length
1035 * This function performs GSM authentication using SIM/USIM card and the
1036 * provided RAND value from HLR/AuC. If authentication command can be completed
1037 * successfully, SRES and Kc values will be written into sres and kc buffers.
1039 int scard_gsm_auth(struct scard_data
*scard
, const unsigned char *_rand
,
1040 unsigned char *sres
, unsigned char *kc
)
1042 unsigned char cmd
[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG
};
1044 unsigned char get_resp
[5] = { SIM_CMD_GET_RESPONSE
};
1045 unsigned char resp
[3], buf
[12 + 3 + 2];
1052 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - RAND", _rand
, 16);
1053 if (scard
->sim_type
== SCARD_GSM_SIM
) {
1055 os_memcpy(cmd
+ 5, _rand
, 16);
1057 cmdlen
= 5 + 1 + 16;
1062 os_memcpy(cmd
+ 6, _rand
, 16);
1065 ret
= scard_transmit(scard
, cmd
, cmdlen
, resp
, &len
);
1066 if (ret
!= SCARD_S_SUCCESS
)
1069 if ((scard
->sim_type
== SCARD_GSM_SIM
&&
1070 (len
!= 2 || resp
[0] != 0x9f || resp
[1] != 0x0c)) ||
1071 (scard
->sim_type
== SCARD_USIM
&&
1072 (len
!= 2 || resp
[0] != 0x61 || resp
[1] != 0x0e))) {
1073 wpa_printf(MSG_WARNING
, "SCARD: unexpected response for GSM "
1074 "auth request (len=%d resp=%02x %02x)",
1075 len
, resp
[0], resp
[1]);
1078 get_resp
[4] = resp
[1];
1081 ret
= scard_transmit(scard
, get_resp
, sizeof(get_resp
), buf
, &len
);
1082 if (ret
!= SCARD_S_SUCCESS
)
1085 if (scard
->sim_type
== SCARD_GSM_SIM
) {
1086 if (len
!= 4 + 8 + 2) {
1087 wpa_printf(MSG_WARNING
, "SCARD: unexpected data "
1088 "length for GSM auth (len=%d, expected 14)",
1092 os_memcpy(sres
, buf
, 4);
1093 os_memcpy(kc
, buf
+ 4, 8);
1095 if (len
!= 1 + 4 + 1 + 8 + 2) {
1096 wpa_printf(MSG_WARNING
, "SCARD: unexpected data "
1097 "length for USIM auth (len=%d, "
1098 "expected 16)", len
);
1101 if (buf
[0] != 4 || buf
[5] != 8) {
1102 wpa_printf(MSG_WARNING
, "SCARD: unexpected SREC/Kc "
1103 "length (%d %d, expected 4 8)",
1106 os_memcpy(sres
, buf
+ 1, 4);
1107 os_memcpy(kc
, buf
+ 6, 8);
1110 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - SRES", sres
, 4);
1111 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - Kc", kc
, 8);
1118 * scard_umts_auth - Run UMTS authentication command on USIM card
1119 * @scard: Pointer to private data from scard_init()
1120 * @_rand: 16-byte RAND value from HLR/AuC
1121 * @autn: 16-byte AUTN value from HLR/AuC
1122 * @res: 16-byte buffer for RES
1123 * @res_len: Variable that will be set to RES length
1124 * @ik: 16-byte buffer for IK
1125 * @ck: 16-byte buffer for CK
1126 * @auts: 14-byte buffer for AUTS
1127 * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
1130 * This function performs AKA authentication using USIM card and the provided
1131 * RAND and AUTN values from HLR/AuC. If authentication command can be
1132 * completed successfully, RES, IK, and CK values will be written into provided
1133 * buffers and res_len is set to length of received RES value. If USIM reports
1134 * synchronization failure, the received AUTS value will be written into auts
1135 * buffer. In this case, RES, IK, and CK are not valid.
1137 int scard_umts_auth(struct scard_data
*scard
, const unsigned char *_rand
,
1138 const unsigned char *autn
,
1139 unsigned char *res
, size_t *res_len
,
1140 unsigned char *ik
, unsigned char *ck
, unsigned char *auts
)
1142 unsigned char cmd
[5 + 1 + AKA_RAND_LEN
+ 1 + AKA_AUTN_LEN
] =
1143 { USIM_CMD_RUN_UMTS_ALG
};
1144 unsigned char get_resp
[5] = { USIM_CMD_GET_RESPONSE
};
1145 unsigned char resp
[3], buf
[64], *pos
, *end
;
1152 if (scard
->sim_type
== SCARD_GSM_SIM
) {
1153 wpa_printf(MSG_ERROR
, "SCARD: Non-USIM card - cannot do UMTS "
1158 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS auth - RAND", _rand
, AKA_RAND_LEN
);
1159 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS auth - AUTN", autn
, AKA_AUTN_LEN
);
1160 cmd
[5] = AKA_RAND_LEN
;
1161 os_memcpy(cmd
+ 6, _rand
, AKA_RAND_LEN
);
1162 cmd
[6 + AKA_RAND_LEN
] = AKA_AUTN_LEN
;
1163 os_memcpy(cmd
+ 6 + AKA_RAND_LEN
+ 1, autn
, AKA_AUTN_LEN
);
1166 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), resp
, &len
);
1167 if (ret
!= SCARD_S_SUCCESS
)
1170 if (len
<= sizeof(resp
))
1171 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS alg response", resp
, len
);
1173 if (len
== 2 && resp
[0] == 0x98 && resp
[1] == 0x62) {
1174 wpa_printf(MSG_WARNING
, "SCARD: UMTS auth failed - "
1177 } else if (len
!= 2 || resp
[0] != 0x61) {
1178 wpa_printf(MSG_WARNING
, "SCARD: unexpected response for UMTS "
1179 "auth request (len=%d resp=%02x %02x)",
1180 len
, resp
[0], resp
[1]);
1183 get_resp
[4] = resp
[1];
1186 ret
= scard_transmit(scard
, get_resp
, sizeof(get_resp
), buf
, &len
);
1187 if (ret
!= SCARD_S_SUCCESS
|| len
> sizeof(buf
))
1190 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS get response result", buf
, len
);
1191 if (len
>= 2 + AKA_AUTS_LEN
&& buf
[0] == 0xdc &&
1192 buf
[1] == AKA_AUTS_LEN
) {
1193 wpa_printf(MSG_DEBUG
, "SCARD: UMTS Synchronization-Failure");
1194 os_memcpy(auts
, buf
+ 2, AKA_AUTS_LEN
);
1195 wpa_hexdump(MSG_DEBUG
, "SCARD: AUTS", auts
, AKA_AUTS_LEN
);
1197 } else if (len
>= 6 + IK_LEN
+ CK_LEN
&& buf
[0] == 0xdb) {
1202 if (pos
[0] > RES_MAX_LEN
|| pos
+ pos
[0] > end
) {
1203 wpa_printf(MSG_DEBUG
, "SCARD: Invalid RES");
1207 os_memcpy(res
, pos
, *res_len
);
1209 wpa_hexdump(MSG_DEBUG
, "SCARD: RES", res
, *res_len
);
1212 if (pos
[0] != CK_LEN
|| pos
+ CK_LEN
> end
) {
1213 wpa_printf(MSG_DEBUG
, "SCARD: Invalid CK");
1217 os_memcpy(ck
, pos
, CK_LEN
);
1219 wpa_hexdump(MSG_DEBUG
, "SCARD: CK", ck
, CK_LEN
);
1222 if (pos
[0] != IK_LEN
|| pos
+ IK_LEN
> end
) {
1223 wpa_printf(MSG_DEBUG
, "SCARD: Invalid IK");
1227 os_memcpy(ik
, pos
, IK_LEN
);
1229 wpa_hexdump(MSG_DEBUG
, "SCARD: IK", ik
, IK_LEN
);
1234 wpa_printf(MSG_DEBUG
, "SCARD: Unrecognized response");