3

I have tried many sample codes to parse APDU response to TLV format. I am able to parse it properly if the response length is less but facing issue if length is more(how calculate length of a tag without any libraries)

NOTE: I am using predefined tags in Constants

code:

private HashMap<String, String> parseTLV(String apduResponse) {

    HashMap<String, String> tagValue = new HashMap<>();
    String remainingApdu = apduResponse.replaceAll(" ", "");
    if (remainingApdu.endsWith(ResponseTags._SUCCESS_STATUSWORDS)) {
        remainingApdu = remainingApdu.substring(0, remainingApdu.length() - 4);
    }
    while (remainingApdu != null && remainingApdu.length() > 2) {
        remainingApdu = addTagValue(tagValue, remainingApdu);
    }
    return tagValue;
}

addTagValue method

   private String addTagValue(HashMap<String, String> tagValue, String apduResponse) {
        String tag = "";
        String length = "";
        String value = "";
        int tagLen = 0;

        if (tagUtils.isValidTag(apduResponse.substring(0, 2))) {
            tagLen = readTagLength(apduResponse.substring(3));
            // tagLen = 2;
            tag = apduResponse.substring(0, 2);
        } else if (tagUtils.isValidTag(apduResponse.substring(0, 4))) {
            tagLen = 4;
            tag = apduResponse.substring(0, 4);
        } else {
            return "";
        }
        Log.e("TAG_LEN","tag: "+tag+"taglen: "+tagLen);
        if (tagUtils.shouldCheckValueFor(tag)) {
            length = apduResponse.substring(tagLen, tagLen + 2);
            int len = tagUtils.hexToDecimal(length);
            value = apduResponse.substring(tagLen + 2, (len * 2) + tagLen + 2);
            tagValue.put(tag, value);
            if (ResponseTags.getRespTagsmap().containsKey(tag)) {
                //logData = logData + "\nKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag)/* + " VALUE:" + value + "\n "*/;
            }
            if (tagUtils.isTemplateTag(tag)) {
              //  logData = logData + "\n\t-->";
                return addTagValue(tagValue, value) + apduResponse.substring(tag.length() + value.length() + length.length());
            } else {
                return apduResponse.substring(tag.length() + value.length() + length.length());
            }
        } else {
            value = apduResponse.substring(2, 4);
            tagValue.put(tag, value);
//            logData = logData + "\n\t\tKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag) /*+ " VALUE:" + value + "\n "*/;
            return apduResponse.substring(tag.length() + value.length() + length.length());
        }
    }

readTagLength :

private int readTagLength(String apduResponse) {
    int len_bytes = 0;
    if (apduResponse.length() > 2) {
        len_bytes = (apduResponse.length()) / 2;
    }
    Log.e("tlv length:", "bytes:" + len_bytes);
    if (len_bytes < 128) {
        return 2;
    } else if (len_bytes > 127 && len_bytes < 255) {
        return 4;
    } else {
        return 6;
    }
}

I cannot able to get length properly for few cards(if apdu response is long) Please help

Uma Achanta
  • 3,669
  • 4
  • 22
  • 49
  • 2
    Possible duplicate of [Is there a Java parser for BER-TLV?](https://stackoverflow.com/questions/11473974/is-there-a-java-parser-for-ber-tlv) – arved Dec 27 '18 at 13:55
  • Possible duplicate of https://stackoverflow.com/questions/36375710/emv-javacard-apdu-response-in-tlv-format – Varun Jain Jan 04 '19 at 13:39

2 Answers2

1

First be sure the input data is proper before you go into the code. Take the full data and try it on https://www.emvlab.org/tlvutils/ .

Once its confirmed the data is proper, go through in EMV 4.3 Book 3, Annex B Rules for BER-TLV Data Objects sections B1, B2, B3 - with utmost attention.

If you follow this precisely, then you wouldn't need to store a static list of tags; will save time in future.

Adarsh Nanu
  • 2,133
  • 1
  • 13
  • 18
  • Please read the question, mentioned specifically that "cannot able to get length properly for few cards". – Uma Achanta Dec 28 '18 at 11:38
  • Please share the APDU which is not getting parsed well in your application. Can you share the logs? – Adarsh Nanu Dec 28 '18 at 15:02
  • The issue is about not about apdu. Its abouts getting length of data in tlv without using any library. Read the question please – Uma Achanta Dec 29 '18 at 14:36
  • I have implemented it end to end without any third party libraries, just by following the tag length and value specification in the document reference I have shared. Bye. – Adarsh Nanu Dec 29 '18 at 14:43
  • @UmaAchanta You need to implement multibyte tag identifiers (you support up to two bytes only) and multibyte tag lengths correctly (it doesn't look like parsing length at all). It is described in the documentation for BER and you may try https://en.wikipedia.org/wiki/X.690 as a decent source. Length has most significant bit set when it is coded on more than one byte. – Michal Gluchowski Jan 22 '19 at 14:56
0

Below sample has an assumption that TLV array is ending with special 0x00 tag but for sure you can ignore it.

Pojo class :

public class Tlv {

    private short tag;

    private byte[] value;

    public Tlv(short tag) {
        this.tag = tag;
    }
    public short getTag() {
        return tag;
    }
    public byte[] getValue() {
        return value;
    }
    public void setValue(byte[] valueBytes) {
        this.value = valueBytes;
    }
}

Utility method :

public static Map<Byte, Tlv> parse(ByteBuffer bb) throws TlvException {

    Map<Byte, Tlv> tlvs = null;
    tlvs = new HashMap<Byte, Tlv>();
    try {
        while (bb.remaining() > 0) {
            byte tag = bb.get();
            if(tag == 0x00)
                continue;
            int length = bb.get();
            byte[] value = new byte[length];
            bb.get(value, 0, length);
            Tlv tlv = new Tlv(tag);
            tlv.setValue(value);
            tlvs.put(tag, tlv);
        }
    } catch (IndexOutOfBoundsException e) {
        throw new TlvException("Malformed TLV part: " + bb.toString() + ".", e);
    }
    return tlvs;
}   
Kemal Atik
  • 307
  • 3
  • 12
  • Your parsing method doesn't include coverage for multiple byte tag identifiers (the ones that have 5 lowest significant bits set on first byte and those that may indicate on the most significant bit on second and later bytes). Your length doesn't also include support for multiple byte lengths (the ones with the most significant bit set and with indication of the number of length bytes). – Michal Gluchowski Jan 22 '19 at 14:40