1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* 2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM 3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify 6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as 7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation. 8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license. 11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details. 13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM 15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * cards through PC/SC smartcard library. These functions are used to implement 16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * authentication routines for EAP-SIM and EAP-AKA. 17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h" 20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include <winscard.h> 21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h" 23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "pcsc_funcs.h" 24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* See ETSI GSM 11.11 and ETSI TS 102 221 for details. 27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SIM commands: 28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Command APDU: CLA INS P1 P2 P3 Data 29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * CLA (class of instruction): A0 for GSM, 00 for USIM 30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * INS (instruction) 31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * P1 P2 P3 (parameters, P3 = length of Data) 32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Response APDU: Data SW1 SW2 33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SW1 SW2 (Status words) 34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Commands (INS P1 P2 P3): 35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SELECT: A4 00 00 02 <file_id, 2 bytes> 36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * GET RESPONSE: C0 00 00 <len> 37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RUN GSM ALG: 88 00 00 00 <RAND len = 10> 38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN 39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * P1 = ID of alg in card 40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * P2 = ID of secret key 41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * READ BINARY: B0 <offset high> <offset low> <len> 42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * READ RECORD: B2 <record number> <mode> <len> 43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * P2 (mode) = '02' (next record), '03' (previous record), 44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * '04' (absolute mode) 45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * VERIFY CHV: 20 00 <CHV number> 08 46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * CHANGE CHV: 24 00 <CHV number> 10 47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * DISABLE CHV: 26 00 01 08 48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * ENABLE CHV: 28 00 01 08 49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SLEEP: FA 00 00 00 51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* GSM SIM commands */ 54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* USIM commands */ 62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_CLA 0x00 63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SIM_RECORD_MODE_ABSOLUTE 0x04 67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_FSP_TEMPL_TAG 0x62 69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_FILE_DESC 0x82 71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_FILE_ID 0x83 72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_DF_NAME 0x84 73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_PROPR_INFO 0xA5 74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A 75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_FILE_SIZE 0x80 76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_TOTAL_FILE_SIZE 0x81 77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_TLV_SHORT_FILE_ID 0x88 79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define USIM_PS_DO_TAG 0x90 81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define AKA_RAND_LEN 16 83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define AKA_AUTN_LEN 16 84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define AKA_AUTS_LEN 14 85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define RES_MAX_LEN 16 86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define IK_LEN 16 87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define CK_LEN 16 88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidttypedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; 91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct scard_data { 93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCARDCONTEXT ctx; 94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCARDHANDLE card; 95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt DWORD protocol; 96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sim_types sim_type; 97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int pin1_required; 98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}; 99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef __MINGW32_VERSION 101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* MinGW does not yet support WinScard, so load the needed functions 102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * dynamically from winscard.dll for now. */ 103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic HINSTANCE dll = NULL; /* winscard.dll */ 105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; 107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#undef SCARD_PCI_T0 108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) 109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#undef SCARD_PCI_T1 110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) 111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardEstablishContext)(IN DWORD dwScope, 115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCVOID pvReserved1, 116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCVOID pvReserved2, 117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt OUT LPSCARDCONTEXT phContext); 118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardEstablishContext dll_SCardEstablishContext 119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic long (*dll_SCardReleaseContext)(long hContext); 121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardReleaseContext dll_SCardReleaseContext 122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, 125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCSTR mszGroups, 126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt OUT LPSTR mszReaders, 127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN OUT LPDWORD pcchReaders); 128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#undef SCardListReaders 129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardListReaders dll_SCardListReadersA 130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardConnectA)(IN SCARDCONTEXT hContext, 133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCSTR szReader, 134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN DWORD dwShareMode, 135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN DWORD dwPreferredProtocols, 136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt OUT LPSCARDHANDLE phCard, 137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt OUT LPDWORD pdwActiveProtocol); 138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#undef SCardConnect 139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardConnect dll_SCardConnectA 140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardDisconnect)(IN SCARDHANDLE hCard, 143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN DWORD dwDisposition); 144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardDisconnect dll_SCardDisconnect 145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardTransmit)(IN SCARDHANDLE hCard, 148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCSCARD_IO_REQUEST pioSendPci, 149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN LPCBYTE pbSendBuffer, 150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN DWORD cbSendLength, 151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN OUT LPSCARD_IO_REQUEST pioRecvPci, 152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt OUT LPBYTE pbRecvBuffer, 153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt IN OUT LPDWORD pcbRecvLength); 154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardTransmit dll_SCardTransmit 155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); 158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardBeginTransaction dll_SCardBeginTransaction 159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic WINSCARDAPI LONG WINAPI 161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); 162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define SCardEndTransaction dll_SCardEndTransaction 163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int mingw_load_symbols(void) 166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *sym; 168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (dll) 170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dll = LoadLibrary("winscard"); 173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (dll == NULL) { 174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " 175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "library"); 176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define LOADSYM(s) \ 180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sym = #s; \ 181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dll_ ## s = (void *) GetProcAddress(dll, sym); \ 182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (dll_ ## s == NULL) \ 183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto fail; 184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardEstablishContext); 186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardReleaseContext); 187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardListReadersA); 188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardConnectA); 189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardDisconnect); 190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardTransmit); 191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardBeginTransaction); 192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(SCardEndTransaction); 193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(g_rgSCardT0Pci); 194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt LOADSYM(g_rgSCardT1Pci); 195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#undef LOADSYM 197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtfail: 201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " 202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "winscard.dll", sym); 203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt FreeLibrary(dll); 204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dll = NULL; 205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void mingw_unload_symbols(void) 210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (dll == NULL) 212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt FreeLibrary(dll); 215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt dll = NULL; 216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* __MINGW32_VERSION */ 219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define mingw_load_symbols() 0 221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define mingw_unload_symbols() do { } while (0) 222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* __MINGW32_VERSION */ 224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int _scard_select_file(struct scard_data *scard, unsigned short file_id, 227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf, size_t *buf_len, 228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sim_types sim_type, unsigned char *aid, 229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t aidlen); 230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_select_file(struct scard_data *scard, unsigned short file_id, 231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf, size_t *buf_len); 232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_verify_pin(struct scard_data *scard, const char *pin); 233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_get_record_len(struct scard_data *scard, 234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char recnum, unsigned char mode); 235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_read_record(struct scard_data *scard, 236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *data, size_t len, 237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char recnum, unsigned char mode); 238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, 241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int *ps_do, int *file_len) 242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *pos, *end; 244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ps_do) 246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *ps_do = -1; 247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (file_len) 248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *file_len = -1; 249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + buf_len; 252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (*pos != USIM_FSP_TEMPL_TAG) { 253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: file header did not " 254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "start with FSP template tag"); 255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos++; 258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos >= end) 259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((pos + pos[0]) < end) 261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + 1 + pos[0]; 262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos++; 263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", 264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos, end - pos); 265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos + 1 < end) { 267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV " 268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "0x%02x len=%d", pos[0], pos[1]); 269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + 2 + pos[1] > end) 270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] == USIM_TLV_FILE_SIZE && 273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (pos[1] == 1 || pos[1] == 2) && file_len) { 274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[1] == 1) 275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *file_len = (int) pos[2]; 276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *file_len = ((int) pos[2] << 8) | 278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (int) pos[3]; 279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", 280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *file_len); 281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE && 284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && 285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[3] >= 1 && ps_do) { 286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", 287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos[4]); 288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *ps_do = (int) pos[4]; 289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2 + pos[1]; 292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos == end) 294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_pin_needed(struct scard_data *scard, 301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *hdr, size_t hlen) 302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hlen > SCARD_CHV1_OFFSET && 305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) 306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_USIM) { 311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int ps_do; 312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) 313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: there could be more than one PS_DO entry because of 315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * multiple PINs in key reference.. */ 316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ps_do > 0 && (ps_do & 0x80)) 317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_get_aid(struct scard_data *scard, unsigned char *aid, 326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t maxlen) 327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int rlen, rec; 329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct efdir { 330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char appl_template_tag; /* 0x61 */ 331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char appl_template_len; 332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char appl_id_tag; /* 0x4f */ 333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char aid_len; 334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char rid[5]; 335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ 336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } *efdir; 337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char buf[100]; 338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen; 339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir = (struct efdir *) buf; 341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { 343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); 344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); 347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (rec = 1; rec < 10; rec++) { 349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt rlen = scard_get_record_len(scard, rec, 350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SIM_RECORD_MODE_ABSOLUTE); 351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (rlen < 0) { 352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " 353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "record length"); 354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (rlen > (int) blen) { 358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); 359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_read_record(scard, buf, rlen, rec, 362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SIM_RECORD_MODE_ABSOLUTE) < 0) { 363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to read " 364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "EF_DIR record %d", rec); 365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); 368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->appl_template_tag != 0x61) { 370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "template tag 0x%x", 372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir->appl_template_tag); 373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->appl_template_len > rlen - 2) { 377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Too long application " 378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "template (len=%d rlen=%d)", 379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir->appl_template_len, rlen); 380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->appl_id_tag != 0x4f) { 384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " 385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "identifier tag 0x%x", efdir->appl_id_tag); 386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->aid_len < 1 || efdir->aid_len > 16) { 390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", 391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir->aid_len); 392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", 396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir->rid, efdir->aid_len); 397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->appl_code[0] == 0x10 && 399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt efdir->appl_code[1] == 0x02) { 400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " 401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "EF_DIR record %d", rec); 402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (rec >= 10) { 407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " 408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "from EF_DIR records"); 409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (efdir->aid_len > maxlen) { 413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); 414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(aid, efdir->rid, efdir->aid_len); 418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return efdir->aid_len; 420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_init - Initialize SIM/USIM connection using PC/SC 425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sim_type: Allowed SIM types (SIM, USIM, or both) 426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to private data structure, or %NULL on failure 427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function is used to initialize SIM/USIM connection. PC/SC is used to 429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * open connection to the SIM/USIM card and the card is verified to support the 430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * selected sim_type. In addition, local flag is set if a PIN is needed to 431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * access some of the card functions. Once the connection is not needed 432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * anymore, scard_deinit() can be used to close it. 433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct scard_data * scard_init(scard_sim_type sim_type) 435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned long len; 438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct scard_data *scard; 439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_NATIVE_WINDOWS 440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt TCHAR *readers = NULL; 441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CONFIG_NATIVE_WINDOWS */ 442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *readers = NULL; 443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_NATIVE_WINDOWS */ 444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char buf[100]; 445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen; 446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int transaction = 0; 447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int pin_needed; 448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); 450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (mingw_load_symbols()) 451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard = os_zalloc(sizeof(*scard)); 453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard == NULL) 454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, 457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &scard->ctx); 458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " 460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "context (err=%ld)", ret); 461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardListReaders(scard->ctx, NULL, NULL, &len); 465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " 467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(err=%ld)", ret); 468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef UNICODE 472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len *= 2; 473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* UNICODE */ 474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt readers = os_malloc(len); 475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (readers == NULL) { 476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); 477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardListReaders(scard->ctx, NULL, readers, &len); 481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " 483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(err=%ld)", ret); 484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len < 3) { 487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: No smart card readers " 488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "available."); 489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* readers is a list of available reader. Last entry is terminated with 492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * double NUL. 493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * TODO: add support for selecting the reader; now just use the first 494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * one.. */ 495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef UNICODE 496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); 497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* UNICODE */ 498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); 499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* UNICODE */ 500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, 502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); 503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret == (long) SCARD_E_NO_SMARTCARD) 505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "No smart card inserted."); 506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); 508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(readers); 512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt readers = NULL; 513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", 515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned int) scard->card, scard->protocol, 516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); 517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardBeginTransaction(scard->card); 519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " 521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "0x%x", (unsigned int) ret); 522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt transaction = 1; 525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->sim_type = SCARD_GSM_SIM; 529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { 530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); 531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, 532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCARD_USIM, NULL, 0)) { 533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); 534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sim_type == SCARD_USIM_ONLY) 535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM"); 537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->sim_type = SCARD_GSM_SIM; 538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); 540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->sim_type = SCARD_USIM; 541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { 547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); 548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { 553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); 554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char aid[32]; 558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int aid_len; 559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aid_len = scard_get_aid(scard, aid, sizeof(aid)); 561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (aid_len < 0) { 562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " 563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "3G USIM app - try to use standard 3G RID"); 564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); 565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aid_len = 5; 566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); 568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Select based on AID = 3G RID from EF_DIR. This is usually 570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * starting with A0 00 00 00 87. */ 571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, 573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aid, aid_len)) { 574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " 575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "app"); 576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", 577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aid, aid_len); 578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Verify whether CHV1 (PIN1) is needed to access the card. */ 583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pin_needed = scard_pin_needed(scard, buf, blen); 584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pin_needed < 0) { 585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " 586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "is needed"); 587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto failed; 588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pin_needed) { 590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->pin1_required = 1; 591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); 592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " 597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "0x%x", (unsigned int) ret); 598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return scard; 601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtfailed: 603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (transaction) 604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); 605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(readers); 606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard_deinit(scard); 607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands 613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @scard: Pointer to private data from scard_init() 614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pin: PIN code as an ASCII string (e.g., "1234") 615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure 616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint scard_set_pin(struct scard_data *scard, const char *pin) 618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard == NULL) 620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Verify whether CHV1 (PIN1) is needed to access the card. */ 623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->pin1_required) { 624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pin == NULL) { 625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "No PIN configured for SIM " 626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "access"); 627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_verify_pin(scard, pin)) { 630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "PIN verification failed for " 631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "SIM access"); 632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_deinit - Deinitialize SIM/USIM connection 642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @scard: Pointer to private data from scard_init() 643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function closes the SIM/USIM connect opened with scard_init(). 645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid scard_deinit(struct scard_data *scard) 647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard == NULL) 651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); 654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->card) { 655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); 656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " 658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "smart card (err=%ld)", ret); 659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->ctx) { 663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardReleaseContext(scard->ctx); 664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "Failed to release smart card " 666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "context (err=%ld)", ret); 667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(scard); 670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt mingw_unload_symbols(); 671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic long scard_transmit(struct scard_data *scard, 675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *_send, size_t send_len, 676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *_recv, size_t *recv_len) 677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned long rlen; 680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", 682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _send, send_len); 683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt rlen = *recv_len; 684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = SCardTransmit(scard->card, 685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->protocol == SCARD_PROTOCOL_T1 ? 686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt SCARD_PCI_T1 : SCARD_PCI_T0, 687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _send, (unsigned long) send_len, 688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt NULL, _recv, &rlen); 689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *recv_len = rlen; 690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret == SCARD_S_SUCCESS) { 691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", 692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _recv, rlen); 693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(err=0x%lx)", ret); 696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return ret; 698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int _scard_select_file(struct scard_data *scard, unsigned short file_id, 702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf, size_t *buf_len, 703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sim_types sim_type, unsigned char *aid, 704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t aidlen) 705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char resp[3]; 708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[50] = { SIM_CMD_SELECT }; 709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int cmdlen; 710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len, rlen; 712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sim_type == SCARD_USIM) { 714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[3] = 0x04; 716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt get_resp[0] = USIM_CLA; 717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); 720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (aid) { 721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", 722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aid, aidlen); 723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (5 + aidlen > sizeof(cmd)) 724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[2] = 0x04; /* Select by AID */ 726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[4] = aidlen; /* len */ 727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 5, aid, aidlen); 728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmdlen = 5 + aidlen; 729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[5] = file_id >> 8; 731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[6] = file_id & 0xff; 732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmdlen = 7; 733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(resp); 735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " 738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(err=0x%lx)", ret); 739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 2) { 743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " 744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "%d (expected 2)", (int) len); 745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (resp[0] == 0x98 && resp[1] == 0x04) { 749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Security status not satisfied (PIN_WLAN) */ 750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " 751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(PIN_WLAN)"); 752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (resp[0] == 0x6e) { 756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); 757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { 761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " 762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(expected 0x61, 0x6c, or 0x9f)", resp[0]); 763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Normal ending of command; resp[1] bytes available */ 766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt get_resp[4] = resp[1]; 767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", 768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt resp[1]); 769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt rlen = *buf_len; 771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); 772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret == SCARD_S_SUCCESS) { 773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *buf_len = resp[1] < rlen ? resp[1] : rlen; 774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); 778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_select_file(struct scard_data *scard, unsigned short file_id, 783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf, size_t *buf_len) 784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return _scard_select_file(scard, file_id, buf, buf_len, 786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt scard->sim_type, NULL, 0); 787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_get_record_len(struct scard_data *scard, unsigned char recnum, 791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char mode) 792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char buf[255]; 794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen; 796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_USIM) 799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[2] = recnum; 801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[3] = mode; 802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[4] = sizeof(buf); 803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " 808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length for record %d", recnum); 809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", 813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, blen); 814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen < 2 || buf[0] != 0x6c) { 816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " 817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length determination"); 818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return buf[1]; 822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_read_record(struct scard_data *scard, 826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *data, size_t len, 827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char recnum, unsigned char mode) 828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; 830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen = len + 3; 831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf; 832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_USIM) 835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[2] = recnum; 837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[3] = mode; 838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[4] = len; 839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf = os_malloc(blen); 841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf == NULL) 842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen != len + 2) { 850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length %ld (expected %ld)", 852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) blen, (long) len + 2); 853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -3; 855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " 859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "status %02x %02x (expected 90 00)", 860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[len], buf[len + 1]); 861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -4; 863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(data, buf, len); 866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_read_file(struct scard_data *scard, 873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *data, size_t len) 874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; 876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen = len + 3; 877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *buf; 878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[4] = len; 881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf = os_malloc(blen); 883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf == NULL) 884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_USIM) 887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); 889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) { 890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen != len + 2) { 894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length %ld (expected %ld)", 896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) blen, (long) len + 2); 897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -3; 899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf[len] != 0x90 || buf[len + 1] != 0x00) { 902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " 903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "status %02x %02x (expected 90 00)", 904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[len], buf[len + 1]); 905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -4; 907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(data, buf, len); 910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(buf); 911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int scard_verify_pin(struct scard_data *scard, const char *pin) 917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char resp[3]; 920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; 921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len; 922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); 924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pin == NULL || os_strlen(pin) > 8) 926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_USIM) 929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 5, pin, os_strlen(pin)); 931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); 932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(resp); 934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) 936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { 939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); 940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); 944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_get_imsi - Read IMSI from SIM/USIM card 950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @scard: Pointer to private data from scard_init() 951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @imsi: Buffer for IMSI 952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Length of imsi buffer; set to IMSI length on success 953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file 954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * selection returns invalid result code, -3 if parsing FSP template file fails 955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set 956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * to needed length), -5 if reading IMSI file fails. 957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function can be used to read IMSI from the SIM/USIM card. If the IMSI 959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * file is PIN protected, scard_set_pin() must have been used to set the 960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * correct PIN code before calling scard_get_imsi(). 961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) 963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char buf[100]; 965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t blen, imsilen, i; 966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *pos; 967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); 969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = sizeof(buf); 970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) 971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen < 4) { 973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " 974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "header (len=%ld)", (long) blen); 975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = (buf[2] << 8) | buf[3]; 980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int file_size; 982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) 983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -3; 984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt blen = file_size; 985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen < 2 || blen > sizeof(buf)) { 987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", 988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) blen); 989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -3; 990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt imsilen = (blen - 2) * 2 + 1; 993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", 994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) blen, (long) imsilen); 995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (blen < 2 || imsilen > *len) { 996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *len = imsilen; 997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -4; 998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard_read_file(scard, buf, blen)) 1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -5; 1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = imsi; 1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = '0' + (buf[1] >> 4 & 0x0f); 1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (i = 2; i < blen; i++) { 1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char digit; 1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt digit = buf[i] & 0x0f; 1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (digit < 10) 1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = '0' + digit; 1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt imsilen--; 1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt digit = buf[i] >> 4 & 0x0f; 1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (digit < 10) 1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos++ = '0' + digit; 1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt imsilen--; 1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *len = imsilen; 1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_gsm_auth - Run GSM authentication command on SIM card 1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @scard: Pointer to private data from scard_init() 1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @_rand: 16-byte RAND value from HLR/AuC 1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sres: 4-byte buffer for SRES 1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @kc: 8-byte buffer for Kc 1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, 1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * -2 if authentication command execution fails, -3 if unknown response code 1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * for authentication command is received, -4 if reading of response fails, 1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * -5 if if response data is of unexpected length 1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function performs GSM authentication using SIM/USIM card and the 1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * provided RAND value from HLR/AuC. If authentication command can be completed 1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * successfully, SRES and Kc values will be written into sres and kc buffers. 1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, 1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *sres, unsigned char *kc) 1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; 1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int cmdlen; 1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; 1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char resp[3], buf[12 + 3 + 2]; 1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len; 1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard == NULL) 1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); 1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmdlen = 5 + 16; 1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 5, _rand, 16); 1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmdlen = 5 + 1 + 16; 1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[0] = USIM_CLA; 1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[3] = 0x80; 1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[4] = 17; 1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[5] = 16; 1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 6, _rand, 16); 1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(resp); 1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, cmdlen, resp, &len); 1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) 1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((scard->sim_type == SCARD_GSM_SIM && 1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || 1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (scard->sim_type == SCARD_USIM && 1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { 1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " 1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "auth request (len=%ld resp=%02x %02x)", 1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) len, resp[0], resp[1]); 1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -3; 1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt get_resp[4] = resp[1]; 1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(buf); 1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) 1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -4; 1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 4 + 8 + 2) { 1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected data " 1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length for GSM auth (len=%ld, expected 14)", 1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) len); 1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -5; 1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(sres, buf, 4); 1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(kc, buf + 4, 8); 1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 1 + 4 + 1 + 8 + 2) { 1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected data " 1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length for USIM auth (len=%ld, " 1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "expected 16)", (long) len); 1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -5; 1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (buf[0] != 4 || buf[5] != 8) { 1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " 1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length (%d %d, expected 4 8)", 1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[0], buf[5]); 1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(sres, buf + 1, 4); 1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(kc, buf + 6, 8); 1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); 1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); 1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * scard_umts_auth - Run UMTS authentication command on USIM card 1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @scard: Pointer to private data from scard_init() 1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @_rand: 16-byte RAND value from HLR/AuC 1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @autn: 16-byte AUTN value from HLR/AuC 1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @res: 16-byte buffer for RES 1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @res_len: Variable that will be set to RES length 1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ik: 16-byte buffer for IK 1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ck: 16-byte buffer for CK 1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @auts: 14-byte buffer for AUTS 1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization 1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * failure 1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function performs AKA authentication using USIM card and the provided 1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RAND and AUTN values from HLR/AuC. If authentication command can be 1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * completed successfully, RES, IK, and CK values will be written into provided 1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * buffers and res_len is set to length of received RES value. If USIM reports 1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * synchronization failure, the received AUTS value will be written into auts 1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * buffer. In this case, RES, IK, and CK are not valid. 1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, 1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const unsigned char *autn, 1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *res, size_t *res_len, 1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char *ik, unsigned char *ck, unsigned char *auts) 1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = 1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { USIM_CMD_RUN_UMTS_ALG }; 1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; 1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char resp[3], buf[64], *pos, *end; 1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t len; 1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long ret; 1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard == NULL) 1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (scard->sim_type == SCARD_GSM_SIM) { 1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " 1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "auth"); 1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); 1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); 1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[5] = AKA_RAND_LEN; 1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); 1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; 1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); 1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(resp); 1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); 1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS) 1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len <= sizeof(resp)) 1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); 1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { 1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " 1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "MAC != XMAC"); 1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (len != 2 || resp[0] != 0x61) { 1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " 1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "auth request (len=%ld resp=%02x %02x)", 1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (long) len, resp[0], resp[1]); 1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt get_resp[4] = resp[1]; 1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt len = sizeof(buf); 1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); 1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) 1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); 1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && 1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf[1] == AKA_AUTS_LEN) { 1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); 1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(auts, buf + 2, AKA_AUTS_LEN); 1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); 1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -2; 1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { 1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf + 1; 1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = buf + len; 1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* RES */ 1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { 1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); 1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *res_len = *pos++; 1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(res, pos, *res_len); 1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += *res_len; 1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); 1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* CK */ 1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] != CK_LEN || pos + CK_LEN > end) { 1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); 1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos++; 1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(ck, pos, CK_LEN); 1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += CK_LEN; 1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); 1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* IK */ 1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos[0] != IK_LEN || pos + IK_LEN > end) { 1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); 1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos++; 1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(ik, pos, IK_LEN); 1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += IK_LEN; 1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); 1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); 1237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1239