2 * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
3 * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.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.
25 #include "wpa_supplicant.h"
26 #include "pcsc_funcs.h"
29 /* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
31 * Command APDU: CLA INS P1 P2 P3 Data
32 * CLA (class of instruction): A0 for GSM, 00 for USIM
34 * P1 P2 P3 (parameters, P3 = length of Data)
35 * Response APDU: Data SW1 SW2
36 * SW1 SW2 (Status words)
37 * Commands (INS P1 P2 P3):
38 * SELECT: A4 00 00 02 <file_id, 2 bytes>
39 * GET RESPONSE: C0 00 00 <len>
40 * RUN GSM ALG: 88 00 00 00 <RAND len = 10>
41 * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
42 * P1 = ID of alg in card
43 * P2 = ID of secret key
44 * READ BINARY: B0 <offset high> <offset low> <len>
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_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
62 #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
63 #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
65 #define USIM_FSP_TEMPL_TAG 0x62
67 #define USIM_TLV_FILE_DESC 0x82
68 #define USIM_TLV_FILE_ID 0x83
69 #define USIM_TLV_DF_NAME 0x84
70 #define USIM_TLV_PROPR_INFO 0xA5
71 #define USIM_TLV_LIFE_CYCLE_STATUS 0x8A
72 #define USIM_TLV_FILE_SIZE 0x80
73 #define USIM_TLV_TOTAL_FILE_SIZE 0x81
74 #define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
75 #define USIM_TLV_SHORT_FILE_ID 0x88
77 #define USIM_PS_DO_TAG 0x90
79 #define AKA_RAND_LEN 16
80 #define AKA_AUTN_LEN 16
81 #define AKA_AUTS_LEN 14
82 #define RES_MAX_LEN 16
87 typedef enum { SCARD_GSM_SIM
, SCARD_USIM
} sim_types
;
92 unsigned long protocol
;
98 static int _scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
99 unsigned char *buf
, size_t *buf_len
,
100 sim_types sim_type
, unsigned char *aid
);
101 static int scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
102 unsigned char *buf
, size_t *buf_len
);
103 static int scard_verify_pin(struct scard_data
*scard
, const char *pin
);
106 static int scard_parse_fsp_templ(unsigned char *buf
, size_t buf_len
,
107 int *ps_do
, int *file_len
)
109 unsigned char *pos
, *end
;
118 if (*pos
!= USIM_FSP_TEMPL_TAG
) {
119 wpa_printf(MSG_DEBUG
, "SCARD: file header did not "
120 "start with FSP template tag");
126 if ((pos
+ pos
[0]) < end
)
127 end
= pos
+ 1 + pos
[0];
129 wpa_hexdump(MSG_DEBUG
, "SCARD: file header FSP template",
132 while (pos
+ 1 < end
) {
133 wpa_printf(MSG_MSGDUMP
, "SCARD: file header TLV "
134 "0x%02x len=%d", pos
[0], pos
[1]);
135 if (pos
+ 2 + pos
[1] > end
)
138 if (pos
[0] == USIM_TLV_FILE_SIZE
&&
139 (pos
[1] == 1 || pos
[1] == 2) && file_len
) {
141 *file_len
= (int) pos
[2];
143 *file_len
= ((int) pos
[2] << 8) |
145 wpa_printf(MSG_DEBUG
, "SCARD: file_size=%d",
149 if (pos
[0] == USIM_TLV_PIN_STATUS_TEMPLATE
&&
150 pos
[1] >= 2 && pos
[2] == USIM_PS_DO_TAG
&&
151 pos
[3] >= 1 && ps_do
) {
152 wpa_printf(MSG_DEBUG
, "SCARD: PS_DO=0x%02x",
154 *ps_do
= (int) pos
[4];
166 static int scard_pin_needed(struct scard_data
*scard
,
167 unsigned char *hdr
, size_t hlen
)
169 if (scard
->sim_type
== SCARD_GSM_SIM
) {
170 if (hlen
> SCARD_CHV1_OFFSET
&&
171 !(hdr
[SCARD_CHV1_OFFSET
] & SCARD_CHV1_FLAG
))
176 if (scard
->sim_type
== SCARD_USIM
) {
178 if (scard_parse_fsp_templ(hdr
, hlen
, &ps_do
, NULL
))
180 /* TODO: there could be more than one PS_DO entry because of
181 * multiple PINs in key reference.. */
191 * scard_init - Initialize SIM/USIM connection using PC/SC
192 * @sim_type: Allowed SIM types (SIM, USIM, or both)
193 * Returns: Pointer to private data structure, or %NULL on failure
195 * This function is used to initialize SIM/USIM connection. PC/SC is used to
196 * open connection to the SIM/USIM card and the card is verified to support the
197 * selected sim_type. In addition, local flag is set if a PIN is needed to
198 * access some of the card functions. Once the connection is not needed
199 * anymore, scard_deinit() can be used to close it.
201 struct scard_data
* scard_init(scard_sim_type sim_type
)
204 struct scard_data
*scard
;
205 char *readers
= NULL
;
209 wpa_printf(MSG_DEBUG
, "SCARD: initializing smart card interface");
210 scard
= malloc(sizeof(*scard
));
213 memset(scard
, 0, sizeof(*scard
));
215 ret
= SCardEstablishContext(SCARD_SCOPE_SYSTEM
, NULL
, NULL
,
217 if (ret
!= SCARD_S_SUCCESS
) {
218 wpa_printf(MSG_DEBUG
, "SCARD: Could not establish smart card "
219 "context (err=%ld)", ret
);
223 ret
= SCardListReaders(scard
->ctx
, NULL
, NULL
, &len
);
224 if (ret
!= SCARD_S_SUCCESS
) {
225 wpa_printf(MSG_DEBUG
, "SCARD: SCardListReaders failed "
230 readers
= malloc(len
);
231 if (readers
== NULL
) {
232 printf("malloc failed\n");
236 ret
= SCardListReaders(scard
->ctx
, NULL
, readers
, &len
);
237 if (ret
!= SCARD_S_SUCCESS
) {
238 wpa_printf(MSG_DEBUG
, "SCARD: SCardListReaders failed(2) "
243 wpa_printf(MSG_WARNING
, "SCARD: No smart card readers "
247 /* readers is a list of available reader. Last entry is terminated with
249 * TODO: add support for selecting the reader; now just use the first
251 wpa_printf(MSG_DEBUG
, "SCARD: Selected reader='%s'", readers
);
253 ret
= SCardConnect(scard
->ctx
, readers
, SCARD_SHARE_SHARED
,
254 SCARD_PROTOCOL_T0
, &scard
->card
, &scard
->protocol
);
255 if (ret
!= SCARD_S_SUCCESS
) {
256 if (ret
== SCARD_E_NO_SMARTCARD
)
257 wpa_printf(MSG_INFO
, "No smart card inserted.");
259 wpa_printf(MSG_WARNING
, "SCardConnect err=%lx", ret
);
266 wpa_printf(MSG_DEBUG
, "SCARD: card=%ld active_protocol=%lu",
267 scard
->card
, scard
->protocol
);
271 scard
->sim_type
= SCARD_GSM_SIM
;
272 if (sim_type
== SCARD_USIM_ONLY
|| sim_type
== SCARD_TRY_BOTH
) {
273 wpa_printf(MSG_DEBUG
, "SCARD: verifying USIM support");
274 if (_scard_select_file(scard
, SCARD_FILE_MF
, buf
, &blen
,
276 wpa_printf(MSG_DEBUG
, "SCARD: USIM is not supported");
277 if (sim_type
== SCARD_USIM_ONLY
)
279 wpa_printf(MSG_DEBUG
, "SCARD: Trying to use GSM SIM");
280 scard
->sim_type
= SCARD_GSM_SIM
;
282 wpa_printf(MSG_DEBUG
, "SCARD: USIM is supported");
283 scard
->sim_type
= SCARD_USIM
;
287 if (scard
->sim_type
== SCARD_GSM_SIM
) {
289 if (scard_select_file(scard
, SCARD_FILE_MF
, buf
, &blen
)) {
290 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read MF");
295 if (scard_select_file(scard
, SCARD_FILE_GSM_DF
, buf
, &blen
)) {
296 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read GSM DF");
300 /* Select based on AID = 3G RID */
302 if (_scard_select_file(scard
, 0, buf
, &blen
, scard
->sim_type
,
303 "\xA0\x00\x00\x00\x87")) {
304 wpa_printf(MSG_DEBUG
, "SCARD: Failed to read 3G RID "
310 /* Verify whether CHV1 (PIN1) is needed to access the card. */
311 if (scard_pin_needed(scard
, buf
, blen
)) {
312 scard
->pin1_required
= 1;
313 wpa_printf(MSG_DEBUG
, "PIN1 needed for SIM access");
326 * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
327 * @scard: Pointer to private data from scard_init()
328 * pin: PIN code as an ASCII string (e.g., "1234")
329 * Returns: 0 on success, -1 on failure
331 int scard_set_pin(struct scard_data
*scard
, const char *pin
)
336 /* Verify whether CHV1 (PIN1) is needed to access the card. */
337 if (scard
->pin1_required
) {
339 wpa_printf(MSG_DEBUG
, "No PIN configured for SIM "
343 if (scard_verify_pin(scard
, pin
)) {
344 wpa_printf(MSG_INFO
, "PIN verification failed for "
355 * scard_deinit - Deinitialize SIM/USIM connection
356 * @scard: Pointer to private data from scard_init()
358 * This function closes the SIM/USIM connect opened with scard_init().
360 void scard_deinit(struct scard_data
*scard
)
367 wpa_printf(MSG_DEBUG
, "SCARD: deinitializing smart card interface");
369 ret
= SCardDisconnect(scard
->card
, SCARD_UNPOWER_CARD
);
370 if (ret
!= SCARD_S_SUCCESS
) {
371 wpa_printf(MSG_DEBUG
, "SCARD: Failed to disconnect "
372 "smart card (err=%ld)", ret
);
377 ret
= SCardReleaseContext(scard
->ctx
);
378 if (ret
!= SCARD_S_SUCCESS
) {
379 wpa_printf(MSG_DEBUG
, "Failed to release smart card "
380 "context (err=%ld)", ret
);
387 static long scard_transmit(struct scard_data
*scard
,
388 unsigned char *send
, size_t send_len
,
389 unsigned char *recv
, size_t *recv_len
)
394 wpa_hexdump_key(MSG_DEBUG
, "SCARD: scard_transmit: send",
397 ret
= SCardTransmit(scard
->card
,
398 scard
->protocol
== SCARD_PROTOCOL_T1
?
399 SCARD_PCI_T1
: SCARD_PCI_T0
,
400 send
, (unsigned long) send_len
,
403 if (ret
== SCARD_S_SUCCESS
) {
404 wpa_hexdump(MSG_DEBUG
, "SCARD: scard_transmit: recv",
407 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit failed "
414 static int _scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
415 unsigned char *buf
, size_t *buf_len
,
416 sim_types sim_type
, unsigned char *aid
)
419 unsigned char resp
[3];
420 unsigned char cmd
[10] = { SIM_CMD_SELECT
};
422 unsigned char get_resp
[5] = { SIM_CMD_GET_RESPONSE
};
425 if (sim_type
== SCARD_USIM
) {
428 get_resp
[0] = USIM_CLA
;
431 wpa_printf(MSG_DEBUG
, "SCARD: select file %04x", file_id
);
433 cmd
[2] = 0x04; /* Select by AID */
434 cmd
[4] = 5; /* len */
435 memcpy(cmd
+ 5, aid
, 5);
438 cmd
[5] = file_id
>> 8;
439 cmd
[6] = file_id
& 0xff;
443 ret
= scard_transmit(scard
, cmd
, cmdlen
, resp
, &len
);
444 if (ret
!= SCARD_S_SUCCESS
) {
445 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit failed "
451 wpa_printf(MSG_WARNING
, "SCARD: unexpected resp len "
452 "%d (expected 2)", (int) len
);
456 if (resp
[0] == 0x98 && resp
[1] == 0x04) {
457 /* Security status not satisfied (PIN_WLAN) */
458 wpa_printf(MSG_WARNING
, "SCARD: Security status not satisfied "
463 if (resp
[0] == 0x6e) {
464 wpa_printf(MSG_DEBUG
, "SCARD: used CLA not supported");
468 if (resp
[0] != 0x6c && resp
[0] != 0x9f && resp
[0] != 0x61) {
469 wpa_printf(MSG_WARNING
, "SCARD: unexpected response 0x%02x "
470 "(expected 0x61, 0x6c, or 0x9f)", resp
[0]);
473 /* Normal ending of command; resp[1] bytes available */
474 get_resp
[4] = resp
[1];
475 wpa_printf(MSG_DEBUG
, "SCARD: trying to get response (%d bytes)",
479 ret
= scard_transmit(scard
, get_resp
, sizeof(get_resp
), buf
, &rlen
);
480 if (ret
== SCARD_S_SUCCESS
) {
481 *buf_len
= resp
[1] < rlen
? resp
[1] : rlen
;
485 wpa_printf(MSG_WARNING
, "SCARD: SCardTransmit err=0x%lx\n", ret
);
490 static int scard_select_file(struct scard_data
*scard
, unsigned short file_id
,
491 unsigned char *buf
, size_t *buf_len
)
493 return _scard_select_file(scard
, file_id
, buf
, buf_len
,
494 scard
->sim_type
, NULL
);
498 static int scard_read_file(struct scard_data
*scard
,
499 unsigned char *data
, size_t len
)
501 char cmd
[5] = { SIM_CMD_READ_BIN
, len
};
502 size_t blen
= len
+ 3;
510 if (scard
->sim_type
== SCARD_USIM
)
512 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), buf
, &blen
);
513 if (ret
!= SCARD_S_SUCCESS
) {
517 if (blen
!= len
+ 2) {
518 wpa_printf(MSG_DEBUG
, "SCARD: file read returned unexpected "
519 "length %d (expected %d)", blen
, len
+ 2);
524 if (buf
[len
] != 0x90 || buf
[len
+ 1] != 0x00) {
525 wpa_printf(MSG_DEBUG
, "SCARD: file read returned unexpected "
526 "status %02x %02x (expected 90 00)",
527 buf
[len
], buf
[len
+ 1]);
532 memcpy(data
, buf
, len
);
539 static int scard_verify_pin(struct scard_data
*scard
, const char *pin
)
542 unsigned char resp
[3];
543 char cmd
[5 + 8] = { SIM_CMD_VERIFY_CHV1
};
546 wpa_printf(MSG_DEBUG
, "SCARD: verifying PIN");
548 if (pin
== NULL
|| strlen(pin
) > 8)
551 if (scard
->sim_type
== SCARD_USIM
)
553 memcpy(cmd
+ 5, pin
, strlen(pin
));
554 memset(cmd
+ 5 + strlen(pin
), 0xff, 8 - strlen(pin
));
557 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), resp
, &len
);
558 if (ret
!= SCARD_S_SUCCESS
)
561 if (len
!= 2 || resp
[0] != 0x90 || resp
[1] != 0x00) {
562 wpa_printf(MSG_WARNING
, "SCARD: PIN verification failed");
566 wpa_printf(MSG_DEBUG
, "SCARD: PIN verified successfully");
572 * scard_get_imsi - Read IMSI from SIM/USIM card
573 * @scard: Pointer to private data from scard_init()
574 * @imsi: Buffer for IMSI
575 * @len: Length of imsi buffer; set to IMSI length on success
576 * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
577 * selection returns invalid result code, -3 if parsing FSP template file fails
578 * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
579 * to needed length), -5 if reading IMSI file fails.
581 * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
582 * file is PIN protected, scard_set_pin() must have been used to set the
583 * correct PIN code before calling scard_get_imsi().
585 int scard_get_imsi(struct scard_data
*scard
, char *imsi
, size_t *len
)
588 size_t blen
, imsilen
;
592 wpa_printf(MSG_DEBUG
, "SCARD: reading IMSI from (GSM) EF-IMSI");
594 if (scard_select_file(scard
, SCARD_FILE_GSM_EF_IMSI
, buf
, &blen
))
597 wpa_printf(MSG_WARNING
, "SCARD: too short (GSM) EF-IMSI "
598 "header (len=%d)", blen
);
602 if (scard
->sim_type
== SCARD_GSM_SIM
) {
603 blen
= (buf
[2] << 8) | buf
[3];
606 if (scard_parse_fsp_templ(buf
, blen
, NULL
, &file_size
))
610 if (blen
< 2 || blen
> sizeof(buf
)) {
611 wpa_printf(MSG_DEBUG
, "SCARD: invalid IMSI file length=%d",
616 imsilen
= (blen
- 2) * 2 + 1;
617 wpa_printf(MSG_DEBUG
, "SCARD: IMSI file length=%d imsilen=%d",
619 if (blen
< 2 || imsilen
> *len
) {
624 if (scard_read_file(scard
, buf
, blen
))
628 *pos
++ = '0' + (buf
[1] >> 4 & 0x0f);
629 for (i
= 2; i
< blen
; i
++) {
632 digit
= buf
[i
] & 0x0f;
634 *pos
++ = '0' + digit
;
638 digit
= buf
[i
] >> 4 & 0x0f;
640 *pos
++ = '0' + digit
;
651 * scard_gsm_auth - Run GSM authentication command on SIM card
652 * @scard: Pointer to private data from scard_init()
653 * @rand: 16-byte RAND value from HLR/AuC
654 * @sres: 4-byte buffer for SRES
655 * @kc: 8-byte buffer for Kc
656 * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
657 * -2 if authentication command execution fails, -3 if unknown response code
658 * for authentication command is received, -4 if reading of response fails,
659 * -5 if if response data is of unexpected length
661 * This function performs GSM authentication using SIM/USIM card and the
662 * provided RAND value from HLR/AuC. If authentication command can be completed
663 * successfully, SRES and Kc values will be written into sres and kc buffers.
665 int scard_gsm_auth(struct scard_data
*scard
, const unsigned char *rand
,
666 unsigned char *sres
, unsigned char *kc
)
668 unsigned char cmd
[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG
};
670 unsigned char get_resp
[5] = { SIM_CMD_GET_RESPONSE
};
671 unsigned char resp
[3], buf
[12 + 3 + 2];
678 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - RAND", rand
, 16);
679 if (scard
->sim_type
== SCARD_GSM_SIM
) {
681 memcpy(cmd
+ 5, rand
, 16);
688 memcpy(cmd
+ 6, rand
, 16);
691 ret
= scard_transmit(scard
, cmd
, cmdlen
, resp
, &len
);
692 if (ret
!= SCARD_S_SUCCESS
)
695 if ((scard
->sim_type
== SCARD_GSM_SIM
&&
696 (len
!= 2 || resp
[0] != 0x9f || resp
[1] != 0x0c)) ||
697 (scard
->sim_type
== SCARD_USIM
&&
698 (len
!= 2 || resp
[0] != 0x61 || resp
[1] != 0x0e))) {
699 wpa_printf(MSG_WARNING
, "SCARD: unexpected response for GSM "
700 "auth request (len=%d resp=%02x %02x)",
701 len
, resp
[0], resp
[1]);
704 get_resp
[4] = resp
[1];
707 ret
= scard_transmit(scard
, get_resp
, sizeof(get_resp
), buf
, &len
);
708 if (ret
!= SCARD_S_SUCCESS
)
711 if (scard
->sim_type
== SCARD_GSM_SIM
) {
712 if (len
!= 4 + 8 + 2) {
713 wpa_printf(MSG_WARNING
, "SCARD: unexpected data "
714 "length for GSM auth (len=%d, expected 14)",
718 memcpy(sres
, buf
, 4);
719 memcpy(kc
, buf
+ 4, 8);
721 if (len
!= 1 + 4 + 1 + 8 + 2) {
722 wpa_printf(MSG_WARNING
, "SCARD: unexpected data "
723 "length for USIM auth (len=%d, "
724 "expected 16)", len
);
727 if (buf
[0] != 4 || buf
[5] != 8) {
728 wpa_printf(MSG_WARNING
, "SCARD: unexpected SREC/Kc "
729 "length (%d %d, expected 4 8)",
732 memcpy(sres
, buf
+ 1, 4);
733 memcpy(kc
, buf
+ 6, 8);
736 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - SRES", sres
, 4);
737 wpa_hexdump(MSG_DEBUG
, "SCARD: GSM auth - Kc", kc
, 8);
744 * scard_umts_auth - Run UMTS authentication command on USIM card
745 * @scard: Pointer to private data from scard_init()
746 * @rand: 16-byte RAND value from HLR/AuC
747 * @autn: 16-byte AUTN value from HLR/AuC
748 * @res: 16-byte buffer for RES
749 * @res_len: Variable that will be set to RES length
750 * @ik: 16-byte buffer for IK
751 * @ck: 16-byte buffer for CK
752 * @auts: 14-byte buffer for AUTS
753 * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
756 * This function performs AKA authentication using USIM card and the provided
757 * RAND and AUTN values from HLR/AuC. If authentication command can be
758 * completed successfully, RES, IK, and CK values will be written into provided
759 * buffers and res_len is set to length of received RES value. If USIM reports
760 * synchronization failure, the received AUTS value will be written into auts
761 * buffer. In this case, RES, IK, and CK are not valid.
763 int scard_umts_auth(struct scard_data
*scard
, const unsigned char *rand
,
764 const unsigned char *autn
,
765 unsigned char *res
, size_t *res_len
,
766 unsigned char *ik
, unsigned char *ck
, unsigned char *auts
)
768 unsigned char cmd
[5 + 1 + AKA_RAND_LEN
+ 1 + AKA_AUTN_LEN
] =
769 { USIM_CMD_RUN_UMTS_ALG
};
771 unsigned char get_resp
[5] = { USIM_CMD_GET_RESPONSE
};
772 unsigned char resp
[3], buf
[64], *pos
, *end
;
779 if (scard
->sim_type
== SCARD_GSM_SIM
) {
780 wpa_printf(MSG_ERROR
, "SCARD: Non-USIM card - cannot do UMTS "
785 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS auth - RAND", rand
, AKA_RAND_LEN
);
786 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS auth - AUTN", autn
, AKA_AUTN_LEN
);
787 cmdlen
= 5 + 1 + AKA_RAND_LEN
+ 1 + AKA_AUTN_LEN
;
788 cmd
[5] = AKA_RAND_LEN
;
789 memcpy(cmd
+ 6, rand
, AKA_RAND_LEN
);
790 cmd
[6 + AKA_RAND_LEN
] = AKA_AUTN_LEN
;
791 memcpy(cmd
+ 6 + AKA_RAND_LEN
+ 1, autn
, AKA_AUTN_LEN
);
794 ret
= scard_transmit(scard
, cmd
, sizeof(cmd
), resp
, &len
);
795 if (ret
!= SCARD_S_SUCCESS
)
798 if (len
>= 0 && len
<= sizeof(resp
))
799 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS alg response", resp
, len
);
801 if (len
== 2 && resp
[0] == 0x98 && resp
[1] == 0x62) {
802 wpa_printf(MSG_WARNING
, "SCARD: UMTS auth failed - "
805 } else if (len
!= 2 || resp
[0] != 0x61) {
806 wpa_printf(MSG_WARNING
, "SCARD: unexpected response for UMTS "
807 "auth request (len=%d resp=%02x %02x)",
808 len
, resp
[0], resp
[1]);
811 get_resp
[4] = resp
[1];
814 ret
= scard_transmit(scard
, get_resp
, sizeof(get_resp
), buf
, &len
);
815 if (ret
!= SCARD_S_SUCCESS
|| len
< 0 || len
> sizeof(buf
))
818 wpa_hexdump(MSG_DEBUG
, "SCARD: UMTS get response result", buf
, len
);
819 if (len
>= 2 + AKA_AUTS_LEN
&& buf
[0] == 0xdc &&
820 buf
[1] == AKA_AUTS_LEN
) {
821 wpa_printf(MSG_DEBUG
, "SCARD: UMTS Synchronization-Failure");
822 memcpy(auts
, buf
+ 2, AKA_AUTS_LEN
);
823 wpa_hexdump(MSG_DEBUG
, "SCARD: AUTS", auts
, AKA_AUTS_LEN
);
825 } else if (len
>= 6 + IK_LEN
+ CK_LEN
&& buf
[0] == 0xdb) {
830 if (pos
[0] > RES_MAX_LEN
|| pos
+ pos
[0] > end
) {
831 wpa_printf(MSG_DEBUG
, "SCARD: Invalid RES");
835 memcpy(res
, pos
, *res_len
);
837 wpa_hexdump(MSG_DEBUG
, "SCARD: RES", res
, *res_len
);
840 if (pos
[0] != CK_LEN
|| pos
+ CK_LEN
> end
) {
841 wpa_printf(MSG_DEBUG
, "SCARD: Invalid CK");
845 memcpy(ck
, pos
, CK_LEN
);
847 wpa_hexdump(MSG_DEBUG
, "SCARD: CK", ck
, CK_LEN
);
850 if (pos
[0] != IK_LEN
|| pos
+ IK_LEN
> end
) {
851 wpa_printf(MSG_DEBUG
, "SCARD: Invalid IK");
855 memcpy(ik
, pos
, IK_LEN
);
857 wpa_hexdump(MSG_DEBUG
, "SCARD: IK", ik
, IK_LEN
);
862 wpa_printf(MSG_DEBUG
, "SCARD: Unrecognized response");