📄 sm_handler.c
字号:
/**
*
* SIM Card Handler for PC/SC lite library
*
* This code was developed by Chris Hessing, using code written by :
*
* Michael Haberler mah@eunet.at
* based on original work by marek@bmlv.gv.at 2000
* make it work with pcsclite-1.0.1: Vincent Guyot <vguyot@inf.enst.fr> 2002-07-12
* some parts Chris Hessing chris.hessing@utah.edu
*
*
* This code is released under dual BSD/GPL license.
*
**********************************************************************
* --- BSD License ---
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* Maryland at College Park and its contributors.
* - Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Smart card handler functions.
*
* \file sm_handler.c
*
* \author chris@open1x.org
*
* \todo Add IPC error events
*
* $Id: sm_handler.c,v 1.19.2.6 2007/04/20 18:35:54 chessing Exp $
* $Date: 2007/04/20 18:35:54 $
**/
/*******************************************************************
*
* The development of the EAP/SIM support was funded by Internet
* Foundation Austria (http://www.nic.at/ipa)
*
*******************************************************************/
/* Interface to Smart Cards using PCSC with 802.1X. */
#ifdef EAP_SIM_ENABLE
#include <stdio.h>
#include <winscard.h>
#include <string.h>
#include <ctype.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include "xsup_debug.h"
#include "xsup_err.h"
#ifdef USE_EFENCE
#include <efence.h>
#endif
// 2G bytecodes
#define SELECT_MF "A0A40000023F00"
#define SELECT_DF_GSM "A0A40000027F20"
#define SELECT_EF_IMSI "A0A40000026F07"
#define RUN_GSM "A088000010"
#define GET_IMSI "A0B0000009"
// 3G bytecodes
#define SELECT_MF_USIM "00A4000C"
#define SELECT_EF_ICCID "00A40004022FE2"
#define SELECT_FCP "00A4000C"
#define SELECT_EFDIR "00A40004022F00"
#define EFDIR_READREC1 "00B20104FF"
#define CHV_RETRIES "0020000100"
#define CHV_UNBLOCK "002C000110"
#define CHV_ATTEMPT "0020000108"
#define USELECT_EF_IMSI "00A40904026F07"
#define READ_IMSI "00B0000009"
#define MODE2G 1
#define MODE3G 0
#define DO_DEBUG 1
#define MAXBUFF 512
typedef unsigned char u8;
/* structure of the EFdir AID (application ID) */
typedef struct t_efdir {
u8 tag61;
u8 length;
u8 tag4f;
u8 aid_len;
/* application identifier value */
u8 rid[5];
u8 app_code[2]; /* 0x1002 for 3G USIM app */
u8 country_code[2];
u8 prov_code[3];
u8 prov_field[4];
u8 tag50;
u8 al_len;
u8 app_label[16]; /* like "Mobilkom Austria", 0xff padded */
} t_efdir;
typedef struct { u8 msk[2], rsp[2], *text; } t_response;
const t_response response[]= {
{ { 0xff, 0xff }, { 0x90, 0x00 } , "Ok" },
{ { 0xff, 0xff }, { 0x98, 0x02 } , "no CHV initialized" },
{ { 0xff, 0xff }, { 0x98, 0x04 } , "access condition not fulfilled" },
{ { 0xff, 0xff }, { 0x98, 0x08 } , "in contradiction with CHV status" },
{ { 0xff, 0xff }, { 0x98, 0x10 } , "in contradiction with invalidation status" },
{ { 0xff, 0xff }, { 0x98, 0x40 } , "unsuccessful CHV verification, no attempts left" },
{ { 0xff, 0xff }, { 0x98, 0x50 } , "decrease cannot be performed, maximum value reached" },
{ { 0xff, 0xff }, { 0x98, 0x62 } , "verify if MAC == XMAC" },
{ { 0xff, 0xff }, { 0x98, 0x64 } , "Service not available" },
{ { 0xff, 0x00 }, { 0x9f, 0x00 } , "%d response bytes available" },
{ { 0xff, 0x00 }, { 0x61, 0x00 } , "%d response bytes available" },
{ { 0xff, 0xff }, { 0x62, 0x00 } , "curent file is already activated" },
{ { 0xff, 0xff }, { 0x62, 0x81 } , "returned data may be corrupt" },
{ { 0xff, 0xff }, { 0x62, 0x82 } , "EOF reached prematurely" },
{ { 0xff, 0xff }, { 0x62, 0x83 } , "selected file invalid" },
{ { 0xff, 0xff }, { 0x62, 0x84 } , "FCI not formated" },
{ { 0xff, 0x00 }, { 0x62, 0x00 } , "nvmem unchanged" },
{ { 0xff, 0x00 }, { 0x63, 0x81 } , "file filled up by last write" },
{ { 0xff, 0xf0 }, { 0x63, 0xc0 } , "Counter=%1.1X" },
{ { 0xff, 0x00 }, { 0x63, 0x00 } , "nvmem changed1" },
{ { 0xff, 0xff }, { 0x64, 0x00 } , "nvmem unchanged or no active application" },
{ { 0xff, 0x00 }, { 0x64, 0x00 } , "nvmem unchanged - RFU" },
{ { 0xff, 0xff }, { 0x65, 0x00 } , "nvmem changed2" },
{ { 0xff, 0xff }, { 0x65, 0x81 } , "nvmem changed - memory failure" },
{ { 0xff, 0x00 }, { 0x65, 0x00 } , "nvmem changed - unknown?" },
{ { 0xff, 0x00 }, { 0x66, 0x00 } , "security related %d" },
{ { 0xff, 0xff }, { 0x67, 0x00 } , "wrong length" },
{ { 0xff, 0x00 }, { 0x67, 0x00 } , "wrong length - %d expected" },
{ { 0xff, 0xff }, { 0x68, 0x81 } , "wrong cla - logical channel not supported" },
{ { 0xff, 0xff }, { 0x68, 0x82 } , "wrong cla - secure messaging not supported" },
{ { 0xff, 0x00 }, { 0x68, 0x00 } , "cla not supported" },
{ { 0xff, 0xff }, { 0x69, 0x81 } , "command incompatible with file structure" },
{ { 0xff, 0xff }, { 0x69, 0x82 } , "security status not satisfied (PIN1)" },
{ { 0xff, 0xff }, { 0x69, 0x83 } , "authentication method blocked - no PIN attempts left" },
{ { 0xff, 0xff }, { 0x69, 0x84 } , "referenced data invalid" },
{ { 0xff, 0xff }, { 0x69, 0x85 } , "conditions of use not satisfied" },
{ { 0xff, 0xff }, { 0x69, 0x86 } , "command not allowed - no current EF" },
{ { 0xff, 0xff }, { 0x69, 0x87 } , "expected SM data objects missing" },
{ { 0xff, 0xff }, { 0x69, 0x88 } , "SM data objects incorrect" },
{ { 0xff, 0x00 }, { 0x69, 0x00 } , "command not allowed" },
{ { 0xff, 0xff }, { 0x6a, 0x80 } , "P1-P2: incorrect parameters in data field" },
{ { 0xff, 0xff }, { 0x6a, 0x81 } , "P1-P2: function not supported" },
{ { 0xff, 0xff }, { 0x6a, 0x82 } , "P1-P2: file/search pattern not found" },
{ { 0xff, 0xff }, { 0x6a, 0x83 } , "P1-P2: record not found" },
{ { 0xff, 0xff }, { 0x6a, 0x84 } , "P1-P2: not enough memory space in file" },
{ { 0xff, 0xff }, { 0x6a, 0x85 } , "P1-P2: Lc inconsistent with TLV" },
{ { 0xff, 0xff }, { 0x6a, 0x86 } , "P1-P2 incorrect (out of range)" },
{ { 0xff, 0xff }, { 0x6a, 0x87 } , "P1-P2 inconsistent with Lc" },
{ { 0xff, 0xff }, { 0x6a, 0x88 } , "verify if EFkeyop exists attached to current file" },
{ { 0xff, 0xff }, { 0x6a, 0x88 } , "Referenced data not found" },
{ { 0xff, 0xff }, { 0x6a, 0x89 } , "File already exists in current DF" },
{ { 0xff, 0x00 }, { 0x6a, 0x00 } , "P1-P2 invalid" },
{ { 0xff, 0x00 }, { 0x6b, 0x00 } , "P1-P2 invalid" },
{ { 0xff, 0x00 }, { 0x6c, 0x00 } , "wrong length - %d expected" },
{ { 0xff, 0x00 }, { 0x6d, 0x00 } , "INS code not supported or invalid" },
{ { 0xff, 0x00 }, { 0x6e, 0x00 } , "CLA %02X not supported" },
{ { 0xff, 0xff }, { 0x6f, 0x01 } , "no active application" },
{ { 0xff, 0xff }, { 0x6f, 0x06 } , "FCP formatting aborted" },
{ { 0xff, 0xff }, { 0x6f, 0x19 } , "no valid key attached to current file" },
{ { 0xff, 0xff }, { 0x6f, 0x00 } , "EF or DF integrity error" },
{ { 0xff, 0xff }, { 0x6f, 0x03 } , "Decrements number of the unblock mechanism (if not 0xff)" },
{ { 0xff, 0xff }, { 0x6f, 0x07 } , "incorrect child number" },
{ { 0xff, 0xff }, { 0x6f, 0x0d } , "Reset PIN/ADM retry counter or disable EFpin or EFadm" },
{ { 0xff, 0xff }, { 0x6f, 0x0e } , "Reset UNBLOCK PIN error counter to maximum value" },
{ { 0xff, 0xff }, { 0x6f, 0x15 } , "PIN/ADM enable/disable not allowed" },
{ { 0xff, 0xff }, { 0x6f, 0x16 } , "incorrect UNBLOCK pin" },
{ { 0xff, 0xff }, { 0x6f, 0x17 } , "number of unblock mechanism is not equal to 0x00" },
{ { 0xff, 0xff }, { 0x6f, 0x1e } , "no data waiting for GET RESPONSE" },
{ { 0xff, 0xff }, { 0x6f, 0x1f } , "File deactivated" },
{ { 0xff, 0xff }, { 0x6f, 0x22 } , "length of search pattern > 128 bytes" },
{ { 0xff, 0x00 }, { 0x6f, 0x00 } , "no precise diagnosis" },
{ { 0x00, 0x00 }, { 0x00, 0x00 } , "Unknown response" }
};
void print_sc_error(long err)
{
switch (err)
{
case SCARD_E_CANCELLED:
debug_printf(DEBUG_NORMAL, "Error : Card Request Cancelled!\n");
break;
case SCARD_E_CANT_DISPOSE:
debug_printf(DEBUG_NORMAL, "Error : Can't dispose (!?)\n");
break;
case SCARD_E_INSUFFICIENT_BUFFER:
debug_printf(DEBUG_NORMAL, "Error : Insufficient Buffer\n");
break;
case SCARD_E_INVALID_ATR:
debug_printf(DEBUG_NORMAL, "Error : Invalid ATR\n");
break;
case SCARD_E_INVALID_HANDLE:
debug_printf(DEBUG_NORMAL, "Error : Invalid handle\n");
break;
case SCARD_E_INVALID_PARAMETER:
debug_printf(DEBUG_NORMAL, "Error : Invalid parameter\n");
break;
case SCARD_E_INVALID_TARGET:
debug_printf(DEBUG_NORMAL, "Error : Invalid target\n");
break;
case SCARD_E_INVALID_VALUE:
debug_printf(DEBUG_NORMAL, "Error : Invalid Value\n");
break;
case SCARD_E_NO_MEMORY:
debug_printf(DEBUG_NORMAL, "Error : No memory\n");
break;
case SCARD_F_COMM_ERROR:
debug_printf(DEBUG_NORMAL, "Error : Communication error \n");
break;
case SCARD_F_INTERNAL_ERROR:
debug_printf(DEBUG_NORMAL, "Error : Internal error\n");
break;
case SCARD_F_WAITED_TOO_LONG:
debug_printf(DEBUG_NORMAL, "Error : Waited too long\n");
break;
case SCARD_E_UNKNOWN_READER:
debug_printf(DEBUG_NORMAL, "Error : Unknown reader\n");
break;
case SCARD_E_TIMEOUT:
debug_printf(DEBUG_NORMAL, "Error : Timeout\n");
break;
case SCARD_E_SHARING_VIOLATION:
debug_printf(DEBUG_NORMAL, "Error : Sharing Violation\n");
break;
case SCARD_E_NO_SMARTCARD:
debug_printf(DEBUG_NORMAL, "Error : No smartcard!\n");
break;
case SCARD_E_UNKNOWN_CARD:
debug_printf(DEBUG_NORMAL, "Error : Unknown card!\n");
break;
case SCARD_E_PROTO_MISMATCH:
debug_printf(DEBUG_NORMAL, "Error : Protocol mismatch!\n");
break;
case SCARD_E_NOT_READY:
debug_printf(DEBUG_NORMAL, "Error : Not ready!\n");
break;
case SCARD_E_SYSTEM_CANCELLED:
debug_printf(DEBUG_NORMAL, "Error : System Cancelled\n");
break;
case SCARD_E_NOT_TRANSACTED:
debug_printf(DEBUG_NORMAL, "Error : Not Transacted\n");
break;
case SCARD_E_READER_UNAVAILABLE:
debug_printf(DEBUG_NORMAL, "Error : Reader unavailable\n");
break;
case SCARD_F_UNKNOWN_ERROR:
default:
debug_printf(DEBUG_NORMAL, "Unknown error!\n");
break;
}
}
int sm_handler_init_ctx(SCARDCONTEXT *card_ctx)
{
long ret;
if (!card_ctx)
{
debug_printf(DEBUG_NORMAL, "Invalid memory location for card context!\n");
return -1;
}
*card_ctx = 0;
ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, card_ctx);
if (ret != SCARD_S_SUCCESS)
{
debug_printf(DEBUG_NORMAL, "Couldn't establish Smart Card context! "
"(Is pcscd loaded?)\n");
print_sc_error(ret);
return -1;
}
return 0;
}
char *sm_handler_get_readers(SCARDCONTEXT *card_ctx)
{
long readerstrlen;
char *readername;
int ret;
ret = SCardListReaders(*card_ctx, NULL, NULL, &readerstrlen);
if (ret != SCARD_S_SUCCESS)
{
debug_printf(DEBUG_NORMAL, "Error requesting list of smart card "
"readers! ");
print_sc_error(ret);
return NULL;
}
readername = (char *)Malloc(readerstrlen+1);
if (readername == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for reader name! "
"(%s:%d)\n", __FUNCTION__, __LINE__);
return NULL;
}
ret = SCardListReaders(*card_ctx, NULL, readername, &readerstrlen);
if (ret != SCARD_S_SUCCESS)
{
debug_printf(DEBUG_NORMAL, "Error requesting list of smart card "
"readers! ");
print_sc_error(ret);
return NULL;
}
return readername;
}
long sm_handler_card_connect(SCARDCONTEXT *card_ctx, SCARDHANDLE *card_hdl,
char *cardreader)
{
long ret, activeprotocol;
debug_printf(DEBUG_NORMAL, "Using reader : %s\n", cardreader);
while (1)
{
ret = SCardConnect(*card_ctx, cardreader, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0, card_hdl, &activeprotocol);
if (ret == SCARD_S_SUCCESS) break;
if (ret == SCARD_E_NO_SMARTCARD)
{
// XXX This should be changed when we attach a GUI to Xsupplicant.
debug_printf(DEBUG_NORMAL, "Please insert a smart card!\n");
sleep(2);
} else {
debug_printf(DEBUG_NORMAL, "Error attempting to connect to the "
"smart card! ");
print_sc_error(ret);
return -1;
break;
}
}
return 0;
}
int sm_handler_wait_card_ready(SCARDHANDLE *card_hdl, int waittime)
{
DWORD dwState, dwProtocol, dwAtrLen, size;
BYTE pbAtr[MAX_ATR_SIZE];
int loopcnt, ret;
LPSTR mszReaders;
loopcnt = 0;
while (1)
{
dwState = 0;
dwProtocol = 0;
dwAtrLen = MAX_ATR_SIZE;
size = 50;
mszReaders = (LPSTR)Malloc(size);
if (mszReaders == NULL)
{
debug_printf(DEBUG_NORMAL, "Error trying to allocate memory for "
"mszReaders! (%s:%d)\n", __FUNCTION__, __LINE__);
return XEMALLOC;
}
memset(&pbAtr, 0x00, MAX_ATR_SIZE);
ret = SCardStatus(*card_hdl, mszReaders, &size, &dwState, &dwProtocol,
pbAtr, &dwAtrLen);
if (ret != SCARD_S_SUCCESS)
{
debug_printf(DEBUG_NORMAL, "Error getting smart card status! ");
print_sc_error(ret);
FREE(mszReaders);
return -1;
}
// XXX We should pass these up to the GUI when we get that going!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -