PC/SC: "Card not transacted" when using C-API Calls

1

A few weeks ago I began experimenting with smart cards for an university project. The exercise was as easy as using a health insurance card (the German one, "eGK") and find out what's saved on it and read out the "public" parts which can be read out without prior authenticating in any way.

Fourtunately the structure of the card is well documented and the documentation can easily be downloaded from the internet. What I basically want to to now is selecting the EF (MF / DF.HCA / EF.VD) and read out the data. The file I want to read out is a binary file. According to the documentation, the first 2x4 bytes represent the start/end-offsets of two parts of the file. Each part should be gzip-compressed XML.

At first, I used "scriptor" from the pcsc-lite tools to try out a few commands, to see if it works and if I get some reasonable results. This all worked out pretty well :)

$ scriptor
No reader given: using Towitoko Chipdrive USB 00 00
Using T=1 protocol
Reading commands from STDIN
reset
> RESET
< OK: 3B DD 97 FF 81 B1 FE 45 1F 03 00 64 04 05 08 03 73 96 21 D0 00 90 00 C8 
00 a4 04 0c 06 d2 76 00 00 01 02    # Select DF
> 00 a4 04 0c 06 d2 76 00 00 01 02
< 90 00 : Normal processing.
00 a4 02 0c 02 d0 02                # Select EF
> 00 a4 02 0c 02 d0 02
< 90 00 : Normal processing.
00 b0 00 00 08                      # Read out start/end offsets
> 00 b0 00 00 08
< 00 08 01 AD 01 AE 02 7C 90 00 : Normal processing.

As you can see, this would be over 400 Bytes to read out (and decompress them afterwards), so I decided I need to write some program which reads this out for me. With the help of this blogpost: http://ludovicrousseau.blogspot.de/2010/04/pcsc-sample-in-c.html I was quickly able to send my first commands to the card using C. The basic flow of my program is:

  1. Establish a context
  2. Get a reader (the program prints out the reader in use and it's the only and the right one ;) )
  3. Get the card (protocol is T=1)
  4. Reset the card
  5. Tell PC/SC I need a transaction
  6. Transmit the commands
  7. End transaction

Here are the fields I send to the SC:

//                    CLA   INS    P1     P2            LEN_SEND
BYTE cmdSelectDF[] = {0x00, 0xA4,  0x04,  0x0C,         0x06,
//                    00    SELECT DF/AID first/noanswer
//                    <- HEADER] ----- [DATA ->
//                    D6    D5    D4     D3    D2    D1
                      0xD2, 0x76, 0x00,  0x00, 0x01, 0x02};

//                    CLA   INS    P1     P2            LEN_SEND
BYTE cmdSelectEF[] = {0x00, 0xA4,  0x02,  0x0C,         0x02,
//                    00    SELECT EF/FID first/noanswer
//                    <- HEADER] ----- [DATA ->
//                    D2    D1
                      0xD0, 0x02};

//                       CLA   INS         P1      P2      LEN_RECV
BYTE cmdReadOffsets[] = {0x00, 0xB0,       0x00,   0x00,   0x08};
//                       00    READ BINARY OFFSET1 OFFSET2 BYTES

The first two commands transmit just fine and I always get a 0x90 0x00 back. Unfortunately, the ReadOffsets-Transmit returns with an error: "Transaction failed". The log says the following:

00000011 winscard.c:1613:SCardTransmit() Send Protocol: T=1
00042572 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000030 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6
03000349 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000043 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000012 winscard.c:1613:SCardTransmit() Send Protocol: T=1
00055517 ifdwrapper.c:553:IFDTransmit() Card not transacted: 612
00000027 winscard.c:1638:SCardTransmit() Card not transacted: 0x80100016
00000010 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000031 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x80100016 for client 6
00000297 winscard_svc.c:348:ContextThread() Client die: 6
00000029 winscard.c:230:SCardReleaseContext() Releasing Context: 0x420027B7

Does anyone have an idea what this means and why it happens? What am I doing wrong?

Thank you very much in advance!

Edit: I have some news for you. I found some #ifdefs in the towitoko driver source code for debugging purposes. Now, I have a much more detailed log file for you. The parts with [[[]]] are only in the error log file. As you can see, there isn't any difference in the bytes submitted and the bytes received at all!

01942065 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000021 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000008 winscard.c:1613:SCardTransmit() Send Protocol: T=1
IFD: Setting baudrate to 9600
IFD: Transmit: 0 40 7 0 A4 2 C 2 D0 2 3D 
IO: Sending: 6F B 5 5A 
IO: Sending: 0 
IO: Sending: 40 7 0 A4 2 C 2 D0 2 3D 
IO: Receiving: 0 
IO: Receiving: 40 2 90 
IFD: Receive: 0 40 2 90 
IO: Receiving: 0 D2 
IFD: Receive: 0 D2 
00042861 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000011 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6
IO: Sending: 3 7 
IO: Receiving: 42 87 
IFD: Status = card / no change
IO: Sending: 3 7 
IO: Receiving: 40 83 
IFD: Status = card / no change
[...]
02773187 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000032 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000009 winscard.c:1613:SCardTransmit() Send Protocol: T=1
IFD: Setting baudrate to 9600
IFD: Transmit: 0 0 5 0 B0 0 0 8 BD 
IO: Sending: 6F 9 5 52 
IO: Sending: 0 
IO: Sending: 0 5 0 B0 0 0 8 BD 
IO: Receiving: 0 
IO: Receiving: 0 A 0 
IFD: Receive: 0 0 A 0 
IO: Receiving: 8 1 AD 1 AE 2 7C 90 0 EF 
IFD: Receive: 8 1 AD 1 AE 2 7C 90 0 EF 
[[[ 00054674 ifdwrapper.c:553:IFDTransmit() Card not transacted: 612
00000011 winscard.c:1638:SCardTransmit() Card not transacted: 0x80100016 ]]]
00054759 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000011 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6

So, where does this error message come from?

Another thing I've learned is that this error doesn't seem to be reader specific. I've tried the program on a friend's internal card reader (Windows says it's a Broadcom reader), which yields to the same results. Because the only case I can think of is an error in my C program, here's the source code with the basic macros and the connection part:

// Parts taken from http://ludovicrousseau.blogspot.de/2010/04/pcsc-sample-in-c.html
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <PCSC/pcsclite.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>

#define EGK_RECV_BUFSIZE 258

#define PCSC_ERROR(debugmsg, retval) \
    if(retval != SCARD_S_SUCCESS) { \
        fprintf(stderr, "PC/SC Error at %s: %s\n", debugmsg, pcsc_stringify_error(retval)); \
        return 1; \
    }

#define TRANS_RESPONSE \
    printf("Command response: "); \
    for(i = 0; i < dwRecvLen; i++) { \
        printf("%02X ", recvBuffer[i]); \
    } printf("\n");

#define CHECK_SUCCESS \
    if(dwRecvLen >= 2) { \
        if(recvBuffer[dwRecvLen-2] == 0x90 && recvBuffer[dwRecvLen-1] == 0x00) { \
            printf("Command success!\n"); \
        } \
    }

#define SCARD_TRANSMIT(cmd) \
    SCardTransmit(scHandle, &scSendProto, cmd, sizeof(cmd), NULL, recvBuffer, &dwRecvLen);

int main(void)
{
    LONG retval = 0;                            // = long
    SCARDCONTEXT scContext;                     // = LONG
    LPTSTR scReaders;                           // = LPSTR = char *
    SCARDHANDLE scHandle;                       // = LONG (specific smartcard)
    DWORD dwReaders, dwCurProto, dwRecvLen;     // = unsigned long

    SCARD_IO_REQUEST scSendProto;
    BYTE recvBuffer[EGK_RECV_BUFSIZE];

    // BYTE cmdXXX[] = {...}; ... SEE ABOVE!

    // Get Context
    retval = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scContext);
    PCSC_ERROR("1 Establish Context", retval);

    // Get Reader

    retval = SCardListReaders(scContext, NULL, NULL, &dwReaders);
    PCSC_ERROR("2.1 Get Readers", retval);

    scReaders = calloc(dwReaders, sizeof(DWORD));

    retval = SCardListReaders(scContext, NULL, scReaders, &dwReaders);
    PCSC_ERROR("2.2 Get Readers", retval);

    printf("Reader name: %s\n", scReaders);

    // Get Card

    retval = SCardConnect(scContext, scReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &scHandle, &dwCurProto);
    PCSC_ERROR("3 SCardConnect", retval);

    // Reset
    retval = SCardReconnect(scHandle, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &dwCurProto);
    PCSC_ERROR("4 RESET Card", retval);

    dwRecvLen = EGK_RECV_BUFSIZE;

    if(dwCurProto == SCARD_PROTOCOL_T0) {
        scSendProto = *SCARD_PCI_T0;
    } else if(dwCurProto == SCARD_PROTOCOL_T1) {
        scSendProto = *SCARD_PCI_T1;
    } else {
        fprintf(stderr, "No known protocol selected\n");
        return 1;
    }

The Transmit-Part looks the same for every command. Example:

printf("READ BINARY -> First 8 Bytes (Offsets)\n");
retval = SCARD_TRANSMIT(cmdReadOffsets);
PCSC_ERROR("8 Transmit READ BINARY", retval);

TRANS_RESPONSE;
CHECK_SUCCESS; printf("\n");

Edit: Sorry this edit comes so late, I totally forgot about this post! I managed to get it working in the end by rewriting my program in Java. I know this is not quite a satisfying answer for those who may stumble upon this question. At least we can be sure now that the error lies somewhere inside the C code. Should anyone know why the program doesn't work, feel free to answer anyway, I would be really interested in knowing which mistake I made :) !

c
smartcard
apdu
pcsc
asked on Stack Overflow Oct 24, 2014 by Marco H. • edited Jun 1, 2015 by Marco H.

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0