1

My method parseTLV() sometimes does not properly decend into constructed values (child TLVs). I use a filter ((tag & 0x20)! = 0) to detect constructed values, but sometimes it doesn't work as expected.

For example

70178C159F02069F03069F1A0295055F2A029A039C019F3704

leads to the following result for parseTLV:

  • Tag: 70 - Value: 8C159F02069F03069F1A0295055F2A029A039C019F3704
  • Tag: 8C - Value: 9F02069F03069F1A0295055F2A029A039C019F3704

However, I would expect to get

  • Tag: 70 - Value: 8C159F02069F03069F1A0295055F2A029A039C019F3704
  • Tag: 8C - Value: 9F02069F03069F1A0295055F2A029A039C019F3704
    • Tag: 9F02 - Value: 06
    • Tag: 9F03 - Value: 06
    • Tag: 9F1A - Value: 02
    • Tag: 95 - Value: 05
    • Tag: 5F2A - Value: 02
    • Tag: 9A - Value: 03
    • Tag: 9C - Value: 01
    • Tag: 9F37 - Value: 04
private ITlv.ITlvDataObjList parseTLV(byte[] src) {
    try {
        if (isBytesEmpty(src)) {
            return null;
        }
        _tlvList = _tlv.createTlvDataObjectList();
        int start = 0;
        int end = start + src.length;
        while (start < end) {
            // tag has 1 byte (0xFF)
            int tag = src[start++] & 0xFF;
            //
            if (tag == 0x00 || tag == 0xFF) {
                continue;
            }
            // tag has more bytes?
            if ((tag & 0x1F) == 0x1F) {
                if (start >= src.length) {
                    break;
                }
                // tag has 2 bytes (0xFFFF)
                tag = (tag << 8) | src[start++] & 0xFF;
                // tag has 3 bytes (0xFFFFFF)
                if ((tag & 0x80) != 0) {
                    if (start >= src.length) {
                        break;
                    }
                    tag = (tag << 8) | src[start++] & 0xFF;
                }
                // break when tag > 3 bytes
                if ((tag & 0x80) != 0) {
                    continue;
                }
            }
            // length 1 byte (0x7F)
            int length = src[start++] & 0xFF;
            // length has more bytes?
            if (length >= 0x80) {
                // break when length > 2 bytes 
                int count = length & 0x7F;
                if (count > 3) {
                    continue;
                }
                // length 1 bytes (0x80-0xFF) or 2 bytes (0x100-0xFFFF)
                length = 0;
                for (int k = 0; k < count; k++) {
                    if (start >= src.length) {
                        break;
                    }
                    length = (length << 8) | src[start++] & 0xFF;
                }
            }
            // values
            byte[] value = new byte[length];
            System.arraycopy(src, start, value, 0, length);
            //
            // create tlv object
            ITlv.ITlvDataObj tlvObj = _tlv.createTlvDataObject();
            tlvObj.setTag(tag);
            tlvObj.setValue(value);
            // save tlv object to list
            _tlvList.addDataObj(tlvObj);
            //
            // next tag
            while (tag > 0xFF) {
                tag = tag >> 8;
            }
            // is constructed (has child)?
            if ((tag & 0x20) != 0) {
                continue;
            }
            start = start + value.length;
        }
        return _tlvList;
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}
Ihdina
  • 452
  • 3
  • 12

2 Answers2

1

The tag 8C does not contain a constructed value. Consequently, your test for ((tag & 0x20) != 0) fails correctly. Instead, that TLV contains a data object list as its value. When you look at the value 9F02069F03069F1A0295055F2A029A039C019F3704, you'll find that these are not complete TLV onbjects but only tags + lengths.

Consequently, you will have to find out based on the tag whether that TLV object contains a data object list. Then you can parse that list in a similar way to parsing complete TLV objects except that you skip the empty value field.

Michael Roland
  • 36,432
  • 10
  • 81
  • 168
-1

If EMV standards are not completely adhered to, your code may fail for below common reasons

  • Tags may be longer than two bytes( from the code, you are not processing tags more than two bytes. The chance of encountering is low however )
  • Length may be more than a byte long( though commonly length comes in one byte).
  • Any new tag introduced by EMV will fail if you try to compare the tags against a list( ignore this if you do not ).

EMV 4.3 Book 3, Annex B Rules for BER-TLV Data Objects sections B1, B2, B3 is the correct place to look for. If you follow this precisely, all the above can be avoided.

Adarsh Nanu
  • 1,833
  • 1
  • 11
  • 17