5
votes

I have tachograph company card which is used to get the client authenticated before allowing him to download the data of the tachograph by the remote download. The used APDU command in my code below are commands of successfully authentication between the Tachograph and company card.

The connection between the both parties is accomplished as the following:

Tachograph <--can cable--> device <---Bluetooth--> Android app <--Socket API--> Company Card Server <--USB cabel--> company card reader <--> company card.

The communication as described above is working well and the app user is getting authenticated. Now I am trying to read some information fom the company card directly without the app as the following:

My Client Programm <--> card reader <--> company card

In my client programm I am using the same APDU commands which are sent from the Android App to the company card. Currently, I am facing Problem with the external authentication with INS tag "82". I am getting the error 66 88 which means wrong certification.

I have downloaded a certification file D__TCC40-1.bin from the

https://dtc.jrc.ec.europa.eu/dtc_public_key_certificates.php

The Public Key Certification content is described as the following:

128 Byte Signature + 58 byte Public Key reminder + 8 byte Certification Authorithy Reference = 194 byte

when reading the file D__TCC40-1.bin it has 194 bytes length (The company card uses as well a certification of the length 194). The external authentication bassically starts with the ´84´ INS command. This command is sent to the smart card by the terminal to deliver 8 digits random number. Subsequently, the terminal receives the random number and encrypte it with some encryption algotrithm that uses a public key for encryption. Afterwards, the terminal sends the encrypted number by the alogrithm to the smart card with the 82 INS tag.

Now I am trying to load the downloaded certificate D__TCC40-1.bin from the project root and use it to encrypte the 8 digits random number which I am getting with the GET CHALLANGE 84 INS tag but I do not know how can I encrypte it with the alogrithm to sent its result to the smart card. How can I use Public Key Certificate to encyrpte the random number to sent it to the smart card to get the 90 00 as a reponse? Currently, as I mentioned before I am getting the 66 88 as a Response.

enter image description here

enter image description here

***Code*

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import javax.xml.bind.DatatypeConverter;


public class CardIdTest {

    static CardChannel channel = null;
    static byte[] signature = null;


    public static void main(String[] args) {

        try {

            try {
                FileInputStream ecPubKeyFIS = new FileInputStream("D__TCC40-1.bin");

                try {
                    int certificateLength = ecPubKeyFIS.available();
                    byte[] certificate = new byte[certificateLength];
                    ecPubKeyFIS.read(certificate);

                    CardIdTest.signature = new byte[128];
                    System.arraycopy(certificate, 0, CardIdTest.signature, 0, 128);
                    int sigLength = CardIdTest.signature.length;

                    byte[] publicKeyReminder = new byte[58];
                    System.arraycopy(certificate, 128, publicKeyReminder, 0, 58);
                    int PKLength = publicKeyReminder.length;

                    byte[] certificationAuthorithyReference = new byte[8];
                    System.arraycopy(certificate, 186, certificationAuthorithyReference, 0, 8);
                    int referenceLength = certificationAuthorithyReference.length;
                    System.out.println("End");
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            TerminalFactory factory = TerminalFactory.getDefault();
            List<CardTerminal> terminals = factory.terminals().list();
            CardTerminal terminal = terminals.get(0);
            Card card = terminal.connect("T=1");
            System.out.println("Terminals list: " + terminals);
            ATR atr = card.getATR();
            byte[] atrArray = atr.getBytes();
            String atrHex = CardIdTest.byteArrayToHexString(atrArray);
            System.out.println("ATR: " + atrHex);
            CardIdTest.channel = card.getBasicChannel();

            String command1 = "00 a4 02 0c 02 00 02"; // select EF_ICC file.
            CardIdTest.execute(command1, 1);
            String command2 = "00 b0 00 00 09";  // Read binary
            String cardExtendedSerialNumberTemp = CardIdTest.execute(command2, 2);
            String cardExtendedSerialNumber = cardExtendedSerialNumberTemp.substring(4);
            String command3 = "00 a4 04 0c 06 ff 54 41 43 48 4f"; // select DF file or master file.
            CardIdTest.execute(command3, 3);
            String command4 = "00 a4 02 0c 02 05 01"; // select 05 01 elementary file.
            CardIdTest.execute(command4, 4);
            String command5 = "00 b0 00 00 01"; // read the binary byte.
            CardIdTest.execute(command5, 5);
            String command6 = "00 22 c1 b6 0a 83 08 00 00 00 05 09 02 ff a1"; // issse security managment environment.
            CardIdTest.execute(command6, 6);
            String command8 = "00 88 00 00 10 e9 96 79 ec 74 27 e6 50 00 00 00 05 09 02 ff a1 80"; // internal authentication.
            CardIdTest.execute(command8, 8);
            String command9 = "00 84 00 00 08"; // Get Challange / 8 digits random number
            String exteranlAuthenticationChallange = CardIdTest.execute(command9, 9);
            String digitalSignature = CardIdTest.byteArrayToHexString(CardIdTest.signature);
            String command10 = "00 82 00 00 80 " + digitalSignature; // eternal authentication.
            CardIdTest.execute(command10, 10);
            String command11 = "00 a4 02 0c 02 05 01"; // select 05 01 file
            String command12 = "0c b0 00 00 09 97 01 01 8e 04 1e ee 49 a1 00"; // read the birnay of the selected file.

            card.disconnect(true); // reset

        } catch (CardException e) {

            e.printStackTrace();
        }

    }


    private static String execute(String commandWithSpace, int number) throws CardException {
        String commandWithoutSpace = commandWithSpace.replace(" ", "");
        byte[] apdu = DatatypeConverter.parseHexBinary(commandWithoutSpace);
        CommandAPDU command = new CommandAPDU(apdu);
        ResponseAPDU responseAPDU = CardIdTest.channel.transmit(command);
        byte[] reponseData = responseAPDU.getData();
        String response = responseAPDU.toString();
        if (reponseData.length > 0) {
            String msg = new String(reponseData);
            String dataHex = CardIdTest.byteArrayToHexString(reponseData);
            System.out.println("command       (" + number + ")   (*" + apdu.length + "): " + commandWithSpace);

            System.out.println("response with data:  ( #" + msg.length() + ") :" + dataHex);
            System.out.println("msg: " + msg);
            return dataHex;

        } else {
            byte[] bytes = responseAPDU.getBytes();
            String responseHex = CardIdTest.byteArrayToHexString(bytes);
            System.out.println("command        (" + number + ")   (*" + apdu.length + "): " + commandWithSpace);
            System.out.println("response without data :" + responseHex);
            return responseHex;
        }
    }


    public static String byteArrayToHexString(byte[] byteArray) {
        StringBuilder sb = new StringBuilder();

        for (byte b : byteArray) {
            sb.append(String.format(" %02x", b));
        }
        return sb.toString();

    }


    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public static String byteArrayToHex(byte[] byteArray) {
        StringBuilder sb = new StringBuilder();
        for (byte b : byteArray) {
            sb.append(String.format(" %02x", b));
        }
        return sb.toString();

    }

}

Output with the 66 88 error

Terminals list: [PC/SC terminal Generic Smart Card Reader Interface 0]
ATR:  3b 9f 96 c0 0a 31 fe 45 43 54 31 69 0b 01 00 01 00 00 00 00 00 00 00 0d
command        (1)   (*7): 00 a4 02 0c 02 00 02
response without data : 90 00
command       (2)   (*5): 00 b0 00 00 09
response with data:  ( #9) : 00 00 01 98 fa 03 16 14 ad
command        (3)   (*11): 00 a4 04 0c 06 ff 54 41 43 48 4f
response without data : 90 00
command        (4)   (*7): 00 a4 02 0c 02 05 01
response without data : 90 00
command       (5)   (*5): 00 b0 00 00 01
response with data:  ( #1) : 04
command        (6)   (*15): 00 22 c1 b6 0a 83 08 00 00 00 05 09 02 ff a1
response without data : 90 00
command       (8)   (*22): 00 88 00 00 10 e9 96 79 ec 74 27 e6 50 00 00 00 05 09 02 ff a1 80
response with data:  ( #128) : 7f 96 43 f2 ee d9 44 34 2d 09 b6 c3 47 a0 08 28 6d 3f 3d 30 e8 3d 82 fb 21 e0 5f 7a 3e bd 99 f9 ba 4c 2c c5 56 df fc cc b1 7e 66 bc 9a 26 b0 0e 53 52 fe d7 51 a3 84 75 f6 7d 3a 24 48 d1 a4 fe 8d 82 0e a8 bb 10 2d f2 51 8d 0c 6c 96 0f 0b 2a e3 a7 ce 5c d9 27 91 8f 7c 2b 21 1c f5 fa 65 cd 5f 5c e6 6f 1c a5 ad 27 4a 57 c3 16 76 0b 06 e1 d8 fc af 20 ce 48 61 1d 53 48 f9 78 5b b9 3a c1
command       (9)   (*5): 00 84 00 00 08
response with data:  ( #8) : 06 ba 52 a6 34 7a fe 30
command        (10)   (*133): 00 82 00 00 80  9b 33 b2 68 9a 71 93 3b 50 c2 4d 65 95 e7 84 59 db 40 77 e1 40 a1 b1 a3 b9 8c a8 a1 fb 36 ac b5 a6 2b 60 b3 63 f8 dd 77 de ad a1 4d ab 39 ab cc c8 79 51 aa d1 7a 97 bd 16 c3 d8 2d dd 74 cf 98 47 89 b9 36 d0 02 43 29 f6 69 2d a5 1f f2 27 89 ad fb 81 3d 47 93 08 e4 56 7c 4f 0d a1 b8 07 4e cb 9b 18 80 73 33 75 2b c9 dc de c4 ce 96 71 07 d8 5f 6d 20 f6 a3 09 88 87 8c 69 ec 6f de 51 ca
response without data : 66 88

By the way the code to read the information of the driver card works without secure messaging and looks like the following:

        // String masterFile = "00 A4 04 0C 06 FF544143484F";
        // String elementaryFile = "00 A4 02 0C 02 0520";
        // String readBinary = "00 B0 00 01 10";
1
Are you sure you get a 6688 instead of a 6988? And maybe you are referring to "INS" (short for "INStruction") instead of "INC" (usually short for "INCrease")?Maarten Bodewes
Yes I am getting 6688. Yes I meant INS instead of INC.Mr Asker
Did you ever get it to work? I'm facing the same problemiboalali

1 Answers

1
votes

tl;dr

You cannot just read the card number of a Company Card, because you will never be able to authenticate with the card this way:

My Client Programm <--> card reader <--> company card

How Can I Get the Card Number?

Use the authentication process of a Remote Download session to your advantage, to get to the card number.

OK, But How Exactly?

In the last APDU of the authentication process, the company cards send the card number with the requested data to the tachograph, just extract the number from it.

It should be for the company card application generation 1 at byte number 4 (0 based index), and 16 bytes long.

Example of the last APDU from a company card (bytes were changed, because this card belongs to my employer):

81 81 8B 12 53 32 30 30 30 34 30 30 30 34 36 33 34 30 30 45 01 43 6F 6E 74
69 6E 65 6E 74 61 6C 20 28 64 65 29 20 37 32 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 55 67 AC 00 55 67 AC 00 65 B2 D5 80 01 43 6F 6D 70 61 6E
79 20 37 32 20 20 20 20 20 20 20 20 20 20 20 60 20 20 20 20 20 20 20 20 20
20 20 20 20 01 61 64 64 72 65 74 73 20 37 32 20 20 24 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 40 20 20 26 20 20 20 63 65 8E 04 05 C9 D2 2F 90 00

The card number in this example is: 53 32 30 30 30 34 30 30 30 34 36 33 34 30 30 45, converted into ASCII it is: S20004000463400E

More Details

For you to read the card number of a company card with just a client application and card reader, you need a Public and Private key pair and a Certificate.

To generate them you can download the Smart Tachograph Keys and Certificates Generation Tool from the European Commission Joint Research Centre for Digital Tachograph here.

With this tool you generate a key pair, and use them to generate and sign a certificate for your application.

Then you need to get your certificate to be signed by your Member State using their private key.

Unfortunately this will not happend, I talked to the person that is responsible for the certificate signing at the Kraftfahrt-Bundesamt (KBA, or the Federal Bureau of Motor Vehicles and Drivers in Germany), and I was told that the European Commission Joint Research Centre for Digital Tachograph does not sign certificates for software for obvious security reasons, only devices like a Tachograph or a Download key device and Cards like a company card.

About the Certificate you Downloaded

This certificate will not help you, because you don't have the Private key that is associated with it.

You need the Private key for the External Authentication that is associated to the certificate, which contains the public key, used in the Internal Authentication.