LCOV - code coverage report
Current view: top level - src/utils - pcsc_funcs.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1388338050 Lines: 3 606 0.5 %
Date: 2013-12-29 Functions: 1 19 5.3 %
Branches: 1 371 0.3 %

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

Generated by: LCOV version 1.9