laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/37435?usp=email )
Change subject: pySim.tlv: Add COMPACT_TLV_IE TLV variant ......................................................................
pySim.tlv: Add COMPACT_TLV_IE TLV variant
the COMPACT-TLV variant is a TLV variant that ISO7816 uses for encoding tag and length into a single octet. This is used (for example) in ATR historical bytes.
Let's add support for this to our pySim TLV encoder/decoder.
Change-Id: I9e98d150b97317ae0c6be2366bdaaeaeddf8031c --- M pySim/tlv.py M tests/test_tlv.py 2 files changed, 69 insertions(+), 1 deletion(-)
Approvals: fixeria: Looks good to me, but someone else must approve laforge: Looks good to me, approved Jenkins Builder: Verified
diff --git a/pySim/tlv.py b/pySim/tlv.py index d7c6876..6dc5301 100644 --- a/pySim/tlv.py +++ b/pySim/tlv.py @@ -246,6 +246,35 @@ return dec, remainder
+class COMPACT_TLV_IE(TLV_IE): + """TLV_IE formatted as COMPACT-TLV described in ISO 7816""" + + @classmethod + def _parse_tag_raw(cls, do: bytes) -> Tuple[int, bytes]: + return do[0] >> 4, do + + @classmethod + def _decode_tag(cls, do: bytes) -> Tuple[dict, bytes]: + rawtag, remainder = cls._parse_tag_raw(do) + return {'tag': rawtag}, remainder + + @classmethod + def _parse_len(cls, do: bytes) -> Tuple[int, bytes]: + return do[0] & 0xf, do[1:] + + def _encode_tag(self) -> bytes: + """Not needed as we override the to_tlv() method to encode tag+length into one byte.""" + raise NotImplementedError + + def _encode_len(self): + """Not needed as we override the to_tlv() method to encode tag+length into one byte.""" + raise NotImplementedError + + def to_tlv(self, context: dict = {}): + val = self.to_bytes(context=context) + return bytes([(self.tag << 4) | (len(val) & 0xF)]) + val + + class BER_TLV_IE(TLV_IE): """TLV_IE formatted as ASN.1 BER described in ITU-T X.690 8.1.2."""
diff --git a/tests/test_tlv.py b/tests/test_tlv.py index 0e73ab1..3b05f19 100644 --- a/tests/test_tlv.py +++ b/tests/test_tlv.py @@ -17,8 +17,9 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
import unittest -from construct import Int8ub +from construct import Int8ub, GreedyBytes from pySim.tlv import * +from pySim.utils import h2b
class TestUtils(unittest.TestCase): def test_camel_to_snake(self): @@ -117,5 +118,28 @@ self.assertEqual(ie.to_bytes(), b'\x42') self.assertEqual(ie.to_ie(), b'\x42')
+class TestCompact(unittest.TestCase): + class IE_3(COMPACT_TLV_IE, tag=0x3): + _construct = GreedyBytes + class IE_7(COMPACT_TLV_IE, tag=0x7): + _construct = GreedyBytes + class IE_5(COMPACT_TLV_IE, tag=0x5): + _construct = GreedyBytes + # pylint: disable=undefined-variable + class IE_Coll(TLV_IE_Collection, nested=[IE_3, IE_7, IE_5]): + _construct = GreedyBytes + def test_ATR(self): + atr = h2b("31E073FE211F5745437531301365") + c = self.IE_Coll() + c.from_tlv(atr) + self.assertEqual(c.children[0].tag, 3) + self.assertEqual(c.children[0].to_bytes(), b'\xe0') + self.assertEqual(c.children[1].tag, 7) + self.assertEqual(c.children[1].to_bytes(), b'\xfe\x21\x1f') + self.assertEqual(c.children[2].tag, 5) + self.assertEqual(c.children[2].to_bytes(), b'\x45\x43\x75\x31\x30\x13\x65') + self.assertEqual(c.to_tlv(), atr) + + if __name__ == "__main__": unittest.main()