send buffer directly to a smartcard

259 Views Asked by At

I need to send a message to a smartcard. First of all, I sent it using gpshell in order to test the correctness and get an answer:

send_apdu_nostop -sc 0 -APDU 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900                             Command --> 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900
Wrapped command --> 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900
Response <-- 604001544F50434F4E31392020202020000000FF00FF0000FF00020000000000000000FF5D11DCAD000000005D11DCAD005D1EF96B9000

With this result I was confident to replicate the behaviour in java using smartcardio. The following is the code I wrote:

    void testCard()
    {
        TerminalFactory factory = TerminalFactory.getDefault();
        List<CardTerminal> terminals;
        try {
            terminals = factory.terminals().list();
        } catch (CardException ex) {
            return;
        }
        CardTerminal cardTerm = terminals.get(0);
        Card card;
        try {
            card = cardTerm.connect("T=0");
        } catch (CardException ex) {           
            return;
        }
        CardChannel cach = card.getBasicChannel();
        ResponseAPDU r;
        try {
            CommandAPDU ca = new CommandAPDU(new byte[]{(byte)0x80,(byte)0x2A,(byte)0x80,(byte)0xB0,(byte)0x5F,(byte)0x87,(byte)0x41,(byte)0x00,(byte)0x61,(byte)0xDA,(byte)0x7A,(byte)0x1E,(byte)0x2F,(byte)0x02,(byte)0x60,(byte)0x2A,(byte)0x25,(byte)0x50,(byte)0x63,(byte)0x71,(byte)0x3F,(byte)0xD6,(byte)0x57,(byte)0x79,(byte)0x70,(byte)0x63,(byte)0xC6,(byte)0xC7,(byte)0xAC,(byte)0xC1,(byte)0x20,(byte)0x72,(byte)0xF5,(byte)0x34,(byte)0x0B,(byte)0x1C,(byte)0x01,(byte)0x26,(byte)0xA6,(byte)0x16,(byte)0xBC,(byte)0x66,(byte)0xC6,(byte)0x5F,(byte)0x49,(byte)0x13,(byte)0x2E,(byte)0xED,(byte)0x10,(byte)0xAE,(byte)0x07,(byte)0x1D,(byte)0xC6,(byte)0x61,(byte)0xAA,(byte)0x13,(byte)0x33,(byte)0xBE,(byte)0xA9,(byte)0x2F,(byte)0x67,(byte)0xA5,(byte)0xBE,(byte)0xFF,(byte)0xDF,(byte)0xA7,(byte)0xA0,(byte)0xF3,(byte)0x1F,(byte)0xC8,(byte)0xB3,(byte)0xD9,(byte)0x81,(byte)0x10,(byte)0x5D,(byte)0x1E,(byte)0xF9,(byte)0x6B,(byte)0x00,(byte)0x0F,(byte)0xD9,(byte)0x00,(byte)0x98,(byte)0xC7,(byte)0xFF,(byte)0x03,(byte)0x19,(byte)0x06,(byte)0xA1,(byte)0x01,(byte)0x8E,(byte)0x08,(byte)0x97,(byte)0xC5,(byte)0xDA,(byte)0x58,(byte)0x00,(byte)0x59,(byte)0xAD,(byte)0x29,(byte)0x00});   
            r = cach.transmit(ca);           
        } catch (CardException ex) {            
            return;
        }
    }        

When the code runs I always get the error 0x6E00 which means: "Class not supported".

Reading the javadoc of transmit I understand that "The CLA byte of the command APDU is automatically adjusted to match the channel number of this CardChannel."

I suspect that for some reasons the class byte was changed somehow and for that reason the card answers with the error.

Is there any way to send directly the message to the card in java?

2

There are 2 best solutions below

0
On BEST ANSWER

I found the solution. It seems that using "T=0" is not a suitable way to send the second command. Using "T=1" or "*" solve the problem. The correction is the following:

card = cardTerm.connect("T=1");
1
On

NOTE: I have not worked with Smart cards and don't have one to validate this answer. But it may point you in the right direction

If you look at the source code of gshell. For sending the APDU it reads it like below

 else if (_tcscmp(token, _T("-APDU")) == 0)
        {
            token = strtokCheckComment(NULL);
            if (token == NULL)
            {
                _tprintf(_T("Error: option -APDU not followed by data\n"));
                rv = EXIT_FAILURE;
                goto end;
            }
            else
            {
                pOptionStr->APDULen = ConvertStringToByteArray(token, APDULEN, pOptionStr->APDU);
            }
        }

https://github.com/sigma/globalplatform/blob/7f1c8669c5991a60b6fada9b1187d2ee6d040223/gpshell/src/gpshell.c#L1648

So what you passed is complete APDU command

if (platform_mode == PLATFORM_MODE_OP_201)
{
    status = OP201_send_APDU(cardContext, cardInfo,
                            (optionStr.secureChannel == 0 ? NULL : &securityInfo201),
                            (PBYTE)(optionStr.APDU), optionStr.APDULen,
                            recvAPDU, &recvAPDULen);
}

Which in turn goes to

https://github.com/sigma/globalplatform/blob/7f1c8669c5991a60b6fada9b1187d2ee6d040223/globalplatform/src/connection.c#L202

OPGP_ERROR_STATUS OPGP_send_APDU(OPGP_CARD_CONTEXT cardContext, OPGP_CARD_INFO cardInfo, GP211_SECURITY_INFO *secInfo, PBYTE capdu, DWORD capduLength, PBYTE rapdu, PDWORD rapduLength) {
    OPGP_ERROR_STATUS errorStatus;
    OPGP_ERROR_STATUS securityStatus;
    OPGP_ERROR_STATUS(*plugin_sendAPDUFunction) (OPGP_CARD_CONTEXT, OPGP_CARD_INFO, PBYTE, DWORD, PBYTE, PDWORD);
    BYTE apduCommand[261];
    DWORD apduCommandLength = 261;
    int i=0;

    OPGP_LOG_START(_T("OPGP_send_APDU"));
    plugin_sendAPDUFunction = (OPGP_ERROR_STATUS(*)(OPGP_CARD_CONTEXT, OPGP_CARD_INFO, PBYTE, DWORD, PBYTE, PDWORD)) cardContext.connectionFunctions.sendAPDU;

So I think an extra cardContext is required to be appended in your command, which is currently not there

See few implementations also and see if you can make out the bytes

https://github.com/handywings/tutorial_hdw_mc/blob/a1dceae1b243b0c79dda5c73218e3a9ff84c259c/src/main/java/com/hdw/mccable/utils/ThaiLandIdCard.java

https://www.javaworld.com/article/2076450/how-to-write-a-java-card-applet--a-developer-s-guide.html

https://github.com/arg3s/ClassAttendanceMaster/blob/a368b07e9b94bd387f91d7d6f57f12e402d58b32/src/main/java/com/classattendancemaster/SmartCard/SmartcardConnector.java