pcsc_funcs.c 33 KB

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