diff options
-rw-r--r-- | pySim/construct.py | 31 | ||||
-rw-r--r-- | pySim/global_platform/__init__.py | 52 | ||||
-rw-r--r-- | tests/test_construct.py | 22 |
3 files changed, 80 insertions, 25 deletions
diff --git a/pySim/construct.py b/pySim/construct.py index 988dbf3..8ef7941 100644 --- a/pySim/construct.py +++ b/pySim/construct.py @@ -365,6 +365,37 @@ class Ipv6Adapter(Adapter): ia = ipaddress.IPv6Address(obj) return ia.packed +class StripTrailerAdapter(Adapter): + """ + Encoder removes all trailing bytes matching the default_value + Decoder pads input data up to total_length with default_value + + This is used in constellations like "FlagsEnum(StripTrailerAdapter(GreedyBytes, 3), ..." + where you have a bit-mask that may have 1, 2 or 3 bytes, depending on whether or not any + of the LSBs are actually set. + """ + def __init__(self, subcon, total_length:int, default_value=b'\x00', min_len=1): + super().__init__(subcon) + assert len(default_value) == 1 + self.total_length = total_length + self.default_value = default_value + self.min_len = min_len + + def _decode(self, obj, context, path): + assert type(obj) == bytes + # pad with suppressed/missing bytes + if len(obj) < self.total_length: + obj += self.default_value * (self.total_length - len(obj)) + return int.from_bytes(obj, 'big') + + def _encode(self, obj, context, path): + assert type(obj) == int + obj = obj.to_bytes(self.total_length, 'big') + # remove trailing bytes if they are zero + while len(obj) > self.min_len and obj[-1] == self.default_value[0]: + obj = obj[:-1] + return obj + def filter_dict(d, exclude_prefix='_'): """filter the input dict to ensure no keys starting with 'exclude_prefix' remain.""" diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py index 494cfe1..7b5ab8f 100644 --- a/pySim/global_platform/__init__.py +++ b/pySim/global_platform/__init__.py @@ -124,15 +124,16 @@ class KeyInformation(BER_TLV_IE, tag=0xe0, nested=[KeyInformationData]): pass # GP v2.3 11.1.9 -KeyUsageQualifier = Struct('byte1'/FlagsEnum(Byte, verification_encryption=0x80, - computation_decipherment=0x40, - sm_response=0x20, - sm_command=0x10, - confidentiality=0x08, - crypto_checksum=0x04, - digital_signature=0x02, - crypto_authorization=0x01), - 'byte2'/COptional(FlagsEnum(Byte, key_agreement=0x80))) +KeyUsageQualifier = FlagsEnum(StripTrailerAdapter(GreedyBytes, 2), + verification_encryption=0x8000, + computation_decipherment=0x4000, + sm_response=0x2000, + sm_command=0x1000, + confidentiality=0x0800, + crypto_checksum=0x0400, + digital_signature=0x0200, + crypto_authorization=0x0100, + key_agreement=0x0080) # GP v2.3 11.1.10 KeyAccess = Enum(Byte, sd_and_any_assoc_app=0x00, sd_only=0x01, any_assoc_app_but_not_sd=0x02, @@ -210,13 +211,13 @@ class SupportedLFDBHAlgorithms(BER_TLV_IE, tag=0x83): class CiphersForLFDBEncryption(BER_TLV_IE, tag=0x84): _construct = Enum(Byte, tripledes16=0x01, aes128=0x02, aes192=0x04, aes256=0x08, icv_supported_for_lfdb=0x80) -CipherSuitesForSignatures = Struct('byte1'/FlagsEnum(Byte, rsa1024_pkcsv15_sha1=0x01, - rsa_gt1024_pss_sha256=0x02, - single_des_plus_final_triple_des_mac_16b=0x04, - cmac_aes128=0x08, cmac_aes192=0x10, cmac_aes256=0x20, - ecdsa_ecc256_sha256=0x40, ecdsa_ecc384_sha384=0x80), - 'byte2'/COptional(FlagsEnum(Byte, ecdsa_ecc512_sha512=0x01, - ecdsa_ecc_521_sha512=0x02))) +CipherSuitesForSignatures = FlagsEnum(StripTrailerAdapter(GreedyBytes, 2), + rsa1024_pkcsv15_sha1=0x0100, + rsa_gt1024_pss_sha256=0x0200, + single_des_plus_final_triple_des_mac_16b=0x0400, + cmac_aes128=0x0800, cmac_aes192=0x1000, cmac_aes256=0x2000, + ecdsa_ecc256_sha256=0x4000, ecdsa_ecc384_sha384=0x8000, + ecdsa_ecc512_sha512=0x0001, ecdsa_ecc_521_sha512=0x0002) class CiphersForTokens(BER_TLV_IE, tag=0x85): _construct = CipherSuitesForSignatures class CiphersForReceipts(BER_TLV_IE, tag=0x86): @@ -387,15 +388,16 @@ class LifeCycleState(BER_TLV_IE, tag=0x9f70): # Section 11.4.3.1 Table 11-36 + Section 11.1.2 class Privileges(BER_TLV_IE, tag=0xc5): - _construct = Struct('byte1'/FlagsEnum(Byte, security_domain=0x80, dap_verification=0x40, - delegated_management=0x20, card_lock=0x10, card_terminate=0x08, - card_reset=0x04, cvm_management=0x02, - mandated_dap_verification=0x01), - 'byte2'/COptional(FlagsEnum(Byte, trusted_path=0x80, authorized_management=0x40, - token_management=0x20, global_delete=0x10, global_lock=0x08, - global_registry=0x04, final_application=0x02, global_service=0x01)), - 'byte3'/COptional(FlagsEnum(Byte, receipt_generation=0x80, ciphered_load_file_data_block=0x40, - contactless_activation=0x20, contactless_self_activation=0x10))) + _construct = FlagsEnum(StripTrailerAdapter(GreedyBytes, 3), + security_domain=0x800000, dap_verification=0x400000, + delegated_management=0x200000, card_lock=0x100000, card_terminate=0x080000, + card_reset=0x040000, cvm_management=0x020000, + mandated_dap_verification=0x010000, + trusted_path=0x8000, authorized_management=0x4000, + token_management=0x2000, global_delete=0x1000, global_lock=0x0800, + global_registry=0x0400, final_application=0x0200, global_service=0x0100, + receipt_generation=0x80, ciphered_load_file_data_block=0x40, + contactless_activation=0x20, contactless_self_activation=0x10) # Section 11.4.3.1 Table 11-36 + Section 11.1.7 class ImplicitSelectionParameter(BER_TLV_IE, tag=0xcf): diff --git a/tests/test_construct.py b/tests/test_construct.py index 11822a8..6251a14 100644 --- a/tests/test_construct.py +++ b/tests/test_construct.py @@ -1,7 +1,9 @@ #!/usr/bin/env python3 import unittest +from pySim.utils import b2h, h2b from pySim.construct import * +from construct import FlagsEnum tests = [ ( b'\x80', 0x80 ), @@ -75,6 +77,26 @@ class TestUcs2Adapter(unittest.TestCase): re_enc = self.ad._encode(string, None, None) self.assertEqual(encoded, re_enc) +class TestTrailerAdapter(unittest.TestCase): + Privileges = FlagsEnum(StripTrailerAdapter(GreedyBytes, 3), security_domain=0x800000, + dap_verification=0x400000, + delegated_management=0x200000, card_lock=0x100000, + card_terminate=0x080000, card_reset=0x040000, + cvm_management=0x020000, mandated_dap_verification=0x010000, + trusted_path=0x8000, authorized_management=0x4000, + token_management=0x2000, global_delete=0x1000, + global_lock=0x0800, global_registry=0x0400, + final_application=0x0200, global_service=0x0100, + receipt_generation=0x80, ciphered_load_file_data_block=0x40, + contactless_activation=0x20, contactless_self_activation=0x10) + examples = ['00', '80', '8040', '400010'] + def test_examples(self): + for e in self.examples: + dec = self.Privileges.parse(h2b(e)) + reenc = self.Privileges.build(dec) + self.assertEqual(e, b2h(reenc)) + + if __name__ == "__main__": |