// Copyright(C): Advanced Card Systems Ltd // // File: SLE4432_4442Dlg.pas // // Description: This sample program outlines the steps on how to // program SLE4432/4442 memory cards using ACS readers // in PC/SC platform. // // Author: Jose Isagani R. Mission // // Date: June 25, 2004 // // Revision Trail: (Date/Author/Description) // //====================================================================== // SLE4432_4442Dlg.cpp : implementation file // #include "stdafx.h" #include "SLE4432_4442.h" #include "SLE4432_4442Dlg.h" // ========================================================================== // SLE4432_4442Dlg include file #include "Winscard.h" // SLE4432_4442Dlg GlobalVariables SCARDCONTEXT hContext; SCARDHANDLE hCard; unsigned long dwActProtocol; LPCBYTE pbSend; DWORD dwSend, dwRecv, size = 64; LPBYTE pbRecv; SCARD_IO_REQUEST ioRequest; int retCode; char readerName [256]; DWORD SendLen, RecvLen, nBytesRet; CmdBytes apdu; BYTE SendBuff[262], RecvBuff[262]; BOOL connActive; CSLE4432_4442Dlg *pThis=NULL; // ========================================================================== #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSLE4432_4442Dlg dialog CSLE4432_4442Dlg::CSLE4432_4442Dlg(CWnd* pParent /*=NULL*/) : CDialog(CSLE4432_4442Dlg::IDD, pParent) { //{{AFX_DATA_INIT(CSLE4432_4442Dlg) //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1); } void CSLE4432_4442Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSLE4432_4442Dlg) DDX_Control(pDX, IDC_BUTTON4, bChange); DDX_Control(pDX, IDC_BUTTON6, bWriteProt); DDX_Control(pDX, IDC_EDIT1, tAdd); DDX_Control(pDX, IDC_RADIO1, rbSLE4432); DDX_Control(pDX, IDC_COMBO1, cbReader); DDX_Control(pDX, IDC_LIST1, mMsg); DDX_Control(pDX, IDC_EDIT4, tData); DDX_Control(pDX, IDC_EDIT3, tLen); DDX_Control(pDX, IDC_BUTTON9, bReset); DDX_Control(pDX, IDC_BUTTON8, bErrCtr); DDX_Control(pDX, IDC_BUTTON7, bSubmit); DDX_Control(pDX, IDC_BUTTON5, bWrite); DDX_Control(pDX, IDC_BUTTON3, bRead); DDX_Control(pDX, IDC_BUTTON2, bConnect); DDX_Control(pDX, IDC_BUTTON10, bQuit); DDX_Control(pDX, IDC_BUTTON1, bInit); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CSLE4432_4442Dlg, CDialog) //{{AFX_MSG_MAP(CSLE4432_4442Dlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, OnInit) ON_BN_CLICKED(IDC_BUTTON9, OnReset) ON_BN_CLICKED(IDC_BUTTON10, OnQuit) ON_BN_CLICKED(IDC_BUTTON2, OnConnect) ON_BN_CLICKED(IDC_RADIO1, OnSLE4418) ON_CBN_EDITCHANGE(IDC_COMBO1, OnEditchangeCombo1) ON_BN_CLICKED(IDC_RADIO2, OnSLE4428) ON_BN_CLICKED(IDC_BUTTON3, OnRead) ON_BN_CLICKED(IDC_BUTTON4, OnReadProt) ON_BN_CLICKED(IDC_BUTTON5, OnWrite) ON_BN_CLICKED(IDC_BUTTON7, OnSubmit) ON_BN_CLICKED(IDC_BUTTON8, OnErrCtr) ON_BN_CLICKED(IDC_BUTTON6, OnWriteProt) ON_CBN_SELCHANGE(IDC_COMBO1, OnSelchangeCombo1) //}}AFX_MSG_MAP END_MESSAGE_MAP() // ========================================================================== // SLE4432_4442Dlg internal routines static CString GetScardErrMsg(int code) { switch(code) { // Smartcard Reader interface errors case SCARD_E_CANCELLED: return ("The action was canceled by an SCardCancel request."); break; case SCARD_E_CANT_DISPOSE: return ("The system could not dispose of the media in the requested manner."); break; case SCARD_E_CARD_UNSUPPORTED: return ("The smart card does not meet minimal requirements for support."); break; case SCARD_E_DUPLICATE_READER: return ("The reader driver didn't produce a unique reader name."); break; case SCARD_E_INSUFFICIENT_BUFFER: return ("The data buffer for returned data is too small for the returned data."); break; case SCARD_E_INVALID_ATR: return ("An ATR string obtained from the registry is not a valid ATR string."); break; case SCARD_E_INVALID_HANDLE: return ("The supplied handle was invalid."); break; case SCARD_E_INVALID_PARAMETER: return ("One or more of the supplied parameters could not be properly interpreted."); break; case SCARD_E_INVALID_TARGET: return ("Registry startup information is missing or invalid."); break; case SCARD_E_INVALID_VALUE: return ("One or more of the supplied parameter values could not be properly interpreted."); break; case SCARD_E_NOT_READY: return ("The reader or card is not ready to accept commands."); break; case SCARD_E_NOT_TRANSACTED: return ("An attempt was made to end a non-existent transaction."); break; case SCARD_E_NO_MEMORY: return ("Not enough memory available to complete this command."); break; case SCARD_E_NO_SERVICE: return ("The smart card resource manager is not running."); break; case SCARD_E_NO_SMARTCARD: return ("The operation requires a smart card, but no smart card is currently in the device."); break; case SCARD_E_PCI_TOO_SMALL: return ("The PCI receive buffer was too small."); break; case SCARD_E_PROTO_MISMATCH: return ("The requested protocols are incompatible with the protocol currently in use with the card."); break; case SCARD_E_READER_UNAVAILABLE: return ("The specified reader is not currently available for use."); break; case SCARD_E_READER_UNSUPPORTED: return ("The reader driver does not meet minimal requirements for support."); break; case SCARD_E_SERVICE_STOPPED: return ("The smart card resource manager has shut down."); break; case SCARD_E_SHARING_VIOLATION: return ("The smart card cannot be accessed because of other outstanding connections."); break; case SCARD_E_SYSTEM_CANCELLED: return ("The action was canceled by the system, presumably to log off or shut down."); break; case SCARD_E_TIMEOUT: return ("The user-specified timeout value has expired."); break; case SCARD_E_UNKNOWN_CARD: return ("The specified smart card name is not recognized."); break; case SCARD_E_UNKNOWN_READER: return ("The specified reader name is not recognized."); break; case SCARD_F_COMM_ERROR: return ("An internal communications error has been detected."); break; case SCARD_F_INTERNAL_ERROR: return ("An internal consistency check failed."); break; case SCARD_F_UNKNOWN_ERROR: return ("An internal error has been detected, but the source is unknown."); break; case SCARD_F_WAITED_TOO_LONG: return ("An internal consistency timer has expired."); break; case SCARD_W_REMOVED_CARD: return ("The smart card has been removed and no further communication is possible."); break; case SCARD_W_RESET_CARD: return ("The smart card has been reset, so any shared state information is invalid."); break; case SCARD_W_UNPOWERED_CARD: return ("Power has been removed from the smart card and no further communication is possible."); break; case SCARD_W_UNRESPONSIVE_CARD: return ("The smart card is not responding to a reset."); break; case SCARD_W_UNSUPPORTED_CARD: return ("The reader cannot communicate with the card due to ATR string configuration conflicts."); break; case NO_READER_INSTALLED: return ("The smartcard reader is not installed in your system."); break; } return ("Error is not documented."); } void ClearBuffers() { int indx; for (indx = 0;indx<263;indx++) { SendBuff[indx] = 0x00; RecvBuff[indx] = 0x00; } } void ClearFields() { pThis->tAdd.SetWindowText(""); pThis->tLen.SetWindowText(""); pThis->tData.SetWindowText(""); } void EnableFields() { pThis->tAdd.EnableWindow(TRUE); pThis->tAdd.SetLimitText(2); pThis->tLen.EnableWindow(TRUE); pThis->tLen.SetLimitText(2); pThis->tData.EnableWindow(TRUE); } void DisableFields() { pThis->tAdd.EnableWindow(FALSE); pThis->tLen.EnableWindow(FALSE); pThis->tData.EnableWindow(FALSE); } void InitMenu() { pThis->cbReader.ResetContent(); pThis->mMsg.ResetContent(); pThis->rbSLE4432.SetCheck(0); pThis->cbReader.EnableWindow(FALSE); pThis->bInit.EnableWindow(TRUE); pThis->bConnect.EnableWindow(FALSE); pThis->bErrCtr.EnableWindow(FALSE); pThis->bRead.EnableWindow(FALSE); pThis->bWrite.EnableWindow(FALSE); pThis->bWriteProt.EnableWindow(FALSE); pThis->bReset.EnableWindow(FALSE); pThis->bSubmit.EnableWindow(FALSE); pThis->bChange.EnableWindow(FALSE); ClearFields(); DisableFields(); } void DisplayOut(int errType, int retVal, CString prtText) { char buffer[300]; switch (errType){ case 0: // Notifications pThis->mMsg.AddString(prtText); break; case 1: // Error Messages pThis->mMsg.AddString(GetScardErrMsg(retVal)); break; case 2: // Input data sprintf(buffer, "< %s", prtText); pThis->mMsg.AddString(buffer); break; case 3: // Output data sprintf(buffer, "> %s", prtText); pThis->mMsg.AddString(buffer); break; } } void AddButtons() { pThis->bInit.EnableWindow(FALSE); pThis->bConnect.EnableWindow(TRUE); pThis->bRead.EnableWindow(TRUE); pThis->bWrite.EnableWindow(TRUE); pThis->bWriteProt.EnableWindow(TRUE); pThis->bReset.EnableWindow(TRUE); if (pThis->rbSLE4432.GetCheck() == 1){ pThis->bSubmit.EnableWindow(FALSE); pThis->bChange.EnableWindow(FALSE); pThis->bErrCtr.EnableWindow(FALSE); } else{ pThis->bSubmit.EnableWindow(TRUE); pThis->bChange.EnableWindow(TRUE); pThis->bErrCtr.EnableWindow(TRUE); } } int SendAPDUandDisplay(int sendType, CString apduIn) { char buffer[300], tmpStr[300]; int indx; ioRequest.dwProtocol = dwActProtocol; ioRequest.cbPciLength = sizeof(SCARD_IO_REQUEST); DisplayOut(2, 0, apduIn); retCode = SCardTransmit( hCard, &ioRequest, SendBuff, SendLen, NULL, RecvBuff, &RecvLen); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return retCode; } switch(sendType){ case 0: // Display SW1/SW2 value if (!((RecvBuff[RecvLen-2] == 0x90) && (RecvBuff[RecvLen-1] == 0x00))) DisplayOut(1, 0, "Return bytes are not acceptable."); else{ strcpy(tmpStr, ""); for (indx=RecvLen-2; indx<(RecvLen); indx++){ sprintf(buffer, "%02X ", RecvBuff[indx] & 0x00FF); strcat(tmpStr, buffer); } } break; case 1: // Display ATR after checking SW1/SW2 if (!((RecvBuff[RecvLen-2] == 0x90) && (RecvBuff[RecvLen-1] == 0x00))) DisplayOut(1, 0, "Return bytes are not acceptable."); else{ strcpy(tmpStr, "ATR : "); for (indx=0; indx<(RecvLen-2); indx++){ sprintf(buffer, "%02X ", RecvBuff[indx] & 0x00FF); strcat(tmpStr, buffer); } sprintf(tmpStr, "%s", tmpStr); } break; case 2: // Display all data after checking SW1/SW2 if (!((RecvBuff[RecvLen-2] == 0x90) && (RecvBuff[RecvLen-1] == 0x00))) DisplayOut(1, 0, "Return bytes are not acceptable."); else{ strcpy(tmpStr, ""); for (indx=0; indx<(RecvLen); indx++){ sprintf(buffer, "%02X ", RecvBuff[indx] & 0x00FF); strcat(tmpStr, buffer); } } break; } DisplayOut(3, 0, tmpStr); return retCode; } BOOL InputOK(int checkType) { char tmpStr[257]; int tmpLen; switch(checkType){ case 0: // for Read function tmpLen = pThis->tAdd.GetWindowText(tmpStr, 3); if (tmpLen != 2){ pThis->tAdd.SetFocus(); return 0; } tmpLen = pThis->tLen.GetWindowText(tmpStr, 3); if (tmpLen != 2){ pThis->tLen.SetFocus(); return 0; } break; case 1: // for Write function tmpLen = pThis->tAdd.GetWindowText(tmpStr, 3); if (tmpLen != 2){ pThis->tAdd.SetFocus(); return 0; } tmpLen = pThis->tLen.GetWindowText(tmpStr, 3); if (tmpLen != 2){ pThis->tLen.SetFocus(); return 0; } tmpLen = pThis->tData.GetWindowText(tmpStr, 257); if (tmpStr[0] == 0){ pThis->tData.SetFocus(); return 0; } break; case 2: // for Verify function pThis->tAdd.Clear(); pThis->tLen.Clear(); tmpLen = pThis->tData.GetWindowText(tmpStr, 257); if (tmpLen < 4){ pThis->tData.SetFocus(); return 0; } break; } return 1; } ///////////////////////////////////////////////////////////////////////////// // CSLE4432_4442Dlg message handlers BOOL CSLE4432_4442Dlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here pThis = this; InitMenu(); return TRUE; // return TRUE unless you set the focus to a control } void CSLE4432_4442Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CSLE4432_4442Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CSLE4432_4442Dlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CSLE4432_4442Dlg::OnInit() { int nLength = 64; // 1. Initialize SC reader // 1.1. Establish context retCode = SCardEstablishContext (SCARD_SCOPE_USER, NULL, NULL, &hContext); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return; } // 1.2. List PC/SC readers size = 256; retCode = SCardListReaders (hContext, NULL, readerName, &size); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return; } if (readerName == NULL) { DisplayOut(0, retCode, "No PC/SC reader is detected in your system."); return; } int i = 0; cbReader.ResetContent(); char *p = readerName; while (*p) { for (int i=0;p[i];i++); i++; if (*p != 0) { cbReader.AddString(p); } p = &p[i]; } cbReader.SetCurSel(0); DisplayOut(0, retCode, "Select Reader and Card to connect."); cbReader.EnableWindow(TRUE); rbSLE4432.SetCheck(1); bConnect.EnableWindow(TRUE); bInit.EnableWindow(FALSE); bReset.EnableWindow(TRUE); } void CSLE4432_4442Dlg::OnReset() { ClearFields(); // Close SC reader if (connActive) retCode = SCardDisconnect(hCard, SCARD_UNPOWER_CARD); retCode = SCardReleaseContext(hContext); connActive = FALSE; InitMenu(); } void CSLE4432_4442Dlg::OnQuit() { int tmpResult = 0; // Close SC reader if (connActive) retCode = SCardDisconnect(hCard, SCARD_UNPOWER_CARD); retCode = SCardReleaseContext(hContext); this->EndDialog(tmpResult); } void CSLE4432_4442Dlg::OnConnect() { int tmpInt = cbReader.GetCurSel(); CString rName,cardType; char buffer[200]; char tmpStr[128]; if (connActive){ DisplayOut(0, 0, "Connection is already active."); return; } cbReader.GetLBText(tmpInt, rName); // 1. Direct Connection retCode = SCardConnect(hContext, rName, SCARD_SHARE_DIRECT, 0, &hCard, &dwActProtocol); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return; } // 2. Select Card Type ClearBuffers(); SendLen = 4; if (rbSLE4432.GetCheck() == 1){ SendBuff[0] = 0x11; // Card Type for SLE4432 cardType = "SLE 4432"; } else{ SendBuff[0] = 0x12; // Card Type for SLE4442 cardType = "SLE 4442"; } RecvLen = 262; retCode = SCardControl(hCard, IOCTL_SMARTCARD_SET_CARD_TYPE, &SendBuff, SendLen, &RecvBuff, RecvLen, &nBytesRet); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return; } sprintf(buffer, "%s is selected.", cardType); DisplayOut(0, 0, buffer); // 3. Reconnect using SCARD_SHARE_SHARED and // SCARD_PROTOCOL_T0 parameters retCode = SCardDisconnect(hCard, SCARD_UNPOWER_CARD); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); return; } retCode = SCardConnect(hContext, rName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActProtocol); if (retCode != SCARD_S_SUCCESS) { DisplayOut(1, retCode, ""); connActive = FALSE; return; } sprintf(buffer, "Connected to %s.", rName); DisplayOut(0, 0, buffer); // 4. Get ATR DisplayOut(2, 0, "Get ATR"); ClearBuffers(); SendBuff[0] = 0xFF; SendBuff[1] = 0xA4; SendBuff[2] = 0x00; SendBuff[3] = 0x00; SendBuff[4] = 0x01; SendBuff[5] = 0x06; // SLE4432/4442 value SendLen = 6; RecvLen = 6; strcpy(tmpStr, ""); for(int i=0; i