views:

2676

answers:

10

I need to read account number from Maestro/Mastercard with smart card reader. I am using Java 1.6 and its javax.smartcardio package. I need to send APDU command which will ask EMV application stored on card's chip for PAN number. Problem is, I cannot find regular byte array to construct APDU command which will return needed data anywhere...

A: 

You need to do construct a CommandAPDU object and pass it to the transmit()-command.

You should be able to find the precise command in the documentation for your smartcard, but here is one example:

byte[] readFile(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0xB0, 0x60, 0x10, 0x00);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}
Rasmus Faber
A: 

that is the problem, to find regular byte array with call. I have googled for documentation, and what I have found is not enough. Nobody made example of simple call which will return Card's PAN number or something similar.

My APDU call looks like this:

byte[] commandPAN={0x00, 0xB2,0x5A,0x14,0x00};

which is:

  1. CLA: 0x00 // class
  2. INS: 0xB2 // call
  3. P1: 0x5A // 1.st param
  4. P2: 0x14 // 2.nd param broken into 2 nibbles: 1st nibble: 0x01=SFI 2nd nibble: 0x04=record 4
  5. Lc: 0x00 // lenght of data part = 0 - no data

I got back status: 0x6D00 with no additional data.

Your example also did not returned 0x9000 as a result of regularly finished call:

card: PC/SC card in Generic Usb Smart Card Reader 0, protocol T=1, state OK Sno: T=1

ATR: 'ATR: 17 bytes'
ResponseAPDU: 2 bytes, SW=6e00 NR:0 data length:0

A: 

Did you try looking up in your documentation what 0x6D00 means? It looks like it might mean that the ENVELOPE command is not supported. Have you tried using T=0 protocol instead of T=1?

I would not expect my example to work on your card. I don't know which APDUs the Maestro/MasterCard-supports, so I couldn't give you a working example.

Try giving the command an explicit expected length like this:

byte[] readPan(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0x00, 0xB2, 0x5a, 0x14, 250);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}
Rasmus Faber
A: 

well, what I've concluded is that since only option to connect to card is throug block protocol (T=1) there is need to 'wrap' APDU with some control bytes, i.e. make TPDU. Then maybe, things would work... so your Command APDU would be somewhat longer:

....new CommandAPDU(0x00,0x00,0x00, 0x00, 0xB2, 0x5a, 0x14, 250,0x00);

these bolded zeros would be some control bytes for which I cannot find any documentation, I dont know even if this is the right way to construct TPDU

A: 

You shouldn't need to wrap the APDU further. The API layer should take care of that.

It looks like the 0x6D00 response just means that the application did not support the INS.

Just troubleshooting now, but you did start out by selecting the MasterCard application, right?

I.e. something like this:

void selectApplication(CardChannel channel) throws CardException {
  byte[] masterCardRid = new byte[]{0xA0, 0x00, 0x00, 0x00, 0x04};
  CommandAPDU command = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, masterCardRid);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}
Rasmus Faber
A: 

Perhaps you already knew this but Maestro cards aren't EMV cards...

A: 

(folluw-up of previous post) only the newest Maestro cards follow the EMV standard. Maybe you have an old one?

A: 

I am looking at some examples, and here I've found Pyton app http://www.darkc0de.com/others/ChAP.py

there are codes for selecting app, and SELECT command differs from above. Anyway, yet I did not succeeded to get some results. Will post code if manage it to read data..

+1  A: 

hi all,

here is some working example:

CardChannel channel = card.getBasicChannel(); 

 byte[] selectMaestro={(byte)0x00, (byte)0xA4,(byte)0x04,(byte)0x00 ,(byte)0x07 ,(byte)0xA0 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x04 ,(byte)0x30 ,(byte)0x60 ,(byte)0x00};
  byte[] getProcessingOptions={(byte)0x80,(byte)0xA8,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x83,(byte)0x00,(byte)0x00};
  byte[] readRecord={(byte)0x00,(byte)0xB2,(byte)0x02,(byte)0x0C,(byte)0x00};

  ResponseAPDU r=null;

   try {
     ATR atr = card.getATR(); //reset kartice

      CommandAPDU capdu=new CommandAPDU( selectMaestro   );

       r=card.getBasicChannel().transmit( capdu );

      capdu=new CommandAPDU(getProcessingOptions);
      r=card.getBasicChannel().transmit( capdu );


      capdu=new CommandAPDU(readRecord);
      r=card.getBasicChannel().transmit( capdu );

This works with Maestro card, I can read PAN number, yet now I need to read MasterCard's PAN number. I do not know should I change the read record APDU or select application APDU. Anyone familiar with APDUs?

It is the select application command you need to change. The last part of that command is the AID of the application you want to select. Changing that to the MasterCard AID should work. Or you might want to just shorten the AID. If you supply A400000004, ...
Rasmus Faber
... it should match all AIDs starting with A400000004.
Rasmus Faber
A: 
atr = open();
prints(atr);

prints("[Step 1] Select 1PAY.SYS.DDF01 to get the PSE directory");
cmd = new ISOSelect(ISOSelect.SELECT_AID, EMV4_1.AID_1PAY_SYS_DDF01);
card_response = execute(cmd);
prints(card_response);
SFI = NumUtil.hex2String((byte)((1 < < 3) | 4));

// try SFI 1 record 1
prints("[Step 2] Send READ RECORD with 0 to find out where the record is");
read = new EMVReadRecord(SFI, "01", "00");
card_response = execute(read);
prints(card_response);
byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());

prints("[Step 3] Send READ RECORD with 1C to get the PSE data");
read = new EMVReadRecord(SFI, "01", byte_size);
card_response = execute(read);
prints(card_response);
// the AID is A0000000031010
prints("[Step 4] Now that we know the AID, select the application");

cmd = new ISOSelect(ISOSelect.SELECT_AID, "A0000000031010");
card_response = execute(cmd);
prints(card_response);
prints("[Step 5] Send GET PROCESSING OPTIONS command");

cmd = new EMVGetProcessingOptions();
card_response = execute(cmd);
prints(card_response);

// SFI for the first group of AFL is 0C

prints("[Step 6] Send READ RECORD with 0 to find out where the record is");
read = new EMVReadRecord("0C", "01", "00");
card_response = execute(read);
prints(card_response);
byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());

prints("[Step 7] Use READ RECORD with the given number of bytes to retrieve the data");
read = new EMVReadRecord("0C", "01", byte_size);
card_response = execute(read);
prints(card_response);

data = new TLV(card_response.getData());

close();