mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-29 22:35:47 +03:00
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
This commit is contained in:
29
pySim/tlv.py
29
pySim/tlv.py
@@ -246,6 +246,35 @@ class TLV_IE(IE):
|
|||||||
return dec, remainder
|
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):
|
class BER_TLV_IE(TLV_IE):
|
||||||
"""TLV_IE formatted as ASN.1 BER described in ITU-T X.690 8.1.2."""
|
"""TLV_IE formatted as ASN.1 BER described in ITU-T X.690 8.1.2."""
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from construct import Int8ub
|
from construct import Int8ub, GreedyBytes
|
||||||
from pySim.tlv import *
|
from pySim.tlv import *
|
||||||
|
from pySim.utils import h2b
|
||||||
|
|
||||||
class TestUtils(unittest.TestCase):
|
class TestUtils(unittest.TestCase):
|
||||||
def test_camel_to_snake(self):
|
def test_camel_to_snake(self):
|
||||||
@@ -117,5 +118,28 @@ class TestIE(unittest.TestCase):
|
|||||||
self.assertEqual(ie.to_bytes(), b'\x42')
|
self.assertEqual(ie.to_bytes(), b'\x42')
|
||||||
self.assertEqual(ie.to_ie(), 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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user