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.
***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";
6688
instead of a6988
? And maybe you are referring to "INS" (short for "INStruction") instead of "INC" (usually short for "INCrease")? – Maarten Bodewes6688
. Yes I meant INS instead ofINC
. – Mr Asker