Chipcard-PCSC-v1.4.16/000755 000765 000024 00000000000 14526744063 015260 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/PCSC.xs000644 000765 000024 00000142052 14526143072 016361 0ustar00rousseaustaff000000 000000 /************************************************************************** * Authors : Lionel VICTOR * * Ludovic ROUSSEAU * Compiler : gcc, Visual C++ * Target : Unix, Windows * * Description : Perl wrapper to the PCSC API * * Copyright (C) 2001 - Lionel VICTOR * Copyright (c) 2003-2015 Ludovic ROUSSEAU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * **************************************************************************/ #ifdef __cplusplus extern "C" { #endif #include #include "PCSCperl.h" #include "EXTERN.h" #include "perl.h" #include "XSUB.h" /* The following hack helps importing variables from the PCSC library. * Those variables are dynamically imported... * TODO: see how we can use them anyway... */ #ifdef SCARD_PCI_T0 # undef SCARD_PCI_T0 # define SCARD_PCI_T0 (gpioSCardT0Pci) #endif #ifdef SCARD_PCI_T1 # undef SCARD_PCI_T1 # define SCARD_PCI_T1 (gpioSCardT1Pci) #endif #ifdef SCARD_PCI_RAW # undef SCARD_PCI_RAW # define SCARD_PCI_RAW (gpioSCardRawPci) #endif #ifdef __cplusplus } #endif /* InitErrorCodes () initializes and creates a few variables describing * important values like error codes and constants. Those values are set * read-only so the user won't be able to eventually modify them. * Those variables are set in the XS because their numerical value is * platform dependent. */ void _InitErrorCodes () { SV * tmpSV; tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_S_SUCCESS", TRUE); sv_setiv (tmpSV, SCARD_S_SUCCESS); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_CANCELLED", TRUE); sv_setiv (tmpSV, SCARD_E_CANCELLED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_CANT_DISPOSE", TRUE); sv_setiv (tmpSV, SCARD_E_CANT_DISPOSE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INSUFFICIENT_BUFFER", TRUE); sv_setiv (tmpSV, SCARD_E_INSUFFICIENT_BUFFER); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INVALID_ATR", TRUE); sv_setiv (tmpSV, SCARD_E_INVALID_ATR); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INVALID_HANDLE", TRUE); sv_setiv (tmpSV, SCARD_E_INVALID_HANDLE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INVALID_PARAMETER", TRUE); sv_setiv (tmpSV, SCARD_E_INVALID_PARAMETER); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INVALID_TARGET", TRUE); sv_setiv (tmpSV, SCARD_E_INVALID_TARGET); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_INVALID_VALUE", TRUE); sv_setiv (tmpSV, SCARD_E_INVALID_VALUE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_NO_MEMORY", TRUE); sv_setiv (tmpSV, SCARD_E_NO_MEMORY); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_UNKNOWN_READER", TRUE); sv_setiv (tmpSV, SCARD_E_UNKNOWN_READER); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_TIMEOUT", TRUE); sv_setiv (tmpSV, SCARD_E_TIMEOUT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_SHARING_VIOLATION", TRUE); sv_setiv (tmpSV, SCARD_E_SHARING_VIOLATION); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_NO_SMARTCARD", TRUE); sv_setiv (tmpSV, SCARD_E_NO_SMARTCARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_UNKNOWN_CARD", TRUE); sv_setiv (tmpSV, SCARD_E_UNKNOWN_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_PROTO_MISMATCH", TRUE); sv_setiv (tmpSV, SCARD_E_PROTO_MISMATCH); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_NOT_READY", TRUE); sv_setiv (tmpSV, SCARD_E_NOT_READY); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_SYSTEM_CANCELLED", TRUE); sv_setiv (tmpSV, SCARD_E_SYSTEM_CANCELLED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_NOT_TRANSACTED", TRUE); sv_setiv (tmpSV, SCARD_E_NOT_TRANSACTED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_READER_UNAVAILABLE", TRUE); sv_setiv (tmpSV, SCARD_E_READER_UNAVAILABLE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_PCI_TOO_SMALL", TRUE); sv_setiv (tmpSV, SCARD_E_PCI_TOO_SMALL); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_READER_UNSUPPORTED", TRUE); sv_setiv (tmpSV, SCARD_E_READER_UNSUPPORTED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_DUPLICATE_READER", TRUE); sv_setiv (tmpSV, SCARD_E_DUPLICATE_READER); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_CARD_UNSUPPORTED", TRUE); sv_setiv (tmpSV, SCARD_E_CARD_UNSUPPORTED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_NO_SERVICE", TRUE); sv_setiv (tmpSV, SCARD_E_NO_SERVICE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_SERVICE_STOPPED", TRUE); sv_setiv (tmpSV, SCARD_E_SERVICE_STOPPED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_E_UNSUPPORTED_FEATURE", TRUE); sv_setiv (tmpSV, SCARD_E_UNSUPPORTED_FEATURE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_UNSUPPORTED_CARD", TRUE); sv_setiv (tmpSV, SCARD_W_UNSUPPORTED_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_UNRESPONSIVE_CARD", TRUE); sv_setiv (tmpSV, SCARD_W_UNRESPONSIVE_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_UNPOWERED_CARD", TRUE); sv_setiv (tmpSV, SCARD_W_UNPOWERED_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_RESET_CARD", TRUE); sv_setiv (tmpSV, SCARD_W_RESET_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_SECURITY_VIOLATION", TRUE); sv_setiv (tmpSV, SCARD_W_SECURITY_VIOLATION); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_W_REMOVED_CARD", TRUE); sv_setiv (tmpSV, SCARD_W_REMOVED_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_F_COMM_ERROR", TRUE); sv_setiv (tmpSV, SCARD_F_COMM_ERROR); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_F_INTERNAL_ERROR", TRUE); sv_setiv (tmpSV, SCARD_F_INTERNAL_ERROR); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_F_UNKNOWN_ERROR", TRUE); sv_setiv (tmpSV, SCARD_F_UNKNOWN_ERROR); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_F_WAITED_TOO_LONG", TRUE); sv_setiv (tmpSV, SCARD_F_WAITED_TOO_LONG); SvREADONLY_on (tmpSV); /* PCSC - Perl wrapper specific error codes */ tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_P_ALREADY_CONNECTED", TRUE); sv_setiv (tmpSV, SCARD_P_ALREADY_CONNECTED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_P_NOT_CONNECTED", TRUE); sv_setiv (tmpSV, SCARD_P_NOT_CONNECTED); SvREADONLY_on (tmpSV); /* PCSC standard constants */ /* tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_CONVENTION_DIRECT", TRUE); sv_setiv (tmpSV, SCARD_CONVENTION_DIRECT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_CONVENTION_INVERSE", TRUE); sv_setiv (tmpSV, SCARD_CONVENTION_INVERSE); SvREADONLY_on (tmpSV); */ tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SCOPE_USER", TRUE); sv_setiv (tmpSV, SCARD_SCOPE_USER); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SCOPE_TERMINAL", TRUE); sv_setiv (tmpSV, SCARD_SCOPE_TERMINAL); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SCOPE_SYSTEM", TRUE); sv_setiv (tmpSV, SCARD_SCOPE_SYSTEM); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_PROTOCOL_T0", TRUE); sv_setiv (tmpSV, SCARD_PROTOCOL_T0); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_PROTOCOL_T1", TRUE); sv_setiv (tmpSV, SCARD_PROTOCOL_T1); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_PROTOCOL_RAW", TRUE); sv_setiv (tmpSV, SCARD_PROTOCOL_RAW); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE", TRUE); sv_setiv (tmpSV, SCARD_SHARE_EXCLUSIVE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SHARE_SHARED", TRUE); sv_setiv (tmpSV, SCARD_SHARE_SHARED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SHARE_DIRECT", TRUE); sv_setiv (tmpSV, SCARD_SHARE_DIRECT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_LEAVE_CARD", TRUE); sv_setiv (tmpSV, SCARD_LEAVE_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_RESET_CARD", TRUE); sv_setiv (tmpSV, SCARD_RESET_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_UNPOWER_CARD", TRUE); sv_setiv (tmpSV, SCARD_UNPOWER_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_EJECT_CARD", TRUE); sv_setiv (tmpSV, SCARD_EJECT_CARD); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_UNKNOWN", TRUE); sv_setiv (tmpSV, SCARD_UNKNOWN); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_ABSENT", TRUE); sv_setiv (tmpSV, SCARD_ABSENT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_PRESENT", TRUE); sv_setiv (tmpSV, SCARD_PRESENT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SWALLOWED", TRUE); sv_setiv (tmpSV, SCARD_SWALLOWED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_POWERED", TRUE); sv_setiv (tmpSV, SCARD_POWERED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_NEGOTIABLE", TRUE); sv_setiv (tmpSV, SCARD_NEGOTIABLE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_SPECIFIC", TRUE); sv_setiv (tmpSV, SCARD_SPECIFIC); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_UNAWARE", TRUE); sv_setiv (tmpSV, SCARD_STATE_UNAWARE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_IGNORE", TRUE); sv_setiv (tmpSV, SCARD_STATE_IGNORE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_CHANGED", TRUE); sv_setiv (tmpSV, SCARD_STATE_CHANGED); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_UNKNOWN", TRUE); sv_setiv (tmpSV, SCARD_STATE_UNKNOWN); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_UNAVAILABLE", TRUE); sv_setiv (tmpSV, SCARD_STATE_UNAVAILABLE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_EMPTY", TRUE); sv_setiv (tmpSV, SCARD_STATE_EMPTY); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_PRESENT", TRUE); sv_setiv (tmpSV, SCARD_STATE_PRESENT); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_ATRMATCH", TRUE); sv_setiv (tmpSV, SCARD_STATE_ATRMATCH); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_EXCLUSIVE", TRUE); sv_setiv (tmpSV, SCARD_STATE_EXCLUSIVE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_INUSE", TRUE); sv_setiv (tmpSV, SCARD_STATE_INUSE); SvREADONLY_on (tmpSV); tmpSV = perl_get_sv ("Chipcard::PCSC::SCARD_STATE_MUTE", TRUE); sv_setiv (tmpSV, SCARD_STATE_MUTE); SvREADONLY_on (tmpSV); } /* _StringifyError is copied from pcsc_stringify_error() which is a * function taken from PCSClite * It has been modified because I added a few internal errors to the * wrapper (SCARD_P_NOT_CONNECTED for instance) * I also feel like using strong types like const char * const and * avoiding to use strcpy() is better from a security point of view. * * See file debuglog.c from your PCSClite distribution for extra * informations */ const char * _StringifyError (unsigned long Error) { switch ( (DWORD)Error ) { case SCARD_S_SUCCESS: return "Command successful."; case SCARD_E_CANCELLED: return "Command cancelled."; case SCARD_E_CANT_DISPOSE: return "Cannot dispose handle."; case SCARD_E_CARD_UNSUPPORTED: return "Card is unsupported."; case SCARD_E_DUPLICATE_READER: return "Reader already exists."; case SCARD_E_INSUFFICIENT_BUFFER: return "Insufficient buffer."; case SCARD_E_INVALID_ATR: return "Invalid ATR."; case SCARD_E_INVALID_HANDLE: return "Invalid handle."; case SCARD_E_INVALID_PARAMETER: return "Invalid parameter given."; case SCARD_E_INVALID_TARGET: return "Invalid target given."; case SCARD_E_INVALID_VALUE: return "Invalid value given."; case SCARD_E_NO_MEMORY: return "Not enough memory."; case SCARD_E_NO_SERVICE: return "Service not available."; case SCARD_E_NO_SMARTCARD: return "No smartcard inserted."; case SCARD_E_NOT_READY: return "Subsystem not ready."; case SCARD_E_NOT_TRANSACTED: return "Transaction failed."; case SCARD_E_PCI_TOO_SMALL: return "PCI struct too small."; case SCARD_E_PROTO_MISMATCH: return "Card protocol mismatch."; case SCARD_E_READER_UNAVAILABLE: return "Reader/s is unavailable."; case SCARD_E_READER_UNSUPPORTED: return "Reader is unsupported."; case SCARD_E_SERVICE_STOPPED: return "Service was stopped."; case SCARD_E_SHARING_VIOLATION: return "Sharing violation."; case SCARD_E_SYSTEM_CANCELLED: return "System cancelled."; case SCARD_E_TIMEOUT: return "Command timeout."; case SCARD_E_UNKNOWN_CARD: return "Unknown card."; case SCARD_E_UNKNOWN_READER: return "Unknown reader specified."; case SCARD_E_UNSUPPORTED_FEATURE: return "Feature not supported."; case SCARD_F_COMM_ERROR: return "RPC transport error."; case SCARD_F_INTERNAL_ERROR: return "Unknown internal error."; case SCARD_F_UNKNOWN_ERROR: return "Unknown internal error."; case SCARD_F_WAITED_TOO_LONG: return "Waited too long."; case SCARD_W_REMOVED_CARD: return "Card was removed."; case SCARD_W_RESET_CARD: return "Card was reset."; case SCARD_W_SECURITY_VIOLATION: return "Access denied."; case SCARD_W_UNPOWERED_CARD: return "Card is unpowered."; case SCARD_W_UNRESPONSIVE_CARD: return "Card is unresponsive."; case SCARD_W_UNSUPPORTED_CARD: return "Card is not supported."; /* The following errors are specific to the Perl wrapper */ case SCARD_P_ALREADY_CONNECTED: return "Object is already connected"; case SCARD_P_NOT_CONNECTED: return "Object is not connected"; /* We finally end with a generic error message */ default: return "Unknown (reader specific ?) error..."; }; } /*************************************************************************/ /*************** Double Typed Magical variable PCSC::errno ***************/ /*************************************************************************/ /* This is an accessor to our internal double-typed magical variable */ I32 gnLastError_get (pTHX_ IV nID, SV *sv) { /* We have to set both int and double values */ sv_setiv (sv, (IV)gnLastError); sv_setnv (sv, (double)gnLastError); /* Then we set the error message string */ sv_setpv (sv, _StringifyError(gnLastError)); /* Then, we eventually put corresponding bits of the SV flag */ SvNOK_on (sv); SvIOK_on (sv); /* return value should be ignored (man samples use return 1) */ return 1; } /* This is a modifier to our internal double-typed magical variable */ I32 gnLastError_set (pTHX_ IV nID, SV *sv) { /* just store the value in our global variable */ gnLastError = SvIV (sv); /* return value should be ignored (man samples use return 1) */ return 1; } /* Initialize the double-typed magical variable Chipcard::PCSC::errno */ void _InitMagic () { struct ufuncs uf_errno; SV *sv; /* Build a new immortal scalar */ sv = perl_get_sv ("Chipcard::PCSC::errno", TRUE); /* Construct the magic virtual table */ uf_errno.uf_val = &gnLastError_get; uf_errno.uf_set = &gnLastError_set; uf_errno.uf_index = 0; /* Then apply magic to it (use uf_eerno as a callback list) */ sv_magic (sv, 0, 'U', (char *)&uf_errno, sizeof(uf_errno)); /* Let the scalar be enchanted ! */ SvMAGICAL_on (sv); } MODULE = Chipcard::PCSC PACKAGE = Chipcard::PCSC PROTOTYPES: ENABLE #/////////////////////////////////////////////////////////////////////////// bool _LoadPCSCLibrary () CODE: if (ghDll) { /* No need to load the library twice */ RETVAL = TRUE; } else { /* Then loads the dynamic library */ ghDll = LOAD_LIB(); if (ghDll == NULL) { RETVAL = FALSE; croak ("Failed to load PCSC library"); } else { hEstablishContext = (TSCardEstablishContext) GET_FCT (ghDll, "SCardEstablishContext"); hReleaseContext = (TSCardReleaseContext) GET_FCT (ghDll, "SCardReleaseContext"); hReconnect = (TSCardReconnect) GET_FCT (ghDll, "SCardReconnect"); hDisconnect = (TSCardDisconnect) GET_FCT (ghDll, "SCardDisconnect"); hBeginTransaction = (TSCardBeginTransaction) GET_FCT (ghDll, "SCardBeginTransaction"); hEndTransaction = (TSCardEndTransaction) GET_FCT (ghDll, "SCardEndTransaction"); hTransmit = (TSCardTransmit) GET_FCT (ghDll, "SCardTransmit"); hControl = (TSCardControl) GET_FCT (ghDll, "SCardControl"); hCancel = (TSCardCancel) GET_FCT (ghDll, "SCardCancel"); #ifdef WIN32 hListReaders = (TSCardListReaders) GET_FCT (ghDll, "SCardListReadersA"); hConnect = (TSCardConnect) GET_FCT (ghDll, "SCardConnectA"); hStatus = (TSCardStatus) GET_FCT (ghDll, "SCardStatusA"); hGetStatusChange = (TSCardGetStatusChange) GET_FCT (ghDll, "SCardGetStatusChangeA"); #else hListReaders = (TSCardListReaders) GET_FCT (ghDll, "SCardListReaders"); hConnect = (TSCardConnect) GET_FCT (ghDll, "SCardConnect"); hStatus = (TSCardStatus) GET_FCT (ghDll, "SCardStatus"); hGetStatusChange = (TSCardGetStatusChange) GET_FCT (ghDll, "SCardGetStatusChange"); #endif if ( !hEstablishContext || !hReleaseContext || !hListReaders || !hConnect || !hReconnect || ! hDisconnect || !hBeginTransaction || !hEndTransaction || !hTransmit || !hStatus || !hGetStatusChange || !hCancel || !hControl) { RETVAL = FALSE; croak ("PCSC library does not contain all the required symbols"); } else { RETVAL = TRUE; } } /* Initialize the magical variable */ _InitMagic (); _InitErrorCodes (); } OUTPUT: RETVAL #/////////////////////////////////////////////////////////////////////////// #// EstablishContext () #// #// INPUT : #// - $dwScope -> Scope of the establishment. This can be either a local #// or remote connection. #// - $pvReserved1 #// - $pwReserved2 -> as of this writting, bothe the above parameters #// are not used by PCSC... they should be 0 #// #// OUTPUT : #// EstablishContext() returns the connection context or the 'undef' #// value if something goes wrong. SV* _EstablishContext (dwScope, pvReserved1, pvReserved2) unsigned long dwScope void* pvReserved1 void* pvReserved2 PREINIT: SCARDCONTEXT hContext = 0; CODE: ST(0) = sv_newmortal(); gnLastError = hEstablishContext (dwScope, pvReserved1, pvReserved2, &hContext); /* Then we either return an explicit 'UNDEF' value or the handle */ if (gnLastError != SCARD_S_SUCCESS) { ST(0) = &PL_sv_undef; } else { sv_setiv (ST(0), hContext); } #/////////////////////////////////////////////////////////////////////////// #// ReleaseContext () #// #// INPUT : #// - $hContext -> Connection context to be closed #// #// OUTPUT : #// - ReleaseContext returns a true value on successful operation and a #// false value otherwise. bool _ReleaseContext (hContext) unsigned long hContext CODE: gnLastError = hReleaseContext (hContext); /* Then returns true or false according to the return code */ if (gnLastError != SCARD_S_SUCCESS) { RETVAL = FALSE; } else { RETVAL = TRUE; } OUTPUT: RETVAL #/////////////////////////////////////////////////////////////////////////// #// ListReaders () #// #// INPUT : #// - $hContext -> Connection context to the PC/SC resource manager. #// - $mszGroups -> List of groups to list readers. (as of this writing, #// this is not used and should be 0 #// #// OUTPUT : #// ListReaders returns the 'undef' value if an error occurs otherwise it #// returns the list of available readers. Note that this can be an empty #// list... #// SV * _ListReaders(hContext, svGroups) unsigned long hContext SV* svGroups PREINIT: DWORD nBufferSize = 0; char* szBuffer = NULL; char* szCurrentToken = NULL; char* mszGroups; PPCODE: /* Before doing anything, we check that we have a valid group. */ if (SvPOK(svGroups)) { /* TODO : see how this works... multistring stuff with time *svGroups may become a reference to an array of groups... or undef */ mszGroups = SvPV (svGroups, PL_na); } else { mszGroups = 0; } /* The first call to SCardListReaders gives us the size of the * buffer we must allocate for the list. */ gnLastError = hListReaders (hContext, mszGroups, 0, &nBufferSize); /* In case of any error we immediately return an explicit UNDEF value */ if (gnLastError != SCARD_S_SUCCESS) { XSRETURN_UNDEF; } if (nBufferSize > 0) { /* At this point, nBufferSize contains the size of the buffer to * alloate. We use New as recomended by perlguts(3pm). The * buffer will be freed with Safefree()... */ New (2018, szBuffer, nBufferSize, char); if (szBuffer == NULL) { gnLastError = SCARD_E_NO_MEMORY; warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* The buffer is ready, so we can now retrieve the whole list. */ gnLastError = hListReaders (hContext, mszGroups, szBuffer, &nBufferSize); /* Then check for any error */ if (gnLastError != SCARD_S_SUCCESS) { Safefree (szBuffer); XSRETURN_UNDEF; } /* The string must be NULL terminated * May be just too much paranoid but... */ if (szBuffer[nBufferSize-1] != 0) { Safefree (szBuffer); gnLastError = SCARD_F_INTERNAL_ERROR; warn ("PCSC did not return a NULL terminated multistring at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* Now we need to push each reader separately on the stack. If * no readers are found, the stack is left empty... */ szCurrentToken = szBuffer; while (strlen(szCurrentToken)) { XPUSHs (sv_2mortal(newSVpv(szCurrentToken,0))); szCurrentToken = strchr (szCurrentToken, 0) + 1; } /* Free our buffer... * DO NOT USE free() or delete() here ! Let Perl deal with this. */ Safefree (szBuffer); } else { gnLastError = SCARD_F_INTERNAL_ERROR; warn ("PCSC did not return a valid buffer length at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } #/////////////////////////////////////////////////////////////////////////// #// Connect () #// #// INPUT : #// - $hContext -> Connection context to the PC/SC Resource Manager #// - $szReader -> ReaderName to connect to #// - dwShareMode -> Mode of connection : exclusive or shared #// - dwPreferredProtocols -> Desired protocol use #// #// OUTPUT : #// Connect returns an array with the handle to the connection and the #// active protocol for this connection ($hCard, $dwActiveProtocol). #// If a problem occurs, it just return the 'undef' value. SV* _Connect (hContext, szReader, dwShareMode, dwPreferredProtocols) unsigned long hContext const char* szReader unsigned long dwShareMode unsigned long dwPreferredProtocols PREINIT: SCARDHANDLE hCard = 0; DWORD dwActiveProtocol = 0; PPCODE: gnLastError = hConnect (hContext, szReader, dwShareMode, dwPreferredProtocols, &hCard, &dwActiveProtocol); /* We return immediately in case of an error */ if (gnLastError != SCARD_S_SUCCESS) XSRETURN_UNDEF; /* If anything was successful, push the two scalar values */ XPUSHs (sv_2mortal(newSViv(hCard))); XPUSHs (sv_2mortal(newSViv(dwActiveProtocol))); #/////////////////////////////////////////////////////////////////////////// #// Reconnect () #// #// INPUT : #// - $hCard -> Handle to a previous call to connect #// - dwShareMode -> Mode of connection : exclusive or shared #// - dwPreferredProtocols -> Desired protocol use #// - $dwInitialization -> Desired action taken on the card/reader #// #// OUTPUT : #// Reconnect returns the new active protocol or the 'undef' value if an #// error occurs SV* _Reconnect (hCard, dwShareMode, dwPreferredProtocols, dwInitialization) unsigned long hCard unsigned long dwShareMode unsigned long dwPreferredProtocols unsigned long dwInitialization PREINIT: DWORD dwActiveProtocol = 0; CODE: ST(0) = sv_newmortal(); gnLastError = hReconnect (hCard, dwShareMode, dwPreferredProtocols, dwInitialization, &dwActiveProtocol); /* Return either an UNDEF value if an error occurs or the current * active protocol as returned by PCSC */ if (gnLastError == SCARD_S_SUCCESS) sv_setiv (ST(0), dwActiveProtocol); else ST(0) = &PL_sv_undef; #/////////////////////////////////////////////////////////////////////////// #// Disconnect () #// #// INPUT : #// - $hCard -> Connection made from Connect #// - $dwDisposition -> Desired action taken on the card/reader #// #// OUTPUT : #// Disconnect returns TRUE upon successful result. Oppositely, it #// returns FALSE if somthing went bang bool _Disconnect (hCard, dwDisposition) unsigned long hCard; unsigned long dwDisposition; CODE: gnLastError = hDisconnect (hCard, dwDisposition); /* Then check for an error */ if (gnLastError != SCARD_S_SUCCESS) RETVAL = FALSE; else RETVAL = TRUE; OUTPUT: RETVAL #/////////////////////////////////////////////////////////////////////////// #// Status () #// #// INPUT : #// - $hCard -> Connection made from Connect #// #// OUTPUT : #// Status returns a list holding different informations about the #// reader : ($szReaderName, $dwState, $dwProtocol, \@bAttr). If an #// error pops up, the 'undef' value is returned. #// #// Important note: #// We return the ATR in the form of a reference to an array of bytes. #// When we build this reference, we start to build an array wich is #// made mortal, then we fill it with non mortal items usin av_push(). #// These items need to be immortal at this point because av_push does #// not increase the reference count of the scalar values it pushes into #// the array. As our array dies when it passes out of scope, perl #// would free its content and then any attempt to use them would result #// in an 'Attempt to free unreferenced scalar' error... SV* _Status (hCard) long hCard PREINIT: int nCount = 0; #ifdef WIN32 char tmpReaderName[200]; char* szReaderName = tmpReaderName; unsigned long cchReaderLen = sizeof(tmpReaderName); char tmpAtr[MAX_ATR_SIZE]; unsigned char* pbAtr = tmpAtr; unsigned long cbAtrLen = sizeof(tmpAtr); #else char* szReaderName = NULL; DWORD cchReaderLen = 0; unsigned char* pbAtr = NULL; DWORD cbAtrLen = 0; #endif DWORD dwState = 0; DWORD dwProtocol = 0; AV* aATR = 0; PPCODE: /* We call the function with a null cchReaderLen : this should * gives us the length of the buffer to allocate */ gnLastError = hStatus (hCard, szReaderName, &cchReaderLen, &dwState, &dwProtocol, (BYTE *)pbAtr, &cbAtrLen); /* Behaviour differs here from PCSC and PCSClite : * PCSC returns SUCCESS while PCSClite returns an error */ if (gnLastError == SCARD_E_INSUFFICIENT_BUFFER || gnLastError == SCARD_S_SUCCESS) { /* The call was hopefuly successful, so we allocate the * buffer for the ATR */ #ifndef WIN32 /* This hack should be temporary as PCSClite should eventually behave like PCSC */ cbAtrLen = MAX_ATR_SIZE; #endif if (cbAtrLen <= 0) { gnLastError = SCARD_F_INTERNAL_ERROR; warn ("PCSC did not return a valid buffer length at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } New (2018, pbAtr, cbAtrLen, unsigned char); if (pbAtr == NULL) { gnLastError = SCARD_E_NO_MEMORY; warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* we then allocate the buffer for the reader name */ if (cbAtrLen <= 0) { gnLastError = SCARD_F_INTERNAL_ERROR; warn ("PCSC did not return a valid buffer length at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } New (2018, szReaderName, cchReaderLen, char); if (szReaderName == NULL) { Safefree (pbAtr); gnLastError = SCARD_E_NO_MEMORY; warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* Now we perform the real call to SCardStatus */ gnLastError = hStatus (hCard, szReaderName, &cchReaderLen, &dwState, &dwProtocol, (BYTE *)pbAtr, &cbAtrLen); if (gnLastError != SCARD_S_SUCCESS) { Safefree (szReaderName); Safefree (pbAtr); XSRETURN_UNDEF; } } else { /* As our first call should trigger the SCARD_E_INSUFFICIENT_BUFFER * error or no error, we consider any other case as a failure... */ XSRETURN_UNDEF; } /* we fill this array with every byte from the ATR * note that we do not make this data mortal because av_push() * does not increment the reference count. See the note in the * function header above */ if (cbAtrLen > 0) { /* We first create an array for the ATR */ aATR = (AV*) sv_2mortal((SV*)newAV()); /* Then we fill it with every byte from the ATR * note that we do not make this data mortal because av_push() * does not increment the reference count. See the note in the * function header above */ for (nCount=0; nCount < cbAtrLen; nCount++) { av_push (aATR, newSViv(pbAtr[nCount])); } } /* In the event that no ATR is available, we used to fill aATR * with '(AV*) &PL_sv_undef' However, pushing a reference to * this seems is hard to handle I therefore prefer to do * nothing and leave aATR with the default null value and * the code below will not push the reference to the ATR array */ /* eventually, we end up pushing all the values */ XPUSHs (sv_2mortal(newSVpv(szReaderName,0))); XPUSHs (sv_2mortal(newSViv(dwState))); XPUSHs (sv_2mortal(newSViv(dwProtocol))); /* as well as a reference to the ATR array if available */ if (aATR) { XPUSHs (sv_2mortal(newRV((SV*)aATR))); } /* As a conclusion, we just free what we took */ Safefree (szReaderName); Safefree (pbAtr); #/////////////////////////////////////////////////////////////////////////// #// Transmit () #// #// INPUT : #// - $hCard #// - @inBuffer = ($Protocol, \@BytesToSend) #// $Protocol contains the protocol (T0|T1) #// @BytesToSend contains the bytes to transmit #// Note: please note that @inBuffer is actually appended to the #// parameters list, therefore, the following calls are equivalent: #// @inBuffer ($Protocol, [0x00, 0x12, 0x33]); = ;Transmit ($hCard, @inBuffer); #// Transmit ($hCard, $Protocol, [0x00, 0x12, 0x33]); #// #// OUTPUT : #// - @outBuffer = ($Protocol, \@BytesRead) #// - $Protocol may be undef #// - @BytesRead contains the returned bytes #// Transmit can return the 'undef' value alone if an error occurs. SV* _Transmit (hCard, dwProtocol, psvSendData) unsigned long hCard; unsigned long dwProtocol; SV* psvSendData; PREINIT: int nCount = 0; static char* pbSendBuffer = NULL; static unsigned char pbRecvBuffer [MAX_BUFFER_SIZE_EXTENDED]; unsigned long cbSendLength = 0; DWORD cbRecvLength = sizeof (pbRecvBuffer); SCARD_IO_REQUEST ioSendPci, ioRecvPci; AV* aRecvBuffer = NULL; PPCODE: /* We make sure that the array is sane */ if (psvSendData == NULL) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvSendData is a NULL pointer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* Should the second parameter not be a reference, we return the * SCARD_E_INVALID_PARAMETER error code. */ if ((!SvROK(psvSendData))||(SvTYPE(SvRV(psvSendData)) != SVt_PVAV)) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvSendData is not a RVAV at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* We have to build up our IO_REQUEST structures according to * $dwProtocol */ switch (dwProtocol) { case SCARD_PROTOCOL_T0: case SCARD_PROTOCOL_T1: case SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1: case SCARD_PROTOCOL_RAW: ioSendPci.dwProtocol = dwProtocol; ioSendPci.cbPciLength = sizeof(ioSendPci); ioRecvPci.dwProtocol = dwProtocol; ioRecvPci.cbPciLength = sizeof(ioRecvPci); break; default: /* If $dwProtocol holds an invalid value, we exist reporting * the error SCARD_E_INVALID_VALUE. */ gnLastError = SCARD_E_INVALID_VALUE; warn ("unknown protocol %ld given at %s line %d\n\t", dwProtocol, __FILE__, __LINE__); XSRETURN_UNDEF; } /* Let's allocate some space for the send buffer */ cbSendLength = av_len((AV*)SvRV(psvSendData)) + 1; if (cbSendLength <= 0) { gnLastError = SCARD_E_INVALID_VALUE; warn ("empty array given at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } New (2018, pbSendBuffer, cbSendLength, char); if (pbSendBuffer == NULL) { gnLastError = SCARD_E_NO_MEMORY; warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* We have to extract data from the array referenced by psvSendData */ for (nCount = 0; nCount < cbSendLength ; nCount++) pbSendBuffer[nCount] = (char)SvIV(*av_fetch((AV*)SvRV(psvSendData), nCount, 0)); /* Everything is ready : call the real function... */ gnLastError = hTransmit (hCard, &ioSendPci, (BYTE *)pbSendBuffer, cbSendLength, &ioRecvPci, pbRecvBuffer, &cbRecvLength); if (gnLastError != SCARD_S_SUCCESS) { /* Free the buffer if something went wrong */ Safefree (pbSendBuffer); XSRETURN_UNDEF; } /* At this point, the command was successful. We still need to * return all the values from our buffer... * so we build an array for the ATR */ aRecvBuffer = (AV*) sv_2mortal((SV*)newAV()); /* we fill this array with every byte from the Response * note that we do not make this data mortal because av_push() * does not increment the reference count. See the note in the * function header above */ for (nCount = 0; nCount < cbRecvLength; nCount++) av_push (aRecvBuffer, newSViv(pbRecvBuffer[nCount])); XPUSHs (sv_2mortal(newSViv(ioRecvPci.dwProtocol))); XPUSHs (sv_2mortal(newRV((SV*)aRecvBuffer))); /* Do not forget to free the dynamically allocated buffer */ Safefree (pbSendBuffer); #/////////////////////////////////////////////////////////////////////////// #// Control () #// #// INPUT : #// - $hCard #// - $dwControlCode #// - @inBuffer = (\@BytesToSend) #// @BytesToSend contains the bytes to transmit #// #// OUTPUT : #// - @outBuffer = (\@BytesRead) #// - @BytesRead contains the returned bytes #// Control can return the 'undef' value alone if an error occurs. SV* _Control (hCard, dwControlCode, psvSendData) unsigned long hCard; unsigned long dwControlCode; SV* psvSendData; PREINIT: int nCount = 0; static char* pbSendBuffer = NULL; static unsigned char pbRecvBuffer [MAX_BUFFER_SIZE]; unsigned long cbSendLength = 0; DWORD cbRecvLength = sizeof (pbRecvBuffer); AV* aRecvBuffer = NULL; PPCODE: /* We make sure that the array is sane */ if (psvSendData == NULL) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvSendData is a NULL pointer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* Should the second parameter not be a reference, we return the * SCARD_E_INVALID_PARAMETER error code. */ if ((!SvROK(psvSendData))||(SvTYPE(SvRV(psvSendData)) != SVt_PVAV)) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvSendData is not a RVAV at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } /* Let's allocate some space for the send buffer, if needed */ cbSendLength = av_len((AV*)SvRV(psvSendData)) + 1; if (cbSendLength <= 0) { gnLastError = SCARD_E_INVALID_VALUE; warn ("empty array given at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } New (2018, pbSendBuffer, cbSendLength, char); if (pbSendBuffer == NULL) { gnLastError = SCARD_E_NO_MEMORY; warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_UNDEF; } for (nCount = 0; nCount < cbSendLength ; nCount++) pbSendBuffer[nCount] = (char)SvIV(*av_fetch((AV*)SvRV(psvSendData), nCount, 0)); /* Everything is ready : call the real function... */ gnLastError = hControl (hCard, dwControlCode, (cbSendLength > 0 ? (BYTE *)pbSendBuffer : NULL), cbSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &cbRecvLength); if (gnLastError != SCARD_S_SUCCESS) { /* Free the buffer if something went wrong */ Safefree (pbSendBuffer); XSRETURN_UNDEF; } /* At this point, the command was successful. We still need to * return all the values from our buffer... */ aRecvBuffer = (AV*) sv_2mortal((SV*)newAV()); /* we fill this array with every byte from the Response * note that we do not make this data mortal because av_push() * does not increment the reference count. See the note in the * function header above */ for (nCount = 0; nCount < cbRecvLength; nCount++) av_push (aRecvBuffer, newSViv(pbRecvBuffer[nCount])); // XPUSHs (sv_2mortal(newSViv(ioRecvPci.dwProtocol))); XPUSHs (sv_2mortal(newRV((SV*)aRecvBuffer))); /* Do not forget to free the dynamically allocated buffer */ Safefree (pbSendBuffer); #/////////////////////////////////////////////////////////////////////////// #// BeginTransaction () #// #// INPUT : #// - $hCard -> connection made from Connect() #// #// OUTPUT : #// BeginTransaction returns true or false depending on its successful #// completion unsigned long _BeginTransaction (hCard) unsigned long hCard; CODE: gnLastError = hBeginTransaction (hCard); /* Then we check for an error */ if (gnLastError != SCARD_S_SUCCESS) RETVAL = FALSE; else RETVAL = TRUE; OUTPUT: RETVAL #/////////////////////////////////////////////////////////////////////////// #// EndTransaction () #// #// INPUT : #// - $hCard -> connection made from Connect() #// - $dwDisposition -> Desired action taken on the card/reader #// #// OUTPUT : #// EndTransaction returns true or false depending on its successful #// completion unsigned long _EndTransaction (hCard, dwDisposition) unsigned long hCard; unsigned long dwDisposition; CODE: gnLastError = hEndTransaction (hCard, dwDisposition); /* Then we check for an error */ if (gnLastError != SCARD_S_SUCCESS) RETVAL = FALSE; else RETVAL = TRUE; OUTPUT: RETVAL #/////////////////////////////////////////////////////////////////////////// #// GetStatusChange () #// #// This #// #// INPUT : #// - $hContext -> Connection context to the PC/SC resource manager. #// - $nTimeout -> Time to wait for a change (or SCARD_INFINITE) #// - \@ReaderStates -> array of reader states #// #// OUTPUT : bool _GetStatusChange (hContext, dwTimeout, psvReaderStates) unsigned long hContext; unsigned long dwTimeout; SV* psvReaderStates; PREINIT: static SCARD_READERSTATE *rgReaderStates_t = NULL; unsigned int nCount = 0; unsigned int nATRCount = 0; unsigned int nReaders = 0; AV* aRecvBuffer = NULL; PPCODE: if (psvReaderStates == NULL) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvReaderStates is a NULL pointer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } /* Should the second parameter not be a reference, we return the * SCARD_E_INVALID_PARAMETER error code. */ if ((!SvROK(psvReaderStates))||(SvTYPE(SvRV(psvReaderStates)) != SVt_PVAV)) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvReaderStates is not a RVAV at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } /* Get the total number of elements in our array */ nReaders = av_len((AV*)SvRV(psvReaderStates)) + 1; /* free the memory allocated during previous call to GetStatusChange */ if (rgReaderStates_t) Safefree(rgReaderStates_t); /* allocate the Reader States table */ Newz(2018, rgReaderStates_t, nReaders, SCARD_READERSTATE); if (rgReaderStates_t == NULL) { warn ("Could not allocate buffer at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } for (nCount = 0; nCount < nReaders; nCount++) { /* As long as psvReaderStates is a reference to a PVAV we * should be able to use av_fetch() without error */ SV *svCurrentToken = (*av_fetch((AV*)SvRV(psvReaderStates), nCount, 0)); /* Now see if the elements in the array are reference to hasharrays */ if ((!SvROK(svCurrentToken)) || (SvTYPE(SvRV(svCurrentToken)) != SVt_PVHV)) { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("psvReaderStates[%d] is not a RVHV at %s line %d\n\t", nCount, __FILE__, __LINE__); XSRETURN_NO; } /* Checkout if the 'name' argument has been passed */ if (hv_exists((HV*)SvRV(svCurrentToken), "reader_name", 11)) { SV** psvName = NULL; /* fetch the value of reader_name */ psvName = hv_fetch((HV*)SvRV(svCurrentToken), "reader_name", 11, 0); /* Link the internal structure and the fetched pointer if appropriate */ if ((psvName != NULL) && (SvTYPE(*psvName) == SVt_PV)) { // printf ("We got a name\n"); rgReaderStates_t[nCount].szReader = SvPV (*psvName, PL_na); // printf ("which is : %s\n", rgReaderStates_t[nCount].szReader); } else { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("reader_name is not valid (must be ASCII) at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } } /* Checkout if the 'current_state' argument has been passed */ if (hv_exists((HV*)SvRV(svCurrentToken), "current_state", 13)) { SV** psvCurrentState = NULL; /* fetch the value of current_state */ psvCurrentState = hv_fetch((HV*)SvRV(svCurrentToken), "current_state", 13, 0); /* Copy the current status into the struct */ if (psvCurrentState != NULL) { if (SvTYPE(*psvCurrentState) == SVt_IV || SvTYPE(*psvCurrentState) == SVt_PVIV) { // printf ("We got a current_state\n"); rgReaderStates_t[nCount].dwCurrentState = SvIV (*psvCurrentState); // printf ("which is : 0x%lX\n", rgReaderStates_t[nCount].dwCurrentState); } else { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("current_state is not valid (must be numeric) at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } } } /* Checkout if the 'event_state' argument has been passed */ if (hv_exists((HV*)SvRV(svCurrentToken), "event_state", 11)) { SV** psvEventState = NULL; /* fetch the value of current_state */ psvEventState = hv_fetch((HV*)SvRV(svCurrentToken), "event_state", 11, 0); /* Copy the event status into the struct */ if (psvEventState != NULL) { if (SvTYPE(*psvEventState) == SVt_IV || SvTYPE(*psvEventState) == SVt_PVIV) { rgReaderStates_t[nCount].dwEventState = SvIV (*psvEventState); } else { gnLastError = SCARD_E_INVALID_PARAMETER; warn ("event_state is not valid (must be numeric) at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } } } /* Checkout if the 'ATR' argument has been passed */ if (hv_exists((HV*)SvRV(svCurrentToken), "ATR", 3)) { SV** psvATR = NULL; /* fetch the value of ATR */ psvATR = hv_fetch((HV*)SvRV(svCurrentToken), "ATR", 3, 0); if (psvATR != NULL) { /* Make sure we have a reference to an array */ if ((SvTYPE(*psvATR) == SVt_RV) && (SvTYPE(SvRV(*psvATR)) == SVt_PVAV)) { int nATR = 0; /* Fetch the ATR length */ nATR = av_len((AV*)SvRV(*psvATR)) + 1; for (nATRCount=0; nATRCount< nATR; nATRCount++) { /* Fetch all bytes of th ATR one by one */ SV *svCurrentATRToken = (*av_fetch((AV*)SvRV(*psvATR), nATRCount, 0)); if (SvTYPE(svCurrentATRToken) != SVt_IV) { /* Return SCARD_E_INVALID_PARAMETER if * the ATR is not made only of numbers */ gnLastError = SCARD_E_INVALID_PARAMETER; warn ("invalid ATR (not a reference to a numerical array) at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } rgReaderStates_t[nCount].rgbAtr[nATRCount] = (char)SvIV(svCurrentATRToken); } } else { /* ATR is invalid therefore we return SCARD_E_INVALID_PARAMETER */ gnLastError = SCARD_E_INVALID_PARAMETER; warn ("invalid ATR (not a reference to an array) at %s line %d\n\t", __FILE__, __LINE__); XSRETURN_NO; } } } } /* Eventually call the real PCSC function */ gnLastError = hGetStatusChange (hContext, dwTimeout, rgReaderStates_t, nReaders); /* Stop here upon failure */ if (gnLastError != SCARD_S_SUCCESS) { XSRETURN_NO; } /* Upon successful completion, we have to propagate changes from * the internalm structs to the hash arays, creating entries if * required */ for (nCount = 0; nCount < nReaders; nCount++) { /* As long as psvReaderStates is a reference to a PVAV we * should be able to use av_fetch() without error */ SV *svCurrentToken = (*av_fetch((AV*)SvRV(psvReaderStates), nCount, 0)); /* Propagates changes to the reader_name... */ /* The name was mandatory so we should have it already * linked to our value... */ /* Propagate changes to the current_state */ if (hv_exists((HV*)SvRV(svCurrentToken), "current_state", 13)) { /* If the current_state was provided we modify its * entry... * Most checks were performed already so this is a * simplified run... */ /* Copy the struct into current_state */ sv_setiv (*hv_fetch((HV*)SvRV(svCurrentToken), "current_state", 13, 0), rgReaderStates_t[nCount].dwCurrentState); } else { /* If the current_state wasn't provided we create its * entry */ hv_store ((HV*)SvRV(svCurrentToken), "current_state", 13, newSViv(rgReaderStates_t[nCount].dwCurrentState), 0); } /* Propagate changes to the event_state */ if (hv_exists((HV*)SvRV(svCurrentToken), "event_state", 11)) { /* If the event_state was provided we modify its * entry... * Most checks were performed already so this is a * simplified run... */ /* Copy the struct into event_state */ sv_setiv (*hv_fetch((HV*)SvRV(svCurrentToken), "event_state", 11, 0), rgReaderStates_t[nCount].dwEventState); } else { /* If the current_state wasn't provided we create its * entry */ hv_store ((HV*)SvRV(svCurrentToken), "event_state", 11, newSViv(rgReaderStates_t[nCount].dwEventState), 0); } /* Build the ATR if possible */ if (rgReaderStates_t[nCount].cbAtr > 0) { /* Create an AV* with the ATR */ aRecvBuffer = (AV*) sv_2mortal((SV*)newAV()); for (nATRCount = 0; nATRCount Connection context to the PC/SC resource manager. #// #// OUTPUT : #// Cancel returns true upon successful conmpletion or false otherwise bool _Cancel (hContext) unsigned long hContext CODE: gnLastError = hCancel (hContext); /* Then we check for an error */ if (gnLastError != SCARD_S_SUCCESS) RETVAL = FALSE; else RETVAL = TRUE; OUTPUT: RETVAL # End of File # Chipcard-PCSC-v1.4.16/PCSCperl.h000644 000765 000024 00000015313 14526143072 017040 0ustar00rousseaustaff000000 000000 /******************************************************************************* * Author : Lionel VICTOR * * Compiler : gcc, Visual C++ * Target : unix, Windows * * Description : Perl wrapper to the PCSC API * * Copyright (C) 2001 - Lionel VICTOR * Copyright (c) 2003-2010 - Ludovic ROUSSEAU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * ******************************************************************************/ /****************************************************************************** * Contains basic definitions for a Perl wrapper to PCSC-lite. The code * here is meant to be portable to most Unices. It should as well compile * under Microsoft Windows without modifications. * Most macros in this file help portability. ******************************************************************************/ #ifndef PCSC_PERL #define PCSC_PERL #ifdef WIN32 # include # include # define LOAD_LIB() LoadLibrary("winscard.dll") # define CLOSE_LIB FreeLibrary # define DLL_HANDLE HINSTANCE # define GET_FCT GetProcAddress /* The following defines are only set with PCSClite, we have to * declare them for use under WIN32 */ # define MAX_ATR_SIZE 33 # define MAX_BUFFER_SIZE 264 #else /* WIN32 */ /* WIN32 entry points are called with the WINAPI convention * the following hack is to handle this shit */ #define WINAPI #ifdef __APPLE__ #include #include #define LPCTSTR LPCSTR #include #include #include #include #define DLL_HANDLE CFBundleRef DLL_HANDLE LOAD_LIB() { CFStringRef bundlePath; CFURLRef bundleURL; CFBundleRef bundle; bundlePath = CFStringCreateWithCString(NULL, "/System/Library/Frameworks/PCSC.framework", kCFStringEncodingMacRoman); if (bundlePath == NULL) { return NULL; } bundleURL = CFURLCreateWithFileSystemPath(NULL, bundlePath, kCFURLPOSIXPathStyle, TRUE); CFRelease(bundlePath); if (bundleURL == NULL) { return NULL; } bundle = CFBundleCreate(NULL, bundleURL); CFRelease(bundleURL); if (bundle == NULL) { return NULL; } if (!CFBundleLoadExecutable(bundle)) { CFRelease(bundle); return NULL; } return bundle; } void* GET_FCT(CFBundleRef bundle, char *fct_name) { CFStringRef cfName; void * fct_addr=NULL; cfName = CFStringCreateWithCString(NULL, fct_name, kCFStringEncodingMacRoman); if (cfName == NULL) { return NULL; } fct_addr = CFBundleGetFunctionPointerForName(bundle, cfName); CFRelease(cfName); return fct_addr; } #else /* other Unixes */ # include # include # define LOAD_LIB() dlopen("libpcsclite.so.1", RTLD_LAZY) # define CLOSE_LIB(x) dlclose(x) # define DLL_HANDLE void* # define GET_FCT dlsym #define LPCTSTR LPCSTR #define LPTSTR LPSTR #endif /* __APPLE__ */ #endif /* WIN32 */ /* extended APDU supported? (pcsc-lite >= 1.3.2 only) */ #ifndef MAX_BUFFER_SIZE_EXTENDED #define MAX_BUFFER_SIZE_EXTENDED MAX_BUFFER_SIZE #endif /* Definitine fuctions imported from the PCSC library and used by the stub */ typedef LONG (WINAPI *TSCardEstablishContext) ( DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT ); typedef LONG (WINAPI *TSCardReleaseContext) ( SCARDCONTEXT ); typedef LONG (WINAPI *TSCardListReaders) ( SCARDCONTEXT, LPCTSTR, LPTSTR, LPDWORD ); typedef LONG (WINAPI *TSCardConnect) ( SCARDCONTEXT, LPCTSTR, DWORD, DWORD, LPSCARDHANDLE, LPDWORD ); typedef LONG (WINAPI *TSCardReconnect) ( SCARDHANDLE, DWORD, DWORD, DWORD, LPDWORD ); typedef LONG (WINAPI *TSCardDisconnect) ( SCARDHANDLE, DWORD ); typedef LONG (WINAPI *TSCardBeginTransaction) ( SCARDHANDLE ); typedef LONG (WINAPI *TSCardEndTransaction) ( SCARDHANDLE, DWORD ); typedef LONG (WINAPI *TSCardTransmit) ( SCARDHANDLE, LPCSCARD_IO_REQUEST, LPCBYTE, DWORD, LPSCARD_IO_REQUEST, LPBYTE, LPDWORD ); typedef LONG (WINAPI *TSCardControl) ( SCARDHANDLE, DWORD, LPCBYTE, DWORD, LPBYTE, DWORD, LPDWORD ); typedef LONG (WINAPI *TSCardStatus) ( SCARDHANDLE, LPTSTR, LPDWORD, LPDWORD, LPDWORD, LPBYTE, LPDWORD ); typedef LONG (WINAPI *TSCardGetStatusChange) ( SCARDHANDLE, DWORD, SCARD_READERSTATE *, DWORD ); typedef LONG (WINAPI *TSCardCancel) ( SCARDCONTEXT ); /* these functions are not used */ /* LONG SCardListReaderGroups( SCARDCONTEXT, LPSTR, LPDWORD ); */ /* Declares a variable for any imported variable */ /* static LPSCARD_IO_REQUEST gpioSCardT0Pci; static LPSCARD_IO_REQUEST gpioSCardT1Pci; static LPSCARD_IO_REQUEST gpioSCardRawPci; */ /* Declares a variable for any imported function */ static TSCardEstablishContext hEstablishContext = NULL; static TSCardReleaseContext hReleaseContext = NULL; static TSCardListReaders hListReaders = NULL; static TSCardConnect hConnect = NULL; static TSCardReconnect hReconnect = NULL; static TSCardDisconnect hDisconnect = NULL; static TSCardBeginTransaction hBeginTransaction = NULL; static TSCardEndTransaction hEndTransaction = NULL; static TSCardTransmit hTransmit = NULL; static TSCardControl hControl = NULL; static TSCardStatus hStatus = NULL; static TSCardGetStatusChange hGetStatusChange = NULL; static TSCardCancel hCancel = NULL; /* Also declares some static variables */ static DLL_HANDLE ghDll = NULL; static LONG gnLastError = SCARD_S_SUCCESS; /* these functions are not used */ /* TSCardListReaderGroups hListReaderGroups = NULL; */ #define SCARD_P_ALREADY_CONNECTED 0x22200001 #define SCARD_P_NOT_CONNECTED 0x22200002 #endif /* End of File */ Chipcard-PCSC-v1.4.16/Card/000755 000765 000024 00000000000 14526744063 016131 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/test/000755 000765 000024 00000000000 14526744063 016237 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/Changelog000644 000765 000024 00000041112 14526143043 017060 0ustar00rousseaustaff000000 000000 2015-11-19 author * README: Release 1.4.14 * PCSC.xs: Update copyright date * PCSC.xs: _StringifyError(): cast Error in a (DWORD) On Mac OS X El Capitan (at least) the value is extended to 64 bits and is then wrong. We get 0xFFFFFFFF80100068 instead of 0x80100068 and all the error codes are all converted to the default error: "Unknown (reader specific ?) error..." 2014-12-05 author * LICENCE: Update GNU GPL v2 license text The FSF postal adress has changed. Thanks to Martin Hauke for the bug report. * README: Release 1.4.13 2013-04-01 author * create_distrib.sh: rcs2log has been moved in /usr/share/cvs/contrib/rcs2log * PCSC.pm: Support Perl 5.16 Remove the warning: defined(@array) is deprecated at /usr/lib/perl/5.16.3/Chipcard/PCSC.pm line 69. (Maybe you should just omit the defined()?) Thanks to Viliam Pucik for the bug report 2011-03-06 author * README: release 1.4.12 * PCSC.xs: Also check for SVt_PVIV and not just SVt_IV. Fixes Debian bug #613722 "libpcsc-perl: GetStatusChange error after print" * PCSC.xs, PCSC.pm, test.pl: Use lines of less than 80 columns 2010-10-27 author * create_distrib.sh: compress using bzip2 instead of gzip * README: release 1.4.11 * PCSCperl.h: SCardCancelTransaction() is no more present in pcsc-lite * PCSC.pm, PCSC.pod, PCSC.xs, PCSCperl.h: SCardSetTimout is no more present in pcsc-lite > 1.6.4 It was a pcsc-lite specific and deprecated function 2010-08-18 author * PCSCperl.h: use SCARD_READERSTATE * instead of LPSCARD_READERSTATE since is not define in pcsc-lite < 1.6.3 * README: release 1.4.10 * PCSC.pm, PCSC.xs, PCSCperl.h, README: Update copyright date * create_distrib.sh: Allow more than one digit in the version numbers * PCSC.xs, PCSCperl.h: Use LPSCARD_READERSTATE instead of LPSCARD_READERSTATE_A since it is no more defined in pcsc-lite >= 1.6.2 2010-06-30 author * README: release 1.4.9 * PCSC.pm, PCSC.pod, PCSC.xs: sort constants in alphabetical order * PCSC.pod, PCSC.xs: SCARD_E_UNSUPPORTED_FEATURE is not specific to pcsc-lite but is also available on Windows * PCSC.pm, PCSC.pod, PCSC.xs: SCARD_W_INSERTED_CARD is no more defined in pcsc-lite 1.6.0 and then pcsc-perl failed to build. It was an error code specific to pcsc-lite. 2010-01-03 author * Card/Card.pod: fix spelling error 2009-09-23 author * README: release 1.4.8 * Card/Card.pod: Correct 3 bugs signaled by podchecker 2009-09-06 author * PCSC.xs: PCSC.xs:853: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’ 2008-09-28 author * PCSC.pod: example code for GetStatusChange() 2008-03-26 author * Card/Card.pm: type: prefered -> preferred * Card/Card.pm: update copyright date * Card/Card.pm: typo: prefered -> preferred * Card/Card.pod: typos * README: release 1.4.7 2008-03-12 author * MANIFEST: remove removed files (merged) * Makefile_OSX.PL, Makefile_win.PL: merged in Makefile.PL * README, README.OSX, README.Unix, README.Windows: merge all README.* in README * Makefile.PL: merge Makefile_win.PL and Makefile_OSX.PL * PCSC.pod: typos * PCSC.pod: typo * PCSC.pm: version 0.05 * PCSC.pod, PCSCperl.h: update copyright date * PCSCperl.h: reorder the .h inclusion to have a default for Unix system 2007-03-07 author * README: release 1.4.6 * PCSCperl.h: add support of GNU/FreeBSD Thanks to Cyril Brulebois for the patch (Debian bug #413618) 2007-03-02 author * README: release 1.4.5 * MANIFEST: add Card/t/test.t * PCSC.xs: remove a const on the return type to avoid: PCSC.xs:244: warning: type qualifiers ignored on function return type * PCSCperl.h: For Linux #define LPCTSTR LPCSTR #define LPTSTR LPSTR to avoid using deprecated types 2007-02-05 author * PCSC.xs: remove some pcsc-lite specific constants 2006-12-09 author * t/test.t: remove Chipcard::PCSC::Card tests since they are now done by Card/t/test.t * Card/t/test.t: new file. Copy from ../t/test.t * t/test.t, test.pl: use Test::More instead of ExtUtils::testlib 2006-10-10 author * PCSC.pm: remove a debug print command 2006-10-08 author * PCSC.pm: version 0.04 * PCSC.pm: ascii_to_array(): check that an hex number is exactly two characters 2006-08-12 author * README: release 1.4.4 * Card/Card.pm, examples/gsm_directory.pl, examples/test_iso_error.pl, test/multiple_readers.pl, test/single_reader.pl, PCSC.pm, README.Unix, README.Windows, create_distrib.sh, test.pl: new $Id$ format 2006-05-30 author * PCSC.xs, PCSCperl.h: add support of extended APDU 2006-05-16 author * README: release 1.4.3 2006-05-04 author * PCSC.xs: use unsigned char for pbAtr[] to have "3B FA ..." instead of "3B FFFFFFFA ..." * t/test.t: update $Id$ * Makefile_OSX.PL: update for Mac OS X Tiger * PCSC.xs: change some types and use some cast to make the code compile under Mac OS X * PCSCperl.h: add some #include <> for Mac OS X 2004-08-06 author * README: release 1.4.2 * PCSC.xs: allow to use SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 as the protocol * Card/Card.pm: typo: informatin -> information 2004-07-04 author * README: release 1.4.1 * README: use http://pcsclite.alioth.debian.org/ as the pcsc-lite homepage * Makefile.PL, PCSCperl.h: back to use pcsclite.h instead of PCSC/pcsclite.h for __linux__ but now use `pkg-config --cflags libpcsclite` at compilation 2004-06-29 author * Card/Card.pm: ISO7816Error(): return an error if given $sw if not 5 chars long "xx xx" * Card/Card.pm: return (undef) if the protocol is not defined in Transmit. This happens if you change a T=0 card with a T=1 (or vice versa) and try to exchange an APDU without disconnecting first. 2004-06-25 author * Card/Card.pod: add en empty line * PCSCperl.h: - use PCSC/pcsclite.h - replace LPCSTR by LPCTSTR 2004-05-30 author * README: release 1.4.0 * PCSC.pm: ABI changed so change VERSION number * PCSCperl.h: - add support of new SCardControl() API through Control() - now loads libpcsclite.so.1 instead of libpcsclite.so.0 * Card/Card.pm, Card/Card.pod, PCSC.xs, test.pl, test/single_reader.pl: add support of new SCardControl() API 2004-04-02 author * README: release 1.3.1 * PCSC.pod: document GetStatusChange() * test.pl: add demo code for GetStatusChange() * PCSC.xs, PCSCperl.h: use dynamic table and avoid using the deprecated PCSCLITE_MAX_CHANNELS 2004-01-18 author * Card/Card.pm, Card/Card.pod: Use regular expression "90 [10]0" instead of "90 [1,0]0" * Card/Card.pm: allow commands to be in the form "00A40100020100" instead of "00 A4 01 00 02 01 00" 2003-12-13 author * README: release 1.3.0 * Card/Card.pod: add documentation for Control() * test.pl: simplify the sample code for Control() since array_to_ascii() now returns an empty string for an empty list * PCSC.pm: array_to_ascii() return an empty string for an empty list * test.pl, test/single_reader.pl: Comment out the tests for Control since the result is any thing depending on the reader and driver. 2003-12-11 author * PCSC.xs: Windows PCSC has a different behavior and ATR and ReaderName buffers must not be set to NULL. Thanks to Andrew Kay for the patch. * MANIFEST: add Makefile_win.PL * Card/Card.pm, PCSC.xs, PCSCperl.h, test.pl, test/single_reader.pl: Add support for SCardControl with $out = $hContext->Control (\@in); 2003-12-10 author * Card/Card.pod: some repaging. * Card/Card.pod: correct a typo 2003-12-09 author * Card/Card.pm, Card/Card.pod: by default use T=0 | T=1 protocols instead of just T=0 * PCSC.xs: Initalise ioRecvPci structure in Transmit(). Patch from Troy Curtiss. * PCSCperl.h: add #define PCSCLITE_MAX_CHANNELS for Windows plateforms * Makefile_win.PL: new file to support Windows platforms 2003-05-27 author * README: release 1.2.2 * MANIFEST: Makefile_OSX.pl is renamed Makefile_OSX.PL since it was not a correct solution to avoid automatic use by Perl. We use PL_FILES instead. * Makefile_OSX.PL: use the new naming scheme and add PL_FILES line to avoid problems with the other Makefile.PL * Makefile.PL: add PL_FILES line to avoid problem with Makefile_OSX.PL 2003-05-25 author * README.OSX: addapted comment to the updated Makefile_OSX.PL * Makefile_OSX.PL: remove #!/usr/bin/perl -w * Card/Card.pm, PCSC.pm: removed #!/usr/bin/perl as suggested by Ville Skyttä * PCSC.pm: add constant definition (thanks to Ville Skyttä for report and patch) 2003-05-24 author * README: release 1.2.1 * MANIFEST: Card/test.pl removed * MANIFEST: test_iso_error.pl moved into examples * MANIFEST: files have moved * Card/Makefile.PL: new file to install Card/Card.* * Makefile.PL: moved files from Chipcard/ to . * test.pl: wait for ".. .." in TransmitWithCheck test since the SW will depend on the inserted card * Card/Card.pm: add a version number * Card/Card.pm: Chipcard::PCSC::Utils.pm no longer exists 2003-05-10 author * MANIFEST, Card/Card.pm, Card/Utils.pm: Utils.pm merged into Card.pm 2003-05-09 author * Card/Card.pod: example are now in typewriter text * Card/Card.pod: typos * MANIFEST: PCSC.pod moved from . to Chipcard/ * README: release 1.2.0 * MANIFEST: add Chipcard/PCSC/Utils.pm and test_iso_error.pl * create_distrib.sh: use 'mkdir -p' instead of just 'mkdir' * create_distrib.sh: make distclean only if Makefile exists * create_distrib.sh: make distclean before anything else * test.pl: add test support of TransmitWithCheck and Chipcard::PCSC::Card::ISO7816Error * examples/test_iso_error.pl: small script to test output of Chipcard::PCSC::Card::ISO7816Error() * Card/Card.pod: add documentation for TransmitWithCheck() and ISO7816Error() * Card/Utils.pm: two new functions: TransmitWithCheck() and ISO7816Error() * test/multiple_readers.pl: cleanly exit if a second reader is not found * t/test.t: remove Log list * Card/Card.pm: some reformating 2003-05-06 author * examples/gsm_directory.pl, t/test.t, test/multiple_readers.pl, test/single_reader.pl, Card/Card.pm, Card/Card.pod, MANIFEST, Makefile.PL, PCSC.pm, PCSC.pod, PCSC.xs, PCSCperl.h, test.pl: naming scheme migration from PCSC to Chipcard::PCSC 2002-11-07 author * README: release 1.1.3 2002-08-29 author * PCSC.xs: add a pTHX_ cast to make it work with Perl 5.8 * PCSC.pm: add prototypes and contants definitions 2002-08-28 author * README: release 1.1.2 * PCSCperl.h: link against libpcsclite.so.0 instead of libpcsclite.so 2002-05-16 author * PCSC.xs: Modified error handling to use warn() instead of the more destructive croak()... croak() only remains for blocking problems such as a missing libraryetc... Implemented GetStatusChange and Cancel * PCSC.pm: Added support for GetStatusChange and Cancel 2002-03-07 author * README: release 1.1.1 * Card/Card.pm, Card/Card.pod, PCSC.pod, PCSC.xs: use bold for commands changed -> into -E (reverse patch :-) 2002-03-06 author * PCSCperl.h: comment unused variable declarations * Makefile.PL: add "-O2 -Wall" arguments * MANIFEST: add README file * README: release 1.1.0 * README.Unix: removed release reference. See README instead * Card/Card.pod, PCSC.pod: complete reindentation * PCSC.xs: correct line wrap in licence text 2002-03-05 author * README.Unix: Release 1.0.9 * PCSC.pm, README.Unix: correctly test if a digit is hexa or not * Card/Card.pm: the minium APDU length is 4 bytes and not 5 2001-10-18 author * MANIFEST: added LICENCE * LICENCE: Added GPL LICENCE * README.Unix: Release 1.0.8 * create_distrib.sh: format is foo-bar-x.y.z not foo-bar.x.y.z * create_distrib.sh: removed debian/ from the official archive * MANIFEST, README.Windows, remarks.txt: remarks.txt renamed README.Windows * MANIFEST, create_distrib.sh: added some comments, remove exit used for debug * MANIFEST, create_distrib.sh: compare the files in the directory with MANIFEST to check all the files will be included in the archive 2001-10-17 author * create_distrib.sh: Added checks: directory name format, directory existance 2001-10-16 author * MANIFEST: removed scriptor and gscriptor scripts (moved to pcsc-tools) * examples/readfile.script: removed * MANIFEST: removed create_distrib.sh from exported files * create_distrib.sh: added automatic creation of Changelog using rcs2log * README.Unix: quick install notes * MANIFEST, create_distrib.sh: *** empty log message *** * create_distrib.sh: create a nice package without Debian specific stuff and CVS directories 2001-10-10 author * t/test.t: Initial check in * PCSC.pm: Added fake variable declarations/initialization to work with make test 2001-09-07 author * examples/gsm_directory.pl: cosmetic chage in the header comment 2001-09-06 author * examples/gsm_directory.pl: added CVS Id and Log fields * examples/gsm_directory.pl: typos in comments * examples/gsm_directory.pl: Added a license 2001-09-05 author * examples/gsm.script, examples/gsm_directory.pl: Added some GSM11.11 demo scripts to gscriptor/scriptor as well as a small example of how to use PCSC-perl to read the directory from your GSM card... * Card/Card.pm: Do not warn anymore when P3(len) is not related to the number of bytes to be transmitted after the APDU * test/single_reader.pl: Added -w flag to #!/usr/bin/perl and corrected some warnings * test/multiple_readers.pl: Added title and author name in the GPL licence * test/single_reader.pl: Added CVS Id and Log fields Added GPL licence * test/multiple_readers.pl: Added -w flag to /usr/bin/perl and corrected some warnings * test/multiple_readers.pl: Added CVS Id and Log fields Added GPL licence * test.pl: Added CVS Log and Id fields Added GPL licence 2001-09-04 author * test/multiple_readers.pl, test/single_reader.pl: Now using the real double typed magical scalar $PCSC::errno to report errors instead of the old $! which was buggy. * test/multiple_readers.pl, test/single_reader.pl: updated the files so that they now use the 'new' package architecture i.e.: PCSC + PCSC::Card insteead of PCSC + PCSCCard... * PCSC.pm: tried to make the @EXPORT @ISA $VERSION variable use more standard (At least I hope so) * PCSC.pm: Fixed a bug in PCSC::ascii_to_array(). The returned array was global therefore, each call to the function was returning all the arrays since the object initialization. I now use 'use strict' to avoid such problems in the future but I do not know if I do it the proper way... I had to modify EXPORT and such to make it run * test/multiple_readers.pl, test/single_reader.pl: More cosmetic changes * Card/Card.pm, Card/Card.pod, PCSC.pm, PCSC.pod, PCSC.xs, test.pl: Applied a patch from somebody who apparently wants to stay anonymous. This patch includes mostly cosmetic changes and extra documentation about array_to_ascii() and ascii_to_array(). Thanks to this contributor for his help and time 2001-07-02 author * PCSC.pod, test.pl: Made minor modifications (corrected some misspelled words in the doc and removed unnecessary commented code) * examples/readfile.script: Initial checkin 2001-06-12 author * README.OSX: Small README about the OS X install. * Makefile_OSX.PL: Changed name tp .pl instead of .PL otherwise MakeMaker tries to run Makefile_OSX.PL * PCSC.pod, PCSC.xs: Modification for Mac OS X support (LOAD_LIB replaced by LOAD_LIB()) * PCSCperl.h: Added support for MacOS X 2001-05-31 author * Card/Card.pm, PCSC.pm: added hash-bang * Card/Card.pm, Card/Card.pod, Makefile.PL, PCSC.pm, PCSC.pod, PCSC.xs, PCSCperl.h, remarks.txt, test.pl, test/multiple_readers.pl, test/single_reader.pl, typemap: Initial import * Card/Card.pm, Card/Card.pod, Makefile.PL, PCSC.pm, PCSC.pod, PCSC.xs, PCSCperl.h, remarks.txt, test.pl, test/multiple_readers.pl, test/single_reader.pl, typemap: New file. Chipcard-PCSC-v1.4.16/MANIFEST000644 000765 000024 00000000573 14526744063 016416 0ustar00rousseaustaff000000 000000 Card/Card.pm Card/Card.pod Card/Makefile.PL Card/t/test.t Changelog LICENCE MANIFEST META.json Makefile.PL PCSC.pm PCSC.pod PCSC.xs PCSCperl.h README examples/gsm.script examples/gsm_directory.pl examples/test_iso_error.pl t/test.t test.pl test/multiple_readers.pl test/single_reader.pl typemap META.yml Module YAML meta-data (added by MakeMaker) Chipcard-PCSC-v1.4.16/PCSC.pm000644 000765 000024 00000020236 14526740446 016352 0ustar00rousseaustaff000000 000000 ########################################################################### # Authors : Lionel VICTOR # # Ludovic ROUSSEAU # Compiler : gcc, Visual C++ # Target : Unix, Windows # # Description : Perl wrapper to the PCSC API # # Copyright (C) 2001 - Lionel VICTOR # Copyright (c) 2003-2010 Ludovic ROUSSEAU # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ########################################################################### package Chipcard::PCSC; require Chipcard::PCSC::Card; require Exporter; require DynaLoader; use warnings; use strict; use Carp; use vars qw($VERSION @ISA @EXPORT); @ISA = qw(Exporter DynaLoader); # Items to export into callers namespace by default. # Note: do not export # names by default without a very good reason. Use # EXPORT_OK instead. # Do not simply export all your public # functions/methods/constants. @EXPORT = qw( ); $VERSION = 'v1.4.16'; bootstrap Chipcard::PCSC $VERSION; # Preloaded methods go here. # We start with some basic conversion function here. They are global to # the package and should not be used through an object instance sub array_to_ascii($) { my $byte_array_ref = shift; confess ("wrong type") unless ref ($byte_array_ref); confess ('usage Chipcard::PCSC::array_to_ascii($string)') unless defined $byte_array_ref; # return an empty string for an empty list return "" if (! @{$byte_array_ref}); my $return_string; my $tmpVal; # format the string with the array's contents foreach $tmpVal (@{$byte_array_ref}) { $return_string .= sprintf ("%02X ", $tmpVal); }; # remove the trailing space or do nothing if the string is empty chop $return_string; return $return_string; } sub ascii_to_array($) { my $ascii_string = shift; my @return_array; my $tmpVal; confess ('usage Chipcard::PCSC::ascii_to_array($string)') unless defined $ascii_string; foreach $tmpVal (split / /, $ascii_string) { croak ("ascii_to_array: wrong value ($tmpVal)") unless ($tmpVal =~ m/^[0-9a-f][0-9a-f]$/i); push @return_array, hex ($tmpVal); } # return a reference to the constructed array return \@return_array; } # Usage: # $my_var = new Chipcard::PCSC ($scope, $remote_host); # # default values: # $scope = $Chipcard::PCSC::SCARD_SCOPE_SYSTEM # $remote_host = 0 (localhost) sub new ($$$) { my $class = shift; my $scope = shift; my $remote_host = shift; my $container = {}; # Apply default values when required $scope = $Chipcard::PCSC::SCARD_SCOPE_SYSTEM unless (defined ($scope)); $remote_host = 0 unless (defined ($remote_host)); $container->{hContext} = _EstablishContext ($scope, $remote_host, 0); return undef unless (defined($container->{hContext})); return bless $container, $class; } sub ListReaders($) { my $self = shift; confess ("wrong type") unless ref $self; my $group = shift; # group is null if not given # $group = 0 unless (defined ($group)); return _ListReaders ($self->{hContext}, $group); } sub GetStatusChange($) { my $self = shift; confess ("wrong type") unless ref $self; my $readers_state = shift; my $nTimeout = shift; # The default timeout value is something supposed to be infinite $nTimeout = 0xFFFFFFFF unless (defined ($nTimeout)); return _GetStatusChange ($self->{hContext}, $nTimeout, $readers_state); } sub Cancel($) { my $self = shift; confess ("wrong type") unless ref $self; return _Cancel ($self->{hContext}); } sub DESTROY($) { my $self = shift; confess ("wrong type") unless ref $self; # Release Chipcard::PCSC context when the object is about to be destroyed my $return_val = _ReleaseContext ($self->{hContext}); # die in case of an error confess ("Can't release context $self->{hContext}: $!") unless (defined ($return_val)); } # Autoload methods go after __END__, and are processed by # the autosplit program. $Chipcard::PCSC::SCARD_ABSENT = 0; $Chipcard::PCSC::SCARD_E_CANCELLED = 0; $Chipcard::PCSC::SCARD_E_CANT_DISPOSE = 0; $Chipcard::PCSC::SCARD_E_CARD_UNSUPPORTED = 0; $Chipcard::PCSC::SCARD_E_DUPLICATE_READER = 0; $Chipcard::PCSC::SCARD_E_INSUFFICIENT_BUFFER = 0; $Chipcard::PCSC::SCARD_E_INVALID_ATR = 0; $Chipcard::PCSC::SCARD_E_INVALID_HANDLE = 0; $Chipcard::PCSC::SCARD_E_INVALID_PARAMETER = 0; $Chipcard::PCSC::SCARD_E_INVALID_TARGET = 0; $Chipcard::PCSC::SCARD_E_INVALID_VALUE = 0; $Chipcard::PCSC::SCARD_EJECT_CARD = 0; $Chipcard::PCSC::SCARD_E_NO_MEMORY = 0; $Chipcard::PCSC::SCARD_E_NO_SERVICE = 0; $Chipcard::PCSC::SCARD_E_NO_SMARTCARD = 0; $Chipcard::PCSC::SCARD_E_NOT_READY = 0; $Chipcard::PCSC::SCARD_E_NOT_TRANSACTED = 0; $Chipcard::PCSC::SCARD_E_PCI_TOO_SMALL = 0; $Chipcard::PCSC::SCARD_E_PROTO_MISMATCH = 0; $Chipcard::PCSC::SCARD_E_READER_UNAVAILABLE = 0; $Chipcard::PCSC::SCARD_E_READER_UNSUPPORTED = 0; $Chipcard::PCSC::SCARD_E_SERVICE_STOPPED = 0; $Chipcard::PCSC::SCARD_E_SHARING_VIOLATION = 0; $Chipcard::PCSC::SCARD_E_SYSTEM_CANCELLED = 0; $Chipcard::PCSC::SCARD_E_TIMEOUT = 0; $Chipcard::PCSC::SCARD_E_UNKNOWN_CARD = 0; $Chipcard::PCSC::SCARD_E_UNKNOWN_READER = 0; $Chipcard::PCSC::SCARD_E_UNSUPPORTED_FEATURE = 0; $Chipcard::PCSC::SCARD_F_COMM_ERROR = 0; $Chipcard::PCSC::SCARD_F_INTERNAL_ERROR = 0; $Chipcard::PCSC::SCARD_F_UNKNOWN_ERROR = 0; $Chipcard::PCSC::SCARD_F_WAITED_TOO_LONG = 0; $Chipcard::PCSC::SCARD_INSERTED = 0; $Chipcard::PCSC::SCARD_LEAVE_CARD = 0; $Chipcard::PCSC::SCARD_NEGOTIABLE = 0; $Chipcard::PCSC::SCARD_POWERED = 0; $Chipcard::PCSC::SCARD_PRESENT = 0; $Chipcard::PCSC::SCARD_REMOVED = 0; $Chipcard::PCSC::SCARD_RESET = 0; $Chipcard::PCSC::SCARD_RESET_CARD = 0; $Chipcard::PCSC::SCARD_SCOPE_GLOBAL = 0; $Chipcard::PCSC::SCARD_SCOPE_TERMINAL = 0; $Chipcard::PCSC::SCARD_SCOPE_USER = 0; $Chipcard::PCSC::SCARD_SHARE_DIRECT = 0; $Chipcard::PCSC::SCARD_SPECIFIC = 0; $Chipcard::PCSC::SCARD_S_SUCCESS = 0; $Chipcard::PCSC::SCARD_STATE_ATRMATCH = 0; $Chipcard::PCSC::SCARD_STATE_CHANGED = 0; $Chipcard::PCSC::SCARD_STATE_EMPTY = 0; $Chipcard::PCSC::SCARD_STATE_EXCLUSIVE = 0; $Chipcard::PCSC::SCARD_STATE_IGNORE = 0; $Chipcard::PCSC::SCARD_STATE_INUSE = 0; $Chipcard::PCSC::SCARD_STATE_MUTE = 0; $Chipcard::PCSC::SCARD_STATE_PRESENT = 0; $Chipcard::PCSC::SCARD_STATE_UNAVAILABLE = 0; $Chipcard::PCSC::SCARD_STATE_UNAWARE = 0; $Chipcard::PCSC::SCARD_STATE_UNKNOWN = 0; $Chipcard::PCSC::SCARD_SWALLOWED = 0; $Chipcard::PCSC::SCARD_UNKNOWN = 0; $Chipcard::PCSC::SCARD_UNPOWER_CARD = 0; $Chipcard::PCSC::SCARD_W_REMOVED_CARD = 0; $Chipcard::PCSC::SCARD_W_RESET_CARD = 0; $Chipcard::PCSC::SCARD_W_SECURITY_VIOLATION = 0; $Chipcard::PCSC::SCARD_W_UNPOWERED_CARD = 0; $Chipcard::PCSC::SCARD_W_UNRESPONSIVE_CARD = 0; $Chipcard::PCSC::SCARD_W_UNSUPPORTED_CARD = 0; $Chipcard::PCSC::SCARD_PROTOCOL_RAW = 4; $Chipcard::PCSC::SCARD_PROTOCOL_T0 = 1; $Chipcard::PCSC::SCARD_PROTOCOL_T1 = 2; $Chipcard::PCSC::SCARD_SHARE_DIRECT = 3; $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE = 1; $Chipcard::PCSC::SCARD_SHARE_SHARED = 2; _LoadPCSCLibrary(); __END__ # Below is the stub of documentation for your module. You # better edit it! Chipcard-PCSC-v1.4.16/t/000755 000765 000024 00000000000 14526744063 015523 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/test.pl000755 000765 000024 00000016066 14526143072 016601 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # test.pl: simple sample program to test the PCSC Perl wrapper # Copyright (C) 2001 Lionel Victor, 2003,2006 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use Test::More; use Chipcard::PCSC; use Chipcard::PCSC::Card; plan 'no_plan'; use warnings; use strict; my $hContext; my @ReadersList; my $hCard; my @StatusResult; my $tmpVal; my $SendData; my $RecvData; my $sw; #-------------------------------------------------------------------------- diag("Getting context:"); $hContext = new Chipcard::PCSC(); die ("Can't create the pcsc object: $Chipcard::PCSC::errno\n") unless (defined $hContext); ok(defined $hContext, "new Chipcard::PCSC()"); #-------------------------------------------------------------------------- diag("Retrieving readers'list:"); @ReadersList = $hContext->ListReaders (); die ("Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); $, = "\n "; $" = "\n "; ok(defined($ReadersList[0]), "\$hContext->ListReaders ()"); diag(@ReadersList); #-------------------------------------------------------------------------- diag("Getting status change:"); my (@readers_states, $reader_state, $timeout, $event_state); # create the list or readers to watch map { push @readers_states, ({'reader_name'=>"$_"}) } @ReadersList; @StatusResult = $hContext->GetStatusChange(\@readers_states); for my $i (0..$#readers_states) { diag("reader: " . $readers_states[$i]{'reader_name'}); diag(" ATR: " . Chipcard::PCSC::array_to_ascii($readers_states[$i]{'ATR'})) if (defined $readers_states[$i]{'ATR'}); diag(" state:"); $event_state = $readers_states[$i]{'event_state'}; diag(" state changed") if ($event_state & $Chipcard::PCSC::SCARD_STATE_CHANGED); diag(" card present") if ($event_state & $Chipcard::PCSC::SCARD_STATE_PRESENT); diag(" card absent") if ($event_state & $Chipcard::PCSC::SCARD_STATE_EMPTY); diag(" card mute") if ($event_state & $Chipcard::PCSC::SCARD_STATE_MUTE); $readers_states[$i]{'current_state'} = $event_state; } if (! ($readers_states[0]{'event_state'} & $Chipcard::PCSC::SCARD_STATE_PRESENT)) { $timeout = 10 * 1000; # 10 seconds diag("Insert a card in the first reader please (timeout in $timeout ms)"); @StatusResult = $hContext->GetStatusChange(\@readers_states, $timeout); } #-------------------------------------------------------------------------- diag("Connecting to the card:"); $hCard = new Chipcard::PCSC::Card ($hContext); die ("Can't create the reader object: $Chipcard::PCSC::errno\n") unless (defined($hCard)); $tmpVal = $hCard->Connect($ReadersList[0], $Chipcard::PCSC::SCARD_SHARE_SHARED); unless ($tmpVal) { # Try to reconnect and reset if connect fails diag("Connect failed: trying to reset the card:"); $tmpVal = $hCard->Reconnect ($Chipcard::PCSC::SCARD_SHARE_SHARED, $Chipcard::PCSC::SCARD_PROTOCOL_T0, $Chipcard::PCSC::SCARD_RESET_CARD); die ("Can't reconnect to the reader '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless ($tmpVal); } ok($hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_T0 || $hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_T1 || $hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_RAW, "Can understand the current protocol: $hCard->{dwProtocol}"); #-------------------------------------------------------------------------- diag("Getting status:"); @StatusResult = $hCard->Status(); die ("Can't get status: $Chipcard::PCSC::errno\n") unless ($StatusResult[0]); diag("Reader name is $StatusResult[0]"); diag("State: $StatusResult[1]"); diag("Current protocol: $StatusResult[2]"); diag("ATR: " . Chipcard::PCSC::array_to_ascii ($StatusResult[3])); #-------------------------------------------------------------------------- diag("Initiating transaction:"); die ("Can't initiate transaction: $Chipcard::PCSC::errno\n") unless ($hCard->BeginTransaction()); diag($hCard->BeginTransaction(), "\$hCard->BeginTransaction()"); #-------------------------------------------------------------------------- diag("Exchanging data:"); $SendData = Chipcard::PCSC::ascii_to_array ("00 A4 01 00 02 01 00"); $RecvData = $hCard->Transmit($SendData); die ("Can't transmit data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); diag(" Send -> " . Chipcard::PCSC::array_to_ascii ($SendData)); diag(" Recv <- " . Chipcard::PCSC::array_to_ascii ($RecvData)); #-------------------------------------------------------------------------- diag("TransmitWithCheck:"); $SendData = "00 A4 00 00 02 3F 00"; # select DF 3F 00 # wait for ".. .." since we the SW will depend on the inserted card ($sw, $RecvData) = $hCard->TransmitWithCheck($SendData, ".. ..", 1); warn "TransmitWithCheck: $Chipcard::PCSC::Card::Error" unless defined $sw; ok(defined $sw, "\$hCard->TransmitWithCheck"); diag(" Send -> $SendData"); diag(" Recv <- $RecvData (SW: $sw)"); #-------------------------------------------------------------------------- diag("ISO7816Error:"); diag("$sw: " . &Chipcard::PCSC::Card::ISO7816Error($sw)); #-------------------------------------------------------------------------- # This test is commented since it is reader/driver specific and may do bad # things for another reader. Reader your reader and driver # specifications to know what data to use. # #diag("Control"); #$SendData = Chipcard::PCSC::ascii_to_array ("02"); #$RecvData = $hCard->Control(0x42000001, $SendData); #die ("Can't Control data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); # #diag(" Send -> " . Chipcard::PCSC::array_to_ascii ($SendData)); #diag(" Recv <- " . Chipcard::PCSC::array_to_ascii ($RecvData)); #-------------------------------------------------------------------------- diag("Ending transaction:"); die ("Can't terminate transaction: $Chipcard::PCSC::errno\n") unless ($hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD)); ok($hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD), "\$hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD)"); #-------------------------------------------------------------------------- diag("Disconnecting the card:"); $tmpVal = $hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); die ("Can't disconnect the Chipcard::PCSC object: $Chipcard::PCSC::errno\n") unless $tmpVal; ok($tmpVal, "\$hCard->Disconnect"); #-------------------------------------------------------------------------- diag("Closing card object:"); $hCard = undef; #-------------------------------------------------------------------------- diag("Closing context:"); $hContext = undef; # End of File # Chipcard-PCSC-v1.4.16/README000644 000765 000024 00000014571 14526143206 016140 0ustar00rousseaustaff000000 000000 Perl interface to the PC/SC smart card library ============================================== This package contains a Perl wrapper to the PC/SC smartcard library (pcsc-lite) [1] from MUSCLE [2] together with some small examples. You can find applications using this wrapper in the pcsc-tools package [3]. [1] http://pcsclite.alioth.debian.org/ [2] http://www.musclecard.com/ [3] http://ludovic.rousseau.free.fr/softwares/pcsc-tools/ Build and Install: ================== A very quick documentation on how to build and install the wrapper. $ perl Makefile.PL $ make Insert a smart card in the (first) PCSC reader $ make test $ sudo make install Remarks: ======== For Windows users: Status behaves different on Unix and from Win32 it returns the Atr len it does not return any error like Authors: ======== - Lionel VICTOR for the main part of the job - Ludovic ROUSSEAU for the debug and maintainance Licences: ========= pcsc-perl: wrapper to the PC/SC smartcard library Copyright (C) 2001-2003 Lionel VICTOR Copyright (C) 2001-2010 Ludovic ROUSSEAU This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA History: ======== 1.4.15 - 18 November 2023, Ludovic ROUSSEAU - add support of SCARD_W_SECURITY_VIOLATION error code 1.4.14 - 19 November 2015, Ludovic ROUSSEAU - Fix _StringifyError() on Mac OS X. The string version of PCSC::errno now works. 1.4.13 - 1 April 2013, Ludovic ROUSSEAU - Fix a warning with Perl 5.16 1.4.12 - 6 March 2011, Ludovic ROUSSEAU - Also check for SVt_PVIV and not just SVt_IV. Fixes Debian bug #613722 "libpcsc-perl: GetStatusChange error after print" 1.4.11 - 27 October 2010, Ludovic ROUSSEAU - Do not use SCardSetTimout() since it is no more present in pcsc-lite > 1.6.4 1.4.10 - 18 August 2010, Ludovic ROUSSEAU - Use LPSCARD_READERSTATE instead of LPSCARD_READERSTATE_A since it is no more defined in pcsc-lite >= 1.6.2 1.4.9 - 30 June 2010, Ludovic ROUSSEAU - remove reference to SCARD_W_INSERTED_CARD since it is no more define in pcsc-lite 1.6.0 Thanks to Olivier Huber for the bug report 1.4.8 - 23 September 2009, Ludovic ROUSSEAU - minor bugs fixed 1.4.7 - 26 March 2008, Ludovic ROUSSEAU - merge all the Makefile.PL.* in Makefile.PL 1.4.6 - 7 March 2007, Ludovic ROUSSEAU - add support of GNU/kFreeBSD 1.4.5 - 2 March 2007, Ludovic ROUSSEAU - remove some pcsc-lite specific constants to make it compile against pcsc-lite 1.4.0 1.4.4 - 12 August 2006, Ludovic ROUSSEAU - add support of extended APDU 1.4.3 - 16 May 2006, Ludovic ROUSSEAU - update for Mac OS X Tiger 1.4.2 - 6 August 2004, Ludovic ROUSSEAU - allow to use SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 as the protocol this is used by gscriptor 1.4.0 1.4.1 - 4 July 2004, Ludovic ROUSSEAU - Card/Card.pm: . ISO7816Error(): return an error if given $sw if not 5 chars long "xx xx" . Transmit(): return (undef) if the protocol is not defined. This happens if you change a T=0 card with a T=1 (or vice versa) and try to exchange an APDU without disconnecting first. - PCSCperl.h: replace LPCSTR by LPCTSTR (pcsc-lite 1.2.9 beta4) 1.4.0 - 20 May 2004, Ludovic ROUSSEAU - use a new Control() API to reflect the change in SCardControl() in pcsc-lite. We now have $RecvData = $hCard->Control($control_code, \@SendData); - load libpcsclite.so.1 instead of libpcsclite.so.0 1.3.1 - 2 April 2004, Ludovic ROUSSEAU - do not use PCSCLITE_MAX_CHANNELS anymor since it is no more defined by pcsc-lite > 1.2.0 and is not defined under Windows - test.pl: add demo code for GetStatusChange() - PCSC.pod: document GetStatusChange() - allow commands to be in the form "00A40100020100" instead of just "00 A4 01 0 0 02 01 00" 1.3.0 - 13 December 2003, Ludovic ROUSSEAU - add support of SCardControl with $out = $hContext->Control (\@in); Thanks to Andrew Kay. - more support of Windows PC/SC and compiler. Thanks to Andrew Kay and Troy Curtiss - array_to_ascii() returns an empty string for an empty list - add Makefile_win.PL for Windows - Card.pm: by default use T=0 | T=1 protocols instead of just T=0 1.2.2 - 27 May 2003, Ludovic ROUSSEAU - add two constant definitions in PCSC.pm. Thanks to Ville Skyttä for report and patch - add a PL_FILES section in Makefile*.PL to avoid problem since we have Makefile.PL and Makefile_OSX.PL. Again thanks goes to Ville Skyttä - Also thanks to Wolfgang Hommel for uploading the package to CPAN and registering the official name Chipcard::PCSC (Wolfgang is maintainer of the Chipcard::CTAPI wrapper) 1.2.1 - 24 May 2003, Ludovic ROUSSEAU - redesign the Makefile.PL to make the modules at least installable - add Card/Makefile.PL to also install Chipcard::PCSC::Card - modified test.pl to accept any SW in TransmitWithCheck 1.2.0 - 9 May 2003, Ludovic ROUSSEAU - naming scheme migration from PCSC to Chipcard::PCSC - add TransmitWithCheck() and Chipcard::PCSC::Card::ISO7816Error() functions 1.1.3 - 7 Nov 2002, Ludovic ROUSSEAU - small modifications to support Perl 5.8 1.1.2 - 28 Aug 2002, Ludovic ROUSSEAU - small modification to link against libpcsclite.so.0 instead of libpcsclite.so since libpcsclite.so should only be available on development platforms (-dev packages). 1.1.1 - 7 Mar 2002, Ludovic ROUSSEAU - small typesetting modifications od .pod files 1.1.0 - 6 Mar 2002, Ludovic ROUSSEAU - create this README file with the history - complete reindentation of .pod files 1.0.9 - 5 Mar 2002, Ludovic ROUSSEAU - the minium APDU length is 4 bytes and not 5 - correctly test if a digit is hexa or not 1.0.8 - 18 Oct 2001, Ludovic ROUSSEAU Chipcard-PCSC-v1.4.16/typemap000644 000765 000024 00000000025 14525227554 016657 0ustar00rousseaustaff000000 000000 const char * T_PV Chipcard-PCSC-v1.4.16/examples/000755 000765 000024 00000000000 14526744063 017076 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/META.yml000644 000765 000024 00000001202 14526744063 016524 0ustar00rousseaustaff000000 000000 --- abstract: 'Communicate with a smart card using PC/SC from a Perl script' author: - 'Ludovic ROUSSEAU ' - 'Lionel VICTOR' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: gpl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Chipcard-PCSC no_index: directory: - t - inc resources: homepage: https://pcsc-perl.apdu.fr/ version: v1.4.16 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Chipcard-PCSC-v1.4.16/PCSC.pod000644 000765 000024 00000017616 14526143072 016520 0ustar00rousseaustaff000000 000000 =head1 NAME Chipcard::PCSC - Smart card reader interface library =head1 SYNOPSIS my $hContext = new Chipcard::PCSC(); @ReadersList = $hContext->ListReaders (); $hContext->GetStatusChange(\@readers_states, $timeout); $apdu = Chipcard::PCSC::array_to_ascii(@apdu); @apdu = Chipcard::PCSC::ascii_to_array($apdu); $hContext = undef; =head1 DESCRIPTION The PCSC module implements the Chipcard::PCSC class. Objects of this class are used to communicate with the PCSC-lite daemon (see F for more information). PC/SC represents an abstraction layer to smart card readers. It provides a communication layer with a wide variety of smart card readers through a standardized API. A PCSC object can be used to communicate with more than one reader through Chipcard::PCSC::Card objects. Please read L for extended information on how to talk to a smart card reader. A PCSC object uses the following property: C<$pcsc_object-E{hContext}> the context returned by the pcsc library =head1 CONSTRUCTORS The following methods can be used to construct a PCSC object: =over 4 =item * B<$hContext = new Chipcard::PCSC($scope, $remote_host);> =over 4 =item * C<$scope> is the scope of the connection to the PC/SC daemon. It can be any of the following: $Chipcard::PCSC::SCARD_SCOPE_USER (not used by PCSClite); $Chipcard::PCSC::SCARD_SCOPE_TERMINAL (not used by PCSClite); $Chipcard::PCSC::SCARD_SCOPE_SYSTEM Services on the local machine; $Chipcard::PCSC::SCARD_SCOPE_GLOBAL Services on a remote host. =item * C<$remote_host> is the host name of the remote machine to contact. It is only used when C<$scope> is equal to C<$Chipcard::PCSC::SCARD_SCOPE_GLOBAL>. A null value means F. =back =item * B<$hContext = new Chipcard::PCSC($scope);> This method is equivalent to: $hContext = new Chipcard::PCSC($scope, 0); =item * B<$hContext = new Chipcard::PCSC();> This method is equivalent to: $hContext = new Chipcard::PCSC($Chipcard::PCSC::SCARD_SCOPE_SYSTEM, 0); =back =head1 CONSTRUCTION FAILURE Chipcard::PCSC constructors return an C value when the object can not be created. C<$Chipcard::PCSC::errno> can be used to get more information about the error. (See section L below for more information) =head1 Chipcard::PCSC METHODS Here is a list of all the methods that can be used with a PCSC object. =over 4 =item * BListReaders( $group );> This method returns the available readers in the given C<$group>. If omitted, C<$group> defaults to a null value meaning "all groups". Please note that as of this writing, C<$group> can safely be omitted as it is not used by PCSClite. The return value upon successful completion is an array of strings: one string by available reader. If an error occurred, the undef value is returned and C<$Chipcard::PCSC::errno> should be used to get more information about the error. (See section L below for more information). The following example describes the use of L: $hContext = new Chipcard::PCSC(); die ("Can't create the PCSC object: $Chipcard::PCSC::errno\n") unless (defined $hContext); @ReadersList = $hContext->ListReaders (); die ("Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); $, = "\n "; print @ReadersList . "\n"; =item * B<$hContext-EGetStatusChange(\@readers_states, $timeout);> The method C<$hContext-EGetStatusChange(\@readers_states, $timeout)> uses a reference to a list of hashes. # create the list or readers to watch map { push @readers_states, ({'reader_name'=>"$_"}) } @ReadersList; @StatusResult = $hContext->GetStatusChange(\@readers_states); The keys of the hash are: 'reader_name', 'current_state', 'event_state' and 'ATR'. To detect a status change you have to first get the status and then copy the 'event_state' in the 'current_state'. The method will return when both states are different or a timeout occurs. @StatusResult = $hContext->GetStatusChange(\@readers_states); foreach $reader (@readers_states) { $reader->{current_state} = $reader->{event_state}; } @StatusResult = $hContext->GetStatusChange(\@readers_states); =item * B<$hContext-EGetStatusChange(\@readers_states);> This method is equivalent to: $hContext->GetStatusChange(\@readers_states, 0xFFFFFFFF); The timeout is set to infinite. =item * B<$apdu_ref = Chipcard::PCSC::ascii_to_array($apdu);> The method C uses references to arrays as in and out parameters. The C is used to transform an APDU in ASCII format to a reference to an array in the good format. Example: $SendData = Chipcard::PCSC::ascii_to_array("00 A4 01 00 02 01 00"); =item * B<$apdu = Chipcard::PCSC::array_to_ascii($apdu_ref);> This method is used to convert the result of a C into ASCII format. Example: $RecvData = $hCard->Transmit($SendData); print Chipcard::PCSC::array_to_ascii($RecvData); =back =head1 ERROR HANDLING All functions from PCSC objects save the return value in a global variable called C<$Chipcard::PCSC::errno>. This variable therefore holds the latest status of PCSC. It is a double-typed magical variable that behaves just like C<$!>. This means that it both holds a numerical value describing the error and the corresponding string. The numerical value may change from a system to another as it depends on the PCSC library... Here is a small example of how to use it: $hContext = new Chipcard::PCSC(); die ("Can't create the PCSC object: $Chipcard::PCSC::errno\n") unless (defined $hContext); In case the last call was successful, C<$Chipcard::PCSC::errno> contains the C status. Here is a list of all possible error codes. They are defined as read-only variables with in the PCSC module: $Chipcard::PCSC::SCARD_S_SUCCESS $Chipcard::PCSC::SCARD_E_CANCELLED $Chipcard::PCSC::SCARD_E_CANT_DISPOSE $Chipcard::PCSC::SCARD_E_CARD_UNSUPPORTED $Chipcard::PCSC::SCARD_E_DUPLICATE_READER $Chipcard::PCSC::SCARD_E_INSUFFICIENT_BUFFER $Chipcard::PCSC::SCARD_E_INVALID_ATR $Chipcard::PCSC::SCARD_E_INVALID_HANDLE $Chipcard::PCSC::SCARD_E_INVALID_PARAMETER $Chipcard::PCSC::SCARD_E_INVALID_TARGET $Chipcard::PCSC::SCARD_E_INVALID_VALUE $Chipcard::PCSC::SCARD_E_NO_MEMORY $Chipcard::PCSC::SCARD_E_NO_SERVICE $Chipcard::PCSC::SCARD_E_NO_SMARTCARD $Chipcard::PCSC::SCARD_E_NOT_READY $Chipcard::PCSC::SCARD_E_NOT_TRANSACTED $Chipcard::PCSC::SCARD_E_PCI_TOO_SMALL $Chipcard::PCSC::SCARD_E_PROTO_MISMATCH $Chipcard::PCSC::SCARD_E_READER_UNAVAILABLE $Chipcard::PCSC::SCARD_E_READER_UNSUPPORTED $Chipcard::PCSC::SCARD_E_SERVICE_STOPPED $Chipcard::PCSC::SCARD_E_SHARING_VIOLATION $Chipcard::PCSC::SCARD_E_SYSTEM_CANCELLED $Chipcard::PCSC::SCARD_E_TIMEOUT $Chipcard::PCSC::SCARD_E_UNKNOWN_CARD $Chipcard::PCSC::SCARD_E_UNKNOWN_READER $Chipcard::PCSC::SCARD_E_UNSUPPORTED_FEATURE $Chipcard::PCSC::SCARD_W_REMOVED_CARD $Chipcard::PCSC::SCARD_W_RESET_CARD $Chipcard::PCSC::SCARD_W_SECURITY_VIOLATION $Chipcard::PCSC::SCARD_W_UNPOWERED_CARD $Chipcard::PCSC::SCARD_W_UNRESPONSIVE_CARD $Chipcard::PCSC::SCARD_W_UNSUPPORTED_CARD PCSClite users will also be able to use the following (PCSClite specific) codes: $Chipcard::PCSC::SCARD_INSERTED $Chipcard::PCSC::SCARD_REMOVED $Chipcard::PCSC::SCARD_RESET $Chipcard::PCSC::SCARD_SCOPE_GLOBAL In addition, the wrapper defines: $Chipcard::PCSC::SCARD_P_ALREADY_CONNECTED $Chipcard::PCSC::SCARD_P_NOT_CONNECTED =head1 SEE ALSO F manpage has useful information about PC/SC lite. L manpage gives information about how to communicate with a reader and the smart card inside it. =head1 COPYRIGHT (C) Lionel VICTOR & Ludovic ROUSSEAU, 2001-2004, GNU GPL (C) Ludovic ROUSSEAU, 2005-2008, GNU GPL =head1 AUTHORS / ACKNOWLEDGEMENT Lionel VICTOR Ludovic ROUSSEAU =cut Chipcard-PCSC-v1.4.16/Makefile.PL000644 000765 000024 00000002146 14526453747 017243 0ustar00rousseaustaff000000 000000 use ExtUtils::MakeMaker; # See ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. use Config; use strict; my $lddflags = ""; my $inc = ""; print "osname: $Config{'osname'}\n"; if ($Config{'osname'} eq "darwin") { # Mac OS X $lddflags = $Config{lddlflags} . ' -framework CoreFoundation'; } else { if ($Config{'osname'} eq "MSWin32") { # Windows } else { # other Unixes $inc = '`pkg-config --cflags libpcsclite`'; } } print "LDDFLAGS: $lddflags\n"; print "INC: $inc\n"; WriteMakefile( 'NAME' => 'Chipcard::PCSC', 'VERSION_FROM' => 'PCSC.pm', # finds $VERSION AUTHOR => ['Ludovic ROUSSEAU ', 'Lionel VICTOR'], ABSTRACT => 'Communicate with a smart card using PC/SC from a Perl script', LICENSE => 'gpl_2', 'LIBS' => [''], # e.g., '-lm' 'LDDLFLAGS' => $lddflags, 'DEFINE' => '-O2 -Wall', # e.g., '-DHAVE_SOMETHING' 'INC' => $inc, 'PL_FILES' => {}, META_MERGE => { resources => { homepage => 'https://pcsc-perl.apdu.fr/', } } ); Chipcard-PCSC-v1.4.16/LICENCE000644 000765 000024 00000043254 14526143043 016244 0ustar00rousseaustaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. Chipcard-PCSC-v1.4.16/META.json000644 000765 000024 00000001721 14526744063 016702 0ustar00rousseaustaff000000 000000 { "abstract" : "Communicate with a smart card using PC/SC from a Perl script", "author" : [ "Ludovic ROUSSEAU ", "Lionel VICTOR" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "gpl_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Chipcard-PCSC", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } } }, "release_status" : "stable", "resources" : { "homepage" : "https://pcsc-perl.apdu.fr/" }, "version" : "v1.4.16", "x_serialization_backend" : "JSON::PP version 4.02" } Chipcard-PCSC-v1.4.16/examples/gsm.script000644 000765 000024 00000001027 14525227554 021112 0ustar00rousseaustaff000000 000000 # Select MF (3F00) # expect 9Fxx A0 A4 00 00 02 3F 00 # Select DF Telecom (7F10) # expect 9Fxx A0 A4 00 00 02 7F 10 # EF_ADN (6F3A) (Abbreviated Dialing Numbers) # expect 9F0F A0 A4 00 00 02 6F 3A # Get Reponse # expect 15 bytes of infos + 9000 # last info byte gives the record length A0 C0 00 00 0F # PIN auth (pin is 1234) # ASCII 31 32 33 34 # + FF up to 8 bytes) # expect 9000 A0 20 00 01 08 31 32 33 34 FF FF FF FF # Read record 01 # length 1A is given by the last byte from # get response (excluding the SW) A0 B2 01 04 1A Chipcard-PCSC-v1.4.16/examples/gsm_directory.pl000755 000765 000024 00000015104 14526143072 022302 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # This program reads the phone directory of a GSM11.11 SIM card and # prints out its contents in a human readable format. It is based on # another Perl script from Ludovic ROUSSEAU # That you can obtain at the following URL: # http://ludovic.rousseau.free.fr/softwares/SIM-1.0.tar.gz # # Copyright (C) 2001 - Lionel VICTOR, 2003 Ludovic ROUSSEAU # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use warnings; use strict; use Carp; use Chipcard::PCSC; use Chipcard::PCSC::Card; use Getopt::Std; use Term::ReadKey; my %options; my $hContext = new Chipcard::PCSC(); my $hCard; my $RecvData; my $nRecordsLength; my $PIN; die ("Could not create PCSC object: $Chipcard::PCSC::errno\n") unless defined $hContext; sub gsmrecord_to_ascii { my $gsmrecord = shift; my $out_string = ''; my $delta = $#$gsmrecord-27; my $i; if ($$gsmrecord[0] != 0xFF) { for $i (0..14+$delta-1) { if ($$gsmrecord[$i] != 0xFF) { $out_string.=chr($$gsmrecord[$i]) } else { $out_string.=' '; } } my $phone_length = $$gsmrecord[14] - 2; if ($phone_length > 0) { my $digit; $out_string .= '-> '; for $i (16+$delta..$#$gsmrecord) { $digit = $$gsmrecord[$i]&0x0F; $out_string .= sprintf ("%01X", $digit) if ($digit!=0x0F); $digit = ($$gsmrecord[$i]&0xF0)>>4; $out_string .= sprintf ("%01X", $digit) if ($digit!=0x0F); } } else { $out_string.= "null or invalid phone"; } } return $out_string; } sub pin_to_array { my $pin = shift; my @array; confess ("PIN code must not exceed 8 bytes.") unless (length $pin <= 8); $pin =~ s/(.)/$1 /g; @array = split / /, $pin; @array = map (ord, @array); # Pad the array with 0xFF up to 8 bytes while ($#array < 7) { push @array, 0xFF; } return @array; } getopt ('hvr:', \%options); if (exists $options{h}) { #TODO print "TODO: usage -v verbose -r reader -h help"; } if (exists $options{r}) { $hCard = new Chipcard::PCSC::Card ($hContext, $options{r}); die ("Can't allocate PCSCCard object: $Chipcard::PCSC::errno\n") unless defined $hCard; print STDERR "Using given card reader: $options{r}\n" if exists $options{'v'}; } else { my @readers_list = $hContext->ListReaders (); die ("Can't get readers list: $Chipcard::PCSC::errno\n") unless defined $readers_list[0]; print STDERR "No reader given: using $readers_list[0]\n" if exists $options{v}; $hCard = new Chipcard::PCSC::Card ($hContext, $readers_list[0]); die ("Can't allocate PCSCCard object: $Chipcard::PCSC::errno\n") unless defined $hCard; } # Select MF (3F00) print STDERR "Selecting Master File (3F00)\n" if exists $options{v}; $RecvData = $hCard->Transmit([0xA0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; die ("Can't select MF: SW = [ ".Chipcard::PCSC::array_to_ascii($RecvData)." ]") unless $$RecvData[0] == 0x9F; # Select DF Telecom (7F10) print STDERR "Selecting Telecom Directory (3F00/7F10)\n" if exists $options{v}; $RecvData = $hCard->Transmit([0xA0, 0xA4, 0x00, 0x00, 0x02, 0x7F, 0x10]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; die ("Can't select DF Telecom: SW = [ ".Chipcard::PCSC::array_to_ascii($RecvData)." ]") unless $$RecvData[0] == 0x9F; # Select EF_ADN (6F3A) (Abbreviated Dialing Numbers) print STDERR "Selecting Abbreviated Dialing Numbers File (3F00/7F10/6F3A)\n" if exists $options{v}; $RecvData = $hCard->Transmit([0xA0, 0xA4, 0x00, 0x00, 0x02, 0x6F, 0x3A]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; die ("Can't select EF_ADN: SW = [ ".Chipcard::PCSC::array_to_ascii($RecvData)." ]") unless $$RecvData[0] == 0x9F; # Get Response (get informations about EF_ADN) # The last SW gives the length of available bytes: # 9F xx means there are xx bytes waiting print STDERR "Getting ADN Records length\n" if exists $options{v}; $nRecordsLength = $$RecvData[1]; $RecvData = $hCard->Transmit([0xA0, 0xC0, 0x00, 0x00, $nRecordsLength]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; die ("Can't retrieve records length: SW = [ ".Chipcard::PCSC::array_to_ascii($RecvData)." ]") unless $$RecvData[$nRecordsLength] == 0x90; # Extract record length from the response $nRecordsLength = $$RecvData[$nRecordsLength-1]; print STDERR "Records are $nRecordsLength bytes long\n" if exists $options{v}; # Asks the user for his/her PIN code print STDOUT "Please insert your PIN code:"; ReadMode 'noecho'; $PIN = ReadLine 0; ReadMode 'normal'; chomp $PIN; print STDOUT "\n"; # Submitting PIN code to the card print STDERR "Submitting PIN code\n" if exists $options{v}; $RecvData = $hCard->Transmit([0xA0, 0x20, 0x00, 0x01, 0x08, pin_to_array($PIN)]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; die ("Can't access file (wrong PIN code ?): SW = [ ".Chipcard::PCSC::array_to_ascii($RecvData)." ]") unless $$RecvData[0] == 0x90; # Get phone records my $i; my @SW; print STDERR "Getting records\n" if exists $options{v}; for $i (1..255) { $RecvData = $hCard->Transmit([0xA0, 0xB2, $i, 0x04, $nRecordsLength]); die ("Can't communicate: $Chipcard::PCSC::errno\n") unless defined $RecvData; # pop the status word out of the retrieved bytes $SW[1] = pop @$RecvData; $SW[0] = pop @$RecvData; # Ignore referencing errors (record out of range, file # empty, etc...) but die if anything else bad occurs. die ("Can't read from EF_ADN: SW = [ ".sprintf ("%02X %02X",$SW[0],$SW[1])." ]\n") if ($SW[0] != 0x94 && $SW[0] != 0x90); # Exit if the status word is not 90xx last if $SW[0] != 0x90; # TODO:remove that it is only debug... # TODO: format that and print phone record... print "SLOT $i: ".gsmrecord_to_ascii($RecvData)."\n"; #print "[ ".Chipcard::PCSC::array_to_ascii($RecvData)." ] [".Chipcard::PCSC::array_to_ascii(\@SW)."]\n"; } print STDERR "Reseting the card\n" if exists $options{v}; $hCard->Disconnect($Chipcard::PCSC::SCARD_RESET); # End of File Chipcard-PCSC-v1.4.16/examples/test_iso_error.pl000755 000765 000024 00000002344 14526143072 022474 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # test_iso_error.pl: simple program to test the pcsc Perl wrapper # Copyright (C) 2003 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use ExtUtils::testlib; use Chipcard::PCSC::Card; use warnings; use strict; my ($sw1, $sw2, $sw1hex, $sw2hex, $sw, $error); for $sw1 (0..255) { $sw1hex = sprintf "%02X", $sw1; for $sw2 (0..255) { $sw2hex = sprintf "%02X", $sw2; $sw = "$sw1hex $sw2hex"; $error = &Chipcard::PCSC::Card::ISO7816Error($sw); print "$sw: $error\n" unless ($error =~ m/not defined by ISO/); } } Chipcard-PCSC-v1.4.16/t/test.t000755 000765 000024 00000003352 14526143072 016666 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # test.pl: simple sample program based on test.pl to test the pcsc # Perl wrapper under Test::Harness # Copyright (C) 2001 Lionel Victor, 2003,2006 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use Test::More; use Chipcard::PCSC; plan tests => 2; use strict; use warnings; my $hContext; my @ReadersList; my @StatusResult; my $tmpVal; my $SendData; my $RecvData; #------------------------------------------------------------------------------- $hContext = new Chipcard::PCSC(); #die ("not ok : Can't create the pcsc object: $Chipcard::PCSC::errno\n") unless (defined $hContext); ok(defined $hContext, "new Chipcard::PCSC()"); #------------------------------------------------------------------------------- @ReadersList = $hContext->ListReaders (); #die ("not ok : Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); ok(defined($ReadersList[0]), "\$hContext->ListReaders ()"); #------------------------------------------------------------------------------- $hContext = undef; # End of File # Chipcard-PCSC-v1.4.16/test/single_reader.pl000755 000765 000024 00000011750 14526143072 021377 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # single_reader.pl: test the pcsc Perl wrapper with one reader # copyright (c) 2001 Lionel Victor, 2003 Ludovic Rousseau # # this program is free software; you can redistribute it and/or modify # it under the terms of the gnu general public license as published by # the free software foundation; either version 2 of the license, or # (at your option) any later version. # # this program is distributed in the hope that it will be useful, # but without any warranty; without even the implied warranty of # merchantability or fitness for a particular purpose. see the # gnu general public license for more details. # # you should have received a copy of the gnu general public license # along with this program; if not, write to the free software # foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa use ExtUtils::testlib; use Chipcard::PCSC; use Chipcard::PCSC::Card; use warnings; use strict; #my $current_protocol; #my @StatusResult; my $hContext; my @ReadersList; my $hCard; my @StatusResult; my $tmpVal; my $SendData; my $RecvData; #my @ConnectionContext; #------------------------------------------------------------------------------- print "Getting context:\n"; $hContext = new Chipcard::PCSC(); die ("Can't create the pcsc object: $Chipcard::PCSC::errno\n") unless (defined $hContext); print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Retrieving readers'list:\n"; @ReadersList = $hContext->ListReaders (); die ("Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); $, = "\n "; $" = "\n "; print " @ReadersList\n" . '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Connecting to the card:\n"; $hCard = new Chipcard::PCSC::Card ($hContext, $ReadersList[0]); die ("Can't connect to the reader '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless (defined($hCard)); print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- if ($hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "Don't understand the active protocol, reconnecting to the card:\n"; my $active_protocol = $hCard->Reconnect($Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T1, $Chipcard::PCSC::SCARD_RESET_CARD); die ("Failed to reconnect to '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless (defined($active_protocol)); if ($hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard->{dwProtocol}!=$Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "here is '$hCard->{dwProtocol}'"; die ("Still don't understand the active current protocol: the card may be mute.\n"); } else { print '.'x40 . " OK\n"; } } #------------------------------------------------------------------------------- print "Getting Status:\n"; @StatusResult = $hCard->Status (); die ("Can't get card status: $Chipcard::PCSC::errno\n") unless (defined ($StatusResult[0])); printf " ReaderName = %s\n Status = %X\n Protocol = %X\n ATR = ", $StatusResult[0], $StatusResult[1], $StatusResult[2]; foreach $tmpVal (@{$StatusResult[3]}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print ("Exchanging data:\n"); $SendData = [0x00,0xA4,0x01,0x00, 0x02, 0x10, 0x00]; $RecvData = $hCard->Transmit($SendData); die ("Can't transmit data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); print " Send = "; foreach $tmpVal (@{$SendData}) { printf ("%02X ", $tmpVal); } print "\n"; print " Recv = "; foreach $tmpVal (@{$RecvData}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; # sleep (3); #------------------------------------------------------------------------------- # This test is commented since it is reader/driver specific and may do bad # things for another reader. Reader your reader and driver # specifications to know what data to use. # #print "Control:\n"; #$SendData = [ 0x02 ]; #$RecvData = $hCard->Control(0x42000001, $SendData); #die ("Can't Control: $Chipcard::PCSC::errno") unless (defined ($RecvData)); # #print " Send = "; #foreach $tmpVal (@{$SendData}) { # printf ("%02X ", $tmpVal); #} print "\n"; # #print " Recv = "; #foreach $tmpVal (@{$RecvData}) { # printf ("%02X ", $tmpVal); #} print "\n"; #print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Disconnecting the card:\n"; $hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); undef $hCard; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Closing context:\n"; $hContext = undef; print '.'x40 . " OK\n"; # End of File # Chipcard-PCSC-v1.4.16/test/multiple_readers.pl000755 000765 000024 00000016137 14526143072 022140 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # multiple_readers.pl: test the pcsc Perl wrapper with TWO readers # Copyright (C) 2001 Lionel Victor, 2003 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use ExtUtils::testlib; use Chipcard::PCSC; use warnings; use strict; #my $current_protocol; #my @StatusResult; my $hContext; my @ReadersList; my $hCard; my @StatusResult; my $tmpVal; my $SendData; my $RecvData; my $hCard2; my @StatusResult2; my $tmpVal2; my $SendData2; my $RecvData2; #my @ConnectionContext; #------------------------------------------------------------------------------- print "Getting context:\n"; $hContext = new Chipcard::PCSC(); die ("Can't create the pcsc object: $Chipcard::PCSC::errno\n") unless (defined $hContext); print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Retrieving readers'list:\n"; @ReadersList = $hContext->ListReaders (); die ("Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); $, = "\n "; $" = "\n "; print " @ReadersList\n" . '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Connecting to the card: $ReadersList[0]\n"; $hCard = new Chipcard::PCSC::Card ($hContext, $ReadersList[0]); die ("Can't connect to the reader '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless (defined($hCard)); print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- die "no second reader present" if (! defined $ReadersList[1]); print "Connecting to the card2: $ReadersList[1]\n"; $hCard2 = new Chipcard::PCSC::Card ($hContext, $ReadersList[1]); die ("Can't connect to the reader '$ReadersList[1]': $Chipcard::PCSC::errno\n") unless (defined($hCard2)); print '.'x40 . " OK\n"; # sleep (3); #------------------------------------------------------------------------------- if ($hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "Don't understand the active protocol, reconnecting to the card:\n"; my $active_protocol = $hCard->Reconnect($Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T1, $Chipcard::PCSC::SCARD_RESET_CARD); die ("Failed to reconnect to '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless (defined($active_protocol)); if ($hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "here is '$hCard->{dwProtocol}'"; die ("Still don't understand the active current protocol: the card may be mute.\n"); } else { print '.'x40 . " OK\n"; } } #------------------------------------------------------------------------------- print "Getting Status:\n"; @StatusResult = $hCard->Status (); die ("Can't get card status: $Chipcard::PCSC::errno\n") unless (defined ($StatusResult[0])); printf " ReaderName = %s\n Status = %X\n Protocol = %X\n ATR = ", $StatusResult[0], $StatusResult[1], $StatusResult[2]; foreach $tmpVal (@{$StatusResult[3]}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print ("Exchanging data:\n"); $SendData = [0x00,0xA4,0x01,0x00, 0x02, 0x10, 0x00]; $RecvData = $hCard->Transmit($SendData); die ("Can't transmit data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); print " Send = "; foreach $tmpVal (@{$SendData}) { printf ("%02X ", $tmpVal); } print "\n"; print " Recv = "; foreach $tmpVal (@{$RecvData}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; # sleep (3); #------------------------------------------------------------------------------- if (defined $hCard2 && $hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "Don't understand the active protocol, reconnecting to the card:\n"; my $active_protocol = $hCard2->Reconnect($Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T1, $Chipcard::PCSC::SCARD_RESET_CARD); die ("Failed to reconnect to '$ReadersList[1]': $Chipcard::PCSC::errno\n") unless (defined($active_protocol)); if ($hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T0 && $hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_T1 && $hCard2->{dwProtocol} != $Chipcard::PCSC::SCARD_PROTOCOL_RAW) { print "here is '$hCard2->{dwProtocol}'"; die ("Still don't understand the active current protocol: the card may be mute.\n"); } else { print '.'x40 . " OK\n"; } } #------------------------------------------------------------------------------- print "Getting Status:\n"; @StatusResult = $hCard2->Status (); die ("Can't get card status: $Chipcard::PCSC::errno\n") unless (defined ($StatusResult[0])); printf " ReaderName = %s\n Status = %X\n Protocol = %X\n ATR = ", $StatusResult[0], $StatusResult[1], $StatusResult[2]; foreach $tmpVal (@{$StatusResult[3]}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print ("Exchanging data:\n"); $SendData = [0x00,0xA4,0x00,0x00, 0x02, 0x10, 0x00]; $RecvData = $hCard2->Transmit($SendData); die ("Can't transmit data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); print " Send = "; foreach $tmpVal (@{$SendData}) { printf ("%02X ", $tmpVal); } print "\n"; print " Recv = "; foreach $tmpVal (@{$RecvData}) { printf ("%02X ", $tmpVal); } print "\n"; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Disconnecting the card:\n"; $hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); undef $hCard; print '.'x40 . " OK\n"; #------------------------------------------------------------------------------- print "Disconnecting the card:\n"; $hCard2->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); undef $hCard2; print '.'x40 . " OK\n"; #die ("") unless ($hCard->Disconnect ($Chipcard::PCSC::SCARD_UNPOWER_CARD)); #------------------------------------------------------------------------------- print "Closing context:\n"; $hContext = undef; print '.'x40 . " OK\n"; # End of File # Chipcard-PCSC-v1.4.16/Card/t/000755 000765 000024 00000000000 14526744063 016374 5ustar00rousseaustaff000000 000000 Chipcard-PCSC-v1.4.16/Card/Card.pod000644 000765 000024 00000035427 14526142773 017521 0ustar00rousseaustaff000000 000000 =head1 NAME Chipcard::PCSC::Card - Smart card communication library =head1 SYNOPSIS $hCard = new Chipcard::PCSC::Card ($hContext, "GemPC430 0 0", $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE); $RecvData = $hCard->Transmit([0xBC,0xB0,0x09,0xC8, 2]); $hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); $hCard->Status(); $hCard->BeginTransaction(); $hCard->EndTransaction(); $hCard->TransmitWithCheck($apdu, $sw_expected [, $debug]); $hCard->Control($control_code, \@data); ISO7816Error($sw); =head1 DESCRIPTION The C module implements the C class. Objects from this class are used to communicate with a given reader. They are constructed out of a reference to a PCSC object that drives the reader. For more information about PC/SC please read the F man page. A C object uses the following property: =over 4 =item * B<$pcsccard_object-E{hContext}> the reference to the underlying PCSC object =item * B<$pcsccard_object-E{hCard}> the current PCSC connection handle =item * B<$pcsccard_object-E{dwProtocol}> the protocol being used =back =head1 CONSTRUCTORS The following methods construct a C object: =over 4 =item * B<$hCard = new Chipcard::PCSC::Card ($hContext);> Constructs a new C object without connecting to any reader. C<$hContext> is mandatory and contains the reference to a valid PCSC object. =item * B<$hCard = new Chipcard::PCSC::Card ($hContext, $reader_name, $share_mode, $preferred_protocol);> Constructs a new Chipcard::PCSC::Card object and connect to the specified reader. =over 4 =item * $hContext is mandatory and contains the reference to a valid PCSC object. =item * $reader_name is the name of the reader you want to connect to. It is of the form "GemPC410 0 0". Please note that the list of available readers can be obtained with a call to C<$hContext-EListReaders()>. (See the section named F in the F man page for more information on C). =item * $share_mode is the desired mode of connection to the reader. It can be any of the following: =over 4 =item * $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE the application do not share the reader =item * $Chipcard::PCSC::SCARD_SHARE_SHARED the application will allow others to share the reader. =item * $Chipcard::PCSC::SCARD_SHARE_DIRECT (not used by PC/SC-lite) =back =item * $preferred_protocol is the protocol which should be used if possible. If the protocol is not available, another protocol will be used and C<$hCard-E{dwProtocol}> will be set accordingly. Both C<$hCard-E{dwProtocol}> and C<$preferred_protocol> accept the following values: =over 4 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0 the T=0 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1 the T=1 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW raw protocol =back =back =item * B<$hCard = new Chipcard::PCSC::Card ($hContext, $reader_name, $share_mode);> This method is equivalent to: $hCard = new Chipcard::PCSC::Card ($hContext, $reader_name, $share_mode, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1); =item * B<$hCard = new Chipcard::PCSC::Card ($hContext, $reader_name);> This method is equivalent to: $hCard = new Chipcard::PCSC::Card ($hContext, $reader_name, $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1); =back =head1 CONSTRUCTION FAILURE C constructors return an C value when the object can not be created. C<$Chipcard::PCSC::errno> can be used to get more information about the error. See section F in F man page for more information. =head1 Chipcard::PCSC::Card METHODS Here is a list of all the methods that can be used with a C object. =head2 $hCard-EConnect($reader_name, $share_mode, $preferred_protocol); C can be used to connect to the reader and its smart card if the connection has not been established yet. The default constructor can establish the connection if given enough parameters. The return value upon successful completion is the protocol used to communicate with the smart card. It can be any of the following: =over 4 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0 the T=0 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1 the T=1 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW raw protocol =back =over 4 =item * $reader_name is mandatory. It contains the name of the reader you want to connect to. It is of the form "GemPC410 0 0". Please note that the list of available readers can be obtained with a call to C<$hContext-EListReaders()>. (See the section named F in the F man page for more information on C). =item * $share_mode is the desired mode of connection to the reader. It can be any of the following: =over 4 =item * $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE the application do not share the reader =item * $Chipcard::PCSC::SCARD_SHARE_SHARED the application will allow others to share the reader. =item * $Chipcard::PCSC::SCARD_SHARE_DIRECT (not used by PCSClite) =back =item * $preferred_protocol is the protocol which should be used if possible. If the protocol is not available, another protocol will be used and C<$hCard-E{dwProtocol}> will be set accordingly. C<$preferred_protocol> accept the following values: =over 4 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0 the T=0 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1 the T=1 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW raw protocol =back =back =head2 $hCard-EConnect($reader_name, $share_mode); This method is equivalent to: $hCard->Connect($reader_name, $share_mode, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1); =head2 $hCard-EConnect($reader_name); This method is equivalent to: $hCard->Connect($reader_name, $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1); =head2 $hCard-EReconnect($share_mode, $preferred_protocol, $initialization); C can be used to re-negotiate an already opened connection. This implies that the C object is connected and has C<$hCard-E{hCard}> set accordingly. Reconnecting to a smart card is used to change the share mode and the current protocol. The return value upon successful completion is the protocol choose to communicate with the smart card. It can be any of the following: =over 4 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0 the T=0 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1 the T=1 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW raw protocol =back =over 4 =item * $share_mode is the desired mode of connection to the reader. It can be any of the following: =over 4 =item * $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE the application do not share the reader =item * $Chipcard::PCSC::SCARD_SHARE_SHARED the application will allow others to share the reader. =item * $Chipcard::PCSC::SCARD_SHARE_DIRECT (not used by PCSClite) =back =item * $preferred_protocol is the protocol which should be used if possible. If the protocol is not available, another protocol will be used and C<$hCard-E{dwProtocol}> will be set accordingly. C<$preferred_protocol> accept the following values: =over 4 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0 the T=0 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1 the T=1 protocol =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW raw protocol =back =item * $initialization is the action to take when reconnecting to the smart card. It can be any of the following values: =over 4 =item * $Chipcard::PCSC::SCARD_LEAVE_CARD do nothing on close =item * $Chipcard::PCSC::SCARD_RESET_CARD reset on close =item * $Chipcard::PCSC::SCARD_UNPOWER_CARD power down on close =item * $Chipcard::PCSC::SCARD_EJECT_CARD eject on close =back =back =head2 $hCard-EReconnect($share_mode, $preferred_protocol); This method is equivalent to: $hCard->Reconnect($share_mode, $preferred_protocol, $Chipcard::PCSC::SCARD_LEAVE_CARD); =head2 $hCard-EReconnect($share_mode); This method is equivalent to: $hCard->Reconnect($share_mode, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1, $Chipcard::PCSC::SCARD_LEAVE_CARD); =head2 $hCard-EReconnect(); This method is equivalent to: $hCard->Reconnect($Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1, $Chipcard::PCSC::SCARD_LEAVE_CARD); =head2 $hCard-EDisconnect($initialization); C closes the connection to the smart card reader. It returns true upon successful completion or undef otherwise. C<$hCard-E{hContext}> will be set to undef if the connection is successfully closed. =over 4 =item * $initialization is the action to take when reconnecting to the smart card. It can be any of the following values: =over 4 =item * $Chipcard::PCSC::SCARD_LEAVE_CARD do nothing on close =item * $Chipcard::PCSC::SCARD_RESET_CARD reset on close =item * $Chipcard::PCSC::SCARD_UNPOWER_CARD power down on close =item * $Chipcard::PCSC::SCARD_EJECT_CARD eject on close =back =back =head2 $hCard-EDisconnect(); This method is equivalent to: $hCard->Disconnect($Chipcard::PCSC::SCARD_EJECT_CARD); =head2 $hCard-EStatus(); C returns the current status of the connection to a smart card. It is used to retrieve the ATR (Answer To Reset) value as well as the protocol being used to communicate. The return value is the C value if an error occurs. In such a case, C<$!> should be set with a string describing the error. Upon successful completion C returns an array as follows: (C<$reader_name>, C<$reader_state>, C<$protocol>, C<\@atr>) =over 4 =item * $reader_name is a string containing the name of the reader =item * $reader_state is a scalar containing the current state of the reader. It can be any combination of the following values: =over 5 =item * $Chipcard::PCSC::SCARD_UNKNOWN unknown state =item * $Chipcard::PCSC::SCARD_ABSENT card is absent =item * $Chipcard::PCSC::SCARD_PRESENT card is present =item * $Chipcard::PCSC::SCARD_SWALLOWED card not powered =item * $Chipcard::PCSC::SCARD_POWERED card is powered =item * $Chipcard::PCSC::SCARD_NEGOTIABLE ready for PTS =item * $Chipcard::PCSC::SCARD_SPECIFIC PTS has been set =back =item * $protocol is the protocol being used. It can be any of the following values: =over 5 =item * $Chipcard::PCSC::SCARD_PROTOCOL_T0, =item * $Chipcard::PCSC::SCARD_PROTOCOL_T1, =item * $Chipcard::PCSC::SCARD_PROTOCOL_RAW =back =item * \@atr is a reference to an array containing the ATR. Each cell of the array contains one byte of the ATR. This parameter is however optional as the ATR may not be available under some circumstances. For instance when the card is not inserted, no ATR can be returned and this parameter will be C. =back =head2 $hCard-ETransmit(\@data); C is used to exchange data with the card. It returns a reference to an anonymous array holding the answer to the emitted data. In case of an error, the reference is the C value. =over 4 =item * \@data is a reference to the data to be sent to the card. =back Here is a small sample of how to use C: $SendData = [0x00, 0xA4, 0x01, 0x00, 0x02, 0x01, 0x00]; $RecvData = $hCard->Transmit($SendData); print " Recv = "; foreach $tmpVal (@{$RecvData}) { printf ("%02X ", $tmpVal); } print "\n"; =head2 $hCard-EBeginTransaction(); C is used to temporarily get exclusive control over the smart card. It returns TRUE upon successful completion and FALSE otherwise. C<$Chipcard::PCSC::errno> should be set accordingly in case of an error. See section F in F man page for more information. =head2 $hCard-EEndTransaction($disposition); C is used to end a transaction initiated with C. It returns C upon successful completion and FALSE otherwise. C<$Chipcard::PCSC::errno> should be set accordingly in case of an error. See section F in F man page for more information. =over 4 =item * $disposition is the action to take when ending the transaction. It can be any of the following values: =over 4 =item * $Chipcard::PCSC::SCARD_LEAVE_CARD do nothing on close =item * $Chipcard::PCSC::SCARD_RESET_CARD reset on close =item * $Chipcard::PCSC::SCARD_UNPOWER_CARD power down on close =item * $Chipcard::PCSC::SCARD_EJECT_CARD eject on close =back =back =head2 $hCard-EEndTransaction(); This method is equivalent to: $hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD); =head2 $hCard-ETransmitWithCheck($apdu, $sw_expected [, $debug]); This method is a wrapper around $hCard-ETransmit(). The $apdu parameter is an ASCII text like "00 A4 01 00 02 01 00", $sw_expected is a Perl regular expression like "90 [01]0". If the status word returned matches the expression $sw_expected the method returns a list ($sw, $recv). $sw is the status word (like "90 00") of the command, $recv is the result of the command. If the status word do not match the expression $sw_expected the method returns undef and the variable $Chipcard::PCSC::Card::Error is set. The $debug argument is optional. If present the method will print on stdout the command sent and the response from the card. Example: ($sw, $RecvData) = $hCard->TransmitWithCheck($SendData, "6E 00", 1); warn "TransmitWithCheck: $Chipcard::PCSC::Card::Error" unless defined $sw; =head2 $hCard-EControl($control_code, \@data); This method uses PC/SC SCardControl() to send data specific to the reader driver. See your driver documentation to know what data to use. Example: $data = Chipcard::PCSC::ascii_to_array ("01 23 45"); $RecvData = $hCard->Control(0x42000001, $SendData); die ("Can't Control data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); =head2 ISO7816Error($sw); This method returns the ASCII text corresponding to the status word $sw according to ISO 7816-4 specifications. Example: $sw = "90 00"; print "$sw: " . &Chipcard::PCSC::Card::ISO7816Error($sw) . "\n"; =head1 SEE ALSO F man page has useful information about PC/SC-lite. F man page holds all the necessary information to create the PCSC object which will be the basis of C. =head1 COPYRIGHT (C) Lionel VICTOR, 2001, GNU GPL (C) Ludovic ROUSSEAU, 2003-2008, GNU GPL =head1 AUTHORS / ACKNOWLEDGEMENT Lionel VICTOR Ludovic ROUSSEAU =cut Chipcard-PCSC-v1.4.16/Card/Card.pm000644 000765 000024 00000031470 14526143072 017336 0ustar00rousseaustaff000000 000000 ############################################################################### # # Authors : Lionel VICTOR # # Ludovic ROUSSEAU # Compiler : gcc, Visual C++ # Target : Unix, Windows # # Description : Perl wrapper to the PCSC API # # Copyright (C) 2001 - Lionel VICTOR # 2003-2008 - Ludovic ROUSSEAU # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # ############################################################################### package Chipcard::PCSC::Card; require Chipcard::PCSC; use warnings; use Carp; use strict; our $VERSION = '0.02'; # Usage: # $hCard = new Chipcard::PCSC::Card ($hcontext); # $hCard = new Chipcard::PCSC::Card ($hcontext, $reader_name, $share_mode, # $preferred_protocol); # # the second version also connect to the supplied reader. # when no connection has been required, use Connect() # # default values: # $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE # $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 sub new { my $class = shift; my $hContext = shift; my $reader_name = shift; my $share_mode = shift; my $preferred_protocol = shift; my $container = {}; # $hContext is required therefore we check for its value return (undef) unless (defined $hContext->{hContext}); # Keep a handle on the given PCSC context $container->{hContext} = $hContext; # if the user wants to initiate the connection we call _Connect() # for him and return the appropriate error code if required if (defined ($reader_name)) { # Apply default values when required $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE unless (defined($share_mode)); $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 unless (defined ($preferred_protocol)); ($container->{hCard}, $container->{dwProtocol}) = Chipcard::PCSC::_Connect ($hContext->{hContext}, $reader_name, $share_mode, $preferred_protocol); return (undef) unless (defined $container->{hCard}); } # At this point, either the connection was successful or the user # did not ask for a connection... in any case, we just return our # blessed reference return bless $container, $class; } # new # Usage: # Connect ($reader_name, $share_mode, $preferred_protocol) # # default values: # $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE # $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 sub Connect { my $self = shift; confess ("wrong type") unless ref $self; # The object may be connected already so we check for that case if (defined ($self->{hCard})) { $Chipcard::PCSC::errno = $Chipcard::PCSC::SCARD_P_ALREADY_CONNECTED; return (undef); } # otherwise, we just pop the other parameters my $reader_name = shift; my $share_mode = shift; my $preferred_protocol = shift; # $reader_name is required so we check for its value return (undef) unless (defined($reader_name)); # Apply default values when required $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE unless (defined($share_mode)); $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 unless (defined ($preferred_protocol)); ($self->{hCard}, $self->{dwProtocol}) = Chipcard::PCSC::_Connect ($self->{hContext}{hContext}, $reader_name, $share_mode, $preferred_protocol); # We return the current protocole being used or undef if an error # occured in this case, $self->{dwProtocol} should be undef return $self->{dwProtocol}; } # Connect # Usage: # Reconnect ($share_mode, $preferred_protocol, $initialization) # # default values: # $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE # $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 # $initialization = $Chipcard::PCSC::SCARD_LEAVE_CARD sub Reconnect { my $self = shift; confess ("wrong type") unless ref $self; # check whever we know the card handle or not unless (defined ($self->{hCard})) { $Chipcard::PCSC::errno = $Chipcard::PCSC::SCARD_P_NOT_CONNECTED; return (undef); } my $share_mode = shift; my $preferred_protocol = shift; my $initialization = shift; # Apply default values when required $share_mode = $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE unless (defined($share_mode)); $preferred_protocol = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1 unless (defined ($preferred_protocol)); $initialization = $Chipcard::PCSC::SCARD_LEAVE_CARD unless (defined($initialization)); $self->{dwProtocol} = Chipcard::PCSC::_Reconnect ($self->{hCard}, $share_mode, $preferred_protocol, $initialization); return ($self->{dwProtocol}); } # Reconnect sub Disconnect { my $self = shift; confess ("wrong type") unless ref $self; # check whever we know the card handle or not unless (defined ($self->{hCard})) { $Chipcard::PCSC::errno = $Chipcard::PCSC::SCARD_P_NOT_CONNECTED; return (undef); } my $disposition = shift; # Apply default values when required $disposition = $Chipcard::PCSC::SCARD_LEAVE_CARD unless (defined ($disposition)); my $return_val = Chipcard::PCSC::_Disconnect ($self->{hCard}, $disposition); $self->{hCard} = (undef) if ($return_val); return $return_val; } # Disconnect sub Status { my $self = shift; confess ("wrong type") unless ref $self; return Chipcard::PCSC::_Status ($self->{hCard}); } # Status sub Transmit { my $self = shift; confess ("wrong type") unless ref $self; my $send_data = shift; my $trash; my $ret; confess ("not connected") unless defined $self->{hCard}; return (undef) unless defined $self->{dwProtocol}; # the APDU is at least 4 bytes (CLA, INS, P1, P2) warn ("Transmit: short APDU ($#$send_data bytes sent)") unless $#$send_data >= 3; #TODO: # The following warning was supposed to be helpful but it is real # pain in the ass... I therefore decided to remove it. I will leave # this code for a little time just to make sure it really is useless # then I plan to remove it... # warn ("Transmit: APDU length does not match P3 (" . ($#$send_data-4) . " instead of $send_data->[4])") unless $send_data->[4] == $#$send_data-4; ($trash, $ret) = Chipcard::PCSC::_Transmit ($self->{hCard}, $self->{dwProtocol}, $send_data); return $ret if (defined($ret)); # else error return (undef) } # Transmit sub Control { my $self = shift; confess ("wrong type") unless ref $self; my $controlcode = shift; my $send_data = shift; confess ("not connected") unless defined $self->{hCard}; return Chipcard::PCSC::_Control ($self->{hCard}, $controlcode, $send_data); } # Control sub BeginTransaction { my $self = shift; confess ("wrong type") unless ref $self; unless (defined ($self->{hCard})) { $Chipcard::PCSC::errno = $Chipcard::PCSC::SCARD_P_NOT_CONNECTED; return (0); } return Chipcard::PCSC::_BeginTransaction ($self->{hCard}); } # BeginTransaction sub EndTransaction { my $self = shift; confess ("wrong type") unless ref $self; unless (defined ($self->{hCard})) { $Chipcard::PCSC::errno = $Chipcard::PCSC::SCARD_P_NOT_CONNECTED; return (0); } my $disposition = shift; # print "we got dispo = $disposition\n"; # Apply default values when required $disposition = $Chipcard::PCSC::SCARD_LEAVE_CARD unless (defined ($disposition)); return Chipcard::PCSC::_EndTransaction ($self->{hCard}, $disposition); } # EndTransaction sub DESTROY { my $self = shift; confess ("wrong type") unless ref $self; $self->Disconnect (); if (defined ($self->{hCard})) { warn ("PCSCCard object $self deleted but still connected"); } } # DESTROY # Usage: # $text = ISO7816Error($sw) # # return the text version of the ISO 7816-4 error given in $sw sub ISO7816Error($) { my $sw = shift; # default error message my $text = "Error not defined by ISO 7816"; return "wrong SW size for: $sw" unless (length($sw) == 5); # split the two error bytes my ($sw1, $sw2) = split / /, $sw; $text = "Normal processing." if ($sw =~ m/90 00/); $text = "0x$sw2 bytes of response still available." if ($sw1 =~ m/61/); if ($sw1 =~ m/62/) { $text = "State of non-volatile memory unchanged. "; $text .= "No information given." if ($sw2 =~ m/00/); $text .= "Part of returned data my be corrupted." if ($sw2 =~ m/81/); $text .= "End of file/record reached before reading Le bytes." if ($sw2 =~ m/82/); $text .= "Selected file invalidated." if ($sw2 =~ m/83/); $text .= "FCI not formated according to 5.1.5." if ($sw2 =~ m/84/); } if ($sw1 =~ m/63/) { $text = "State of non-volatile memory changed. "; $text .= "No information given." if ($sw2 =~ m/00/); $text .= "File filled up by the last write." if ($sw2 =~ m/81/); $text .= "Counter: 0x" . substr($sw2, 1, 1) if ($sw2 =~ m/^C/); } $text = "State of non-volatile memory unchanged." if ($sw =~ m/64 00/); if ($sw1 =~ m/65/) { $text = "State of non-volatile memory changed. "; $text .= "Memory failure." if ($sw2 =~ m/81/); } $text = "Reserved for security-related issues." if ($sw1 =~ m/66/); $text = "Wrong length." if ($sw =~ m/67 00/); if ($sw1 =~ m/68/) { $text = "Functions in CLA not supported. "; $text .= "Logical channel not supported." if ($sw2 =~ m/81/); $text .= "Secure messaging not supported." if ($sw2 =~ m/82/); } if ($sw1 =~ m/69/) { $text = "Command not allowed. "; $text .= "Command incompatible with file structure." if ($sw2 =~ m/81/); $text .= "Security status not satisfied." if ($sw2 =~ m/82/); $text .= "Authentication method blocked." if ($sw2 =~ m/83/); $text .= "Referenced data invalidated." if ($sw2 =~ m/84/); $text .= "Conditions of use not satisfied." if ($sw2 =~ m/85/); $text .= "Command not allowed (no current EF)." if ($sw2 =~ m/86/); $text .= "Expected SM data objects missing." if ($sw2 =~ m/87/); $text .= "SM data objects incorrect." if ($sw2 =~ m/88/); } if ($sw1 =~ m/6A/) { $text = "Wrong parameter(s) P1-P2. "; $text .= "Incorrect parameters in the data field." if ($sw2 =~ m/80/); $text .= "Function not supported." if ($sw2 =~ m/81/); $text .= "File not found." if ($sw2 =~ m/82/); $text .= "Record not found." if ($sw2 =~ m/83/); $text .= "Not enough memory space in the file." if ($sw2 =~ m/84/); $text .= "Lc inconsistent with TLV structure." if ($sw2 =~ m/85/); $text .= "Incorrect parameters P1-P2." if ($sw2 =~ m/86/); $text .= "Lc inconsistent with P1-P2." if ($sw2 =~ m/87/); $text .= "Referenced data not found." if ($sw2 =~ m/88/); } $text = "Wrong parameter(s) P1-P2." if ($sw =~ m/6B 00/); $text = "Wrong length Le: should be 0x$sw2" if ($sw1 =~ m/6C/); $text = "Instruction code not supported or invalid." if ($sw =~ m/6D 00/); $text = "Class not supported." if ($sw =~ m/6E 00/); $text = "No precise diagnosis." if ($sw =~ m/6F 00/); return $text; } # ISO7816Error $Chipcard::PCSC::Card::Error = ""; # Usage: # ($sw, $res) = TransmitWithCheck($apdu, $sw_expected); # die "Error: $Chipcard::PCSC::Card::Error\n" unless defined $sw; # # With debug # ($sw, $res) = TransmitWithCheck($apdu, $sw_expected, 1); # die "Error: $Chipcard::PCSC::Card::Error\n" unless defined $sw; # # Example: # ($sw, $res) = TransmitWithCheck("00 A4 01 00 02 01 00", "90 [10]0"); sub TransmitWithCheck { my $self = shift; confess ("wrong type") unless ref $self; my $command = shift; my $sw_expected = shift; my $debug = shift; my ($send, $recv, $data, $sw); # add needed spaces $command =~ s/(..)/$1 /g if ($command !~ m/ /); print "=> $command\n" if (defined $debug); # Convert $command in a reference to an array $send = Chipcard::PCSC::ascii_to_array($command); # send the APDU $recv = $self -> Transmit($send); if (! defined $recv) { $Chipcard::PCSC::Card::Error = "Can't transmit data: $Chipcard::PCSC::errno"; return undef; } $data = Chipcard::PCSC::array_to_ascii($recv); print "<= $data\n" if defined $debug; # Status word $sw = substr $data, length ($data) -5, 5, ""; print "SW: $sw (" . &Chipcard::PCSC::Card::ISO7816Error($sw) . ")\n" if defined $debug; if ($sw !~ m/$sw_expected/) { #$sw = PCSC::ISO7816_ErrorStr($sw); $Chipcard::PCSC::Card::Error = "ERROR: expected $sw_expected and got $sw\n"; return undef; } # normal execution and no error return ($sw, $data); } # TransmitWithCheck 1; Chipcard-PCSC-v1.4.16/Card/Makefile.PL000644 000765 000024 00000000365 14526142572 020104 0ustar00rousseaustaff000000 000000 use ExtUtils::MakeMaker; # See ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Chipcard::PCSC::Card', 'VERSION_FROM' => 'Card.pm', # finds $VERSION ); Chipcard-PCSC-v1.4.16/Card/t/test.t000755 000765 000024 00000010226 14526143072 017535 0ustar00rousseaustaff000000 000000 #!/usr/bin/perl # test.pl: simple sample program based on test.pl to test the pcsc # Perl wrapper under Test::Harness # Copyright (C) 2001 Lionel Victor, 2003 Ludovic Rousseau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use Test::More; use Chipcard::PCSC; use Chipcard::PCSC::Card; plan tests => 9; use strict; use warnings; my $hContext; my @ReadersList; my $hCard; my @StatusResult; my $tmpVal; my $SendData; my $RecvData; #------------------------------------------------------------------------------- $hContext = new Chipcard::PCSC(); #die ("not ok : Can't create the pcsc object: $Chipcard::PCSC::errno\n") unless (defined $hContext); ok(defined $hContext, "new Chipcard::PCSC()"); #------------------------------------------------------------------------------- @ReadersList = $hContext->ListReaders (); #die ("not ok : Can't get readers' list: $Chipcard::PCSC::errno\n") unless (defined($ReadersList[0])); ok(defined($ReadersList[0]), "\$hContext->ListReaders ()"); #------------------------------------------------------------------------------- $hCard = new Chipcard::PCSC::Card ($hContext); #die ("not ok : Can't create the reader object: $Chipcard::PCSC::errno\n") unless (defined($hCard)); ok(defined($hCard), "new Chipcard::PCSC::Card (\$hContext)"); $tmpVal = $hCard->Connect($ReadersList[0], $Chipcard::PCSC::SCARD_SHARE_SHARED); unless ($tmpVal) { # Try to reconnect and reset if connect fails print "not ok : Connect failed: trying to reset the card:\n"; $tmpVal = $hCard->Reconnect ($Chipcard::PCSC::SCARD_SHARE_SHARED, $Chipcard::PCSC::SCARD_PROTOCOL_T0, $Chipcard::PCSC::SCARD_RESET_CARD); die ("not ok : Can't reconnect to the reader '$ReadersList[0]': $Chipcard::PCSC::errno\n") unless ($tmpVal); } ok ($hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_T0 || $hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_T1 || $hCard->{dwProtocol}==$Chipcard::PCSC::SCARD_PROTOCOL_RAW, "Can understand the current protocol: $hCard->{dwProtocol}"); #------------------------------------------------------------------------------- @StatusResult = $hCard->Status(); #die ("not ok : Can't get status: $Chipcard::PCSC::errno\n") unless ($StatusResult[0]); ok($StatusResult[0], "\$hCard->Status()"); #------------------------------------------------------------------------------- #die ("not ok : Can't initiate transaction: $Chipcard::PCSC::errno\n") unless ($hCard->BeginTransaction()); ok($hCard->BeginTransaction(), "\$hCard->BeginTransaction()"); #------------------------------------------------------------------------------- $SendData = Chipcard::PCSC::ascii_to_array ("00 A4 01 00 02 01 00"); $RecvData = $hCard->Transmit($SendData); #die ("not ok : Can't transmit data: $Chipcard::PCSC::errno") unless (defined ($RecvData)); ok(defined ($RecvData), "\$hCard->Transmit()"); #------------------------------------------------------------------------------- #die ("not ok : Can't terminate transaction: $Chipcard::PCSC::errno\n") #unless ($hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD)); ok($hCard->EndTransaction($Chipcard::PCSC::SCARD_LEAVE_CARD), "\$hCard->EndTransaction()"); #------------------------------------------------------------------------------- $tmpVal = $hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); #die ("not ok : Can't disconnect the PCSC object: $Chipcard::PCSC::errno\n") unless $tmpVal; ok($tmpVal, "\$hCard->Disconnect"); #------------------------------------------------------------------------------- $hCard = undef; $hContext = undef; # End of File #