Search code examples
c#marshallingsmartcardpcscwinscard

SCardTransmit return empty buffer


Im trying to learn using winscard.dll in C# and I have a problem when running the SCardTransmit() where it always return me an empty buffer.

Here is my test code:

 class Program
    {
        static void Main(string[] args)
        {

            IntPtr _hContext;
            IntPtr _hCard;
            uint _activeProtocol;

            int retcode = 0;

            // Establish context:
            retcode = PCSCLite.SCardEstablishContext(PCSCLite.SCARD_SCOPE_USER, IntPtr.Zero, IntPtr.Zero, out _hContext);

            // List Readers:
            uint pcchReaders = 0;
            retcode = PCSCLite.SCardListReaders(_hContext, null, null, ref pcchReaders);

            byte[] mszGroups = new byte[pcchReaders];
            retcode = PCSCLite.SCardListReaders(_hContext, null, mszGroups, ref pcchReaders);

            string sBuffer = Encoding.ASCII.GetString(mszGroups);

            int nullIndex = -1;
            char nullchar = (char)0;
            int len = (int)pcchReaders;

            List<String> readers = new List<String>();

            while(sBuffer[0] != (char)0)
            {
                nullIndex = sBuffer.IndexOf(nullchar);
                string reader = sBuffer.Substring(0, nullIndex);

                readers.Add(reader);

                len -= (reader.Length + 1);
                sBuffer = sBuffer.Substring(nullIndex + 1, len);
            }

            foreach(var reader in readers)
            {
                Console.WriteLine(reader);
            }

            // Connect
            retcode = PCSCLite.SCardConnect(_hContext, readers[1], PCSCLite.SCARD_SHARE_SHARED, PCSCLite.SCARD_PROTOCOL_T0, out _hCard, out _activeProtocol);

            // Transmit
            //SCARD_IO_REQUEST pioSendPci = _activeProtocol == 1 ? PCSCLite.SCARD_PCI_T0() : PCSCLite.SCARD_PCI_T1(); // based on current active protocol
            SCARD_IO_REQUEST pioSendPci = new SCARD_IO_REQUEST();
            pioSendPci.cbPciLength = 8;
            byte[] pbSendBuffer = { 0x00, 0xA4, 0x04, 0x0C, 0x00 };
            uint cbSendLength = (uint)pbSendBuffer.Length;
            byte[] pbRecvBuffer = new byte[263];
            uint pcbRecvLength = 0;
            retcode = PCSCLite.SCardTransmit(_hCard, ref pioSendPci, pbSendBuffer, cbSendLength, IntPtr.Zero, pbRecvBuffer, ref pcbRecvLength);

The source code for how I marshall the winscard.dll can be found here: LibPCSCLite

How i run it:

First I created C# Class Library (the LibPCSCLite), then built it to get the LibPCSCLite.dll Second, I created C# Console Program, add reference the LibPCSCLite.dll, and run / debug the console.

I am using Windows 10, using VS 2019 and Net Framework version 3.5 I had already tested it on Net Framework version 4.5 still no differences. Changing the platform target (AnyCPU - x86) also has no effect.

When running the SELECT FILE command I got all zeros on pbRecvBuffer not even the SW bytes, but got value of 20 in the pcbRecvLength variable which I assume is the FCI + SW bytes length.

The reader I used is OMNIKEY 5321 contactless


Solution

  • When running the SELECT FILE command I got all zeros on pbRecvBuffer not even the SW bytes, but got value of 20 in the pcbRecvLength variable which I assume is the FCI + SW bytes length.

    It's OK because you pass pcbRecvLength equal to zero. Value of pcbRecvLength supplies the length, in bytes, of the pbRecvBuffer parameter. So, zero means "zero buffer size", i.e no destination buffer to copy result. After execution of SCardTransmit you have in pcbRecvLength the actual number of bytes received from the smart card: 20 bytes.

    Try to assign pcbRecvLength with actual size of pbRecvBuffer.