Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# PCSC-sharp Send / Receive Custom Commands with Data

I'm working on a C# Java Card (Smart Card) program, and I am trying to utilize the PCSC-sharp library on github.

Here's the "short / tl;dr" version of my request: The PCSC-sharp example covers Iso7816 Case2Short. Can someone either correct my examples below, or provide me an example of an Iso7816 Case3Short (Command data. No response data) and Case4Short (Command data. Expected response data)?

Here's the "long" version of my request: On the Java Card, I'm using both standard and custom APDU commands, and I can successfully invoke these commands using a python script (with the smartcard library). In other words, I have proven working Java Card commands.

My goal now is to use PCSC-sharp to perform the same commands, but I'm failing when I'm including data (i.e., APDU LC is > 0).

Here's the example on github. Note that I can use this with only changes to the reader name, the instruction (select file instead of get challenge), and Le.

var contextFactory = ContextFactory.Instance;
using (var ctx = contextFactory.Establish(SCardScope.System)) {
    using (var isoReader = new IsoReader(ctx, "ACME Smartcard reader", 
        SCardShareMode.Shared, SCardProtocol.Any, false)) {

        var apdu = new CommandApdu(IsoCase.Case2Short, isoReader.ActiveProtocol) {
            CLA = 0x00, // Class
            Instruction = InstructionCode.GetChallenge,
            P1 = 0x00, // Parameter 1
            P2 = 0x00, // Parameter 2
            Le = 0x08 // Expected length of the returned data
        };

        var response = isoReader.Transmit(apdu);
        Console.WriteLine("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2);
        // ..
    }
}

The APDU in my version of the example translates to:

Send: 00 A4 00 00 00 00
Resp: 90 00

... which works for me and is appropriate for Case2Short (no data, no response)

What I'm trying to recreate are 2 different types of transfers:

Case3Short (Command data. No response data)

Send: 00 A4 04 00 06 01 02 03 04 05 06 00
Resp  90 00

Here's my code:

    private bool SendApduCase3()
    {
        var success = false;
        DebugWriteLine("case3 start");
        using (var isoReader = new IsoReader(td.context, td.name, SCardShareMode.Shared, SCardProtocol.T1, false))
        {
            DebugWriteLine("case3 command");
            var commandApdu = new CommandApdu(IsoCase.Case3Short, isoReader.ActiveProtocol)
            {
                CLA = 0x00,
                INS = 0xA4,
                P1 = 0x04,
                P2 = 0x00,
                Data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
                Le = 0x00
            };

            DebugWriteLine("case3 transmit");
            var response = isoReader.Transmit(commandApdu);
            if ((response.SW1 == 0x90) && (response.SW2 == 0x00)) success = true;
        }
        DebugWriteLine("case3 " + success.ToString());
        return (success);
    }

... but it catches on the command and never makes it to the transmit, instead returning the following error:

System.ArgumentException:
    Iso7816-4 Case3Short does not expect any data fields in its return value and therefore has no bytes for Le
at PCSC.Iso7816.CommandApdu.set_Le(Int32 value)

if = 0x00 is removed then the Command is send, but now it's getting hung up on the transmit, which is odd since there shouldn't be return data.

ReaderPresent: catch case3
PCSC.Exceptions.InsufficientBufferException: The data buffer to receive returned data is too small for the returned data."

Case4Short (Command data. Expected response data)

Send: 80 11 00 00 04
Resp: 01 02 03 04 90 00

Here's my code:

    private bool SendApduCase4()
    {
        var success = false;
        DebugWriteLine("case4 start");
        using (var isoReader = new IsoReader(td.context, td.name, SCardShareMode.Shared, SCardProtocol.T1, false))
        {
            DebugWriteLine("case4 command");
            var commandApdu = new CommandApdu(IsoCase.Case3Short, isoReader.ActiveProtocol)
            {
                CLA = 0x00,
                INS = 0xA4,
                P1 = 0x00,
                P2 = 0x00,
                Data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 },
                Le = 0x00
            };

            DebugWriteLine("case4 transmit");
            var response = isoReader.Transmit(commandApdu);
            if (response.HasData) DebugWriteLine(response.GetData().ToString());
            if ((response.SW1 == 0x90) && (response.SW2 == 0x00))
            {
                if (response.HasData)
                {
                    byte[] expected = new byte[] { 0x51, 0x01, 0x02, 0x03 };
                    if (response.GetData() == expected) success = true;
                }
            }

        }
        DebugWriteLine("case4 " + success.ToString());
        return (success);
    }

... similarly, it catches on the command and never makes it to the transmit

What am I doing wrong here?

Oh and the closest answer I found in my search was here, but didn't cover what I need.

like image 213
Blue Smoke Avatar asked Nov 07 '22 01:11

Blue Smoke


1 Answers

Case 3 doesn't expect any return data. If you're not expecting data then Le should not be present. Le is the encoding of the amount of data to be expected, called Ne. Le = 00 means: give me a maximum number of 256 bytes in return: Ne = 256. So inclusion of any Le value makes it an ISO case 4 command. If Le is not present then Ne = 0.

Generally smart cards will still send the correct response even if Le is set. Unfortunately for you the PCSC-sharp library decided differently and disallowed you to send the command - which is probably a good thing, as a smart card implementation could still return an error.


When you removed your Le = 00 you ran into another issue. SELECT by name (INS = A4 and P1 = 04 with P2 = 00 may actually return file control data, making it an ISO case 4 command. This time the command is correctly constructed as ISO case 3, but the card returned data, for which no buffer space was reserved in the library - giving you an error after receiving the response.

To test case 3 you need to use INS = A4, P1 = 04 and P2 = 0C which indicates that no response data is expected. Or any other actual ISO case 3 command such as SELECT by File ID, of course.


Notes:

  • ISO here is short for ISO/IEC 7816-4, if photographers can abuse the ISO name then so can smart card devs
like image 142
Maarten Bodewes Avatar answered Nov 14 '22 22:11

Maarten Bodewes