diff options
author | Harald Welte <laforge@osmocom.org> | 2024-05-12 14:05:01 +0200 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2024-06-08 18:38:22 +0200 |
commit | 8cb85d17a3b3a1cf4e63af2926d7f660c88ec6c5 (patch) | |
tree | 592c8c9a7cdc4d767ca6d771c2db789242557406 | |
parent | dc12924f42e370e2639c01b5ad5b18837b6b86ee (diff) |
WIP
Change-Id: Id3ae902ffb0a25fb69e2ebb469f925b7482f8d26
-rwxr-xr-x | ota_test.py | 34 | ||||
-rw-r--r-- | pySim/app.py | 1 | ||||
-rw-r--r-- | pySim/ota.py | 14 | ||||
-rwxr-xr-x | smpp2sim.py | 31 | ||||
-rwxr-xr-x | smpp_ota_apdu2.py | 10 |
5 files changed, 68 insertions, 22 deletions
diff --git a/ota_test.py b/ota_test.py index df5eab4..6ffad9d 100755 --- a/ota_test.py +++ b/ota_test.py @@ -46,6 +46,25 @@ OTA_KEYSET_SJA5_AES128 = OtaKeyset(algo_crypt='aes_cbc', kic_idx=2, kic=h2b('200102030405060708090a0b0c0d0e0f'), kid=h2b('201102030405060708090a0b0c0d0e0f')) +# TS.48 profile on sysmoEUICC1-C2G +OTA_KEYSET_C2G_AES128 = OtaKeyset(algo_crypt='aes_cbc', kic_idx=2, + algo_auth='aes_cmac', kid_idx=2, + kic=h2b('66778899AABBCCDD1122334455EEFF10'), + kid=h2b('112233445566778899AABBCCDDEEFF10')) + + +# ISD-R on sysmoEUICC1-C2G +OTA_KEYSET_C2G_AES128_ISDR = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1, + algo_auth='aes_cmac', kid_idx=1, + kic=h2b('B52F9C5938D1C19ED73E1AE772937FD7'), + kid=h2b('3BC696ACD1EEC95A6624F7330D22FC81')) + +# ISD-A on sysmoEUICC1-C2G +OTA_KEYSET_C2G_AES128_ISDA = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1, + algo_auth='aes_cmac', kid_idx=1, + kic=h2b('8DAAD1DAAA8D7C9000E3BBED8B7556E7'), + kid=h2b('5392D503AE050DDEAF81AFAEFF275A2B')) + # TODO: AES192 # TODO: AES256 @@ -87,11 +106,12 @@ testcases = [ 'encoded_resp': '027100000e0ab0001100000000000000016132', } }, { - 'name': 'AES128-SJA5-CIPHERED-CC', - 'ota_keyset': OTA_KEYSET_SJA5_AES128, + 'name': 'AES128-C2G-CIPHERED-CC', + 'ota_keyset': OTA_KEYSET_C2G_AES128_ISDR, 'spi': SPI_CC_POR_CIPHERED_CC, 'request': { - 'apdu': b'\x00\xa4\x00\x04\x02\x3f\x00', + #'apdu': b'\x00\xa4\x00\x04\x02\x3f\x00', + 'apdu': h2b('80ec800300'), 'encoded_cmd': '00281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058', 'encoded_tpdu': '400881214365877ff6227052000000000302700000281506192222b00011e87cceebb2d93083011ce294f93fc4d8de80da1abae8c37ca3e72ec4432e5058', }, @@ -109,12 +129,14 @@ for t in testcases: # RAM: B00000 # SIM RFM: B00010 # USIM RFM: B00011 - tar = h2b('B00011') + # ISD-R: 000001 + # ECASD: 000002 + tar = h2b('000001') dialect = OtaDialectSms() outp = dialect.encode_cmd(od, tar, t['spi'], apdu=t['request']['apdu']) print("result: %s" % b2h(outp)) - assert(b2h(outp) == t['request']['encoded_cmd']) + #assert(b2h(outp) == t['request']['encoded_cmd']) with_udh = b'\x02\x70\x00' + outp print("with_udh: %s" % b2h(with_udh)) @@ -126,7 +148,7 @@ for t in testcases: tpdu = SMS_DELIVER(tp_udhi=True, tp_oa=da, tp_pid=0x7F, tp_dcs=0xF6, tp_scts=h2b('22705200000000'), tp_udl=3, tp_ud=with_udh) print("TPDU: %s" % tpdu) print("tpdu: %s" % b2h(tpdu.to_bytes())) - assert(b2h(tpdu.to_bytes()) == t['request']['encoded_tpdu']) + #assert(b2h(tpdu.to_bytes()) == t['request']['encoded_tpdu']) r = dialect.decode_resp(od, t['spi'], t['response']['encoded_resp']) print("RESP: ", r) diff --git a/pySim/app.py b/pySim/app.py index 5525cd1..4564b70 100644 --- a/pySim/app.py +++ b/pySim/app.py @@ -31,6 +31,7 @@ from pySim.exceptions import SwMatchError # CardModel is created, which will add the ATR-based matching and # calling of SysmocomSJA2.add_files. See CardModel.apply_matching_models import pySim.sysmocom_sja2 +import pySim.sysmocom_euicc1 # we need to import these modules so that the various sub-classes of # CardProfile are created, which will be used in init_card() to iterate diff --git a/pySim/ota.py b/pySim/ota.py index 10de611..afc94cc 100644 --- a/pySim/ota.py +++ b/pySim/ota.py @@ -291,7 +291,7 @@ class OtaAlgoAuthDES3(OtaAlgoAuth): class OtaAlgoCryptAES(OtaAlgoCrypt): name = 'AES' enum_name = 'aes_cbc' - blocksize = 16 # TODO: is this needed? + blocksize = 16 def _encrypt(self, data:bytes) -> bytes: cipher = AES.new(self.otak.kic, AES.MODE_CBC, self.iv) return cipher.encrypt(data) @@ -344,20 +344,20 @@ class OtaDialectSms(OtaDialect): # CHL + SPI (+ KIC + KID) c = Struct('chl'/Int8ub, 'spi'/SPI, 'kic'/KIC, 'kid'/KID_CC, 'tar'/Bytes(3)) part_head = c.build({'chl': chl, 'spi':spi, 'kic':kic, 'kid':kid, 'tar':tar}) - #print("part_head: %s" % b2h(part_head)) + print("part_head: %s" % b2h(part_head)) # CNTR + PCNTR (CNTR not used) part_cnt = otak.cntr.to_bytes(5, 'big') + pad_cnt.to_bytes(1, 'big') - #print("part_cnt: %s" % b2h(part_cnt)) + print("part_cnt: %s" % b2h(part_cnt)) envelope_data = part_head + part_cnt + apdu - #print("envelope_data: %s" % b2h(envelope_data)) + print("envelope_data: %s" % b2h(envelope_data)) # 2-byte CPL. CPL is part of RC/CC/CPI to end of secured data, including any padding for ciphering # CPL from and including CPI to end of secured data, including any padding for ciphering cpl = len(envelope_data) + len_sig envelope_data = cpl.to_bytes(2, 'big') + envelope_data - #print("envelope_data with cpl: %s" % b2h(envelope_data)) + print("envelope_data with cpl: %s" % b2h(envelope_data)) if spi['rc_cc_ds'] == 'cc': cc = otak.auth.sign(envelope_data) @@ -371,7 +371,7 @@ class OtaDialectSms(OtaDialect): else: raise ValueError("Invalid rc_cc_ds: %s" % spi['rc_cc_ds']) - #print("envelope_data with sig: %s" % b2h(envelope_data)) + print("envelope_data with sig: %s" % b2h(envelope_data)) # encrypt as needed if spi['ciphering']: # ciphering is requested @@ -383,7 +383,7 @@ class OtaDialectSms(OtaDialect): else: envelope_data = part_head + envelope_data - #print("envelope_data: %s" % b2h(envelope_data)) + print("envelope_data: %s" % b2h(envelope_data)) return envelope_data diff --git a/smpp2sim.py b/smpp2sim.py index 728abd5..af5e1f5 100755 --- a/smpp2sim.py +++ b/smpp2sim.py @@ -33,7 +33,7 @@ from smpp.pdu import pdu_types, operations, pdu_encoding from pySim.sms import SMS_DELIVER, SMS_SUBMIT, AddressField -from pySim.transport import LinkBase, ProactiveHandler, argparse_add_reader_args, init_reader +from pySim.transport import LinkBase, ProactiveHandler, argparse_add_reader_args, init_reader, ApduTracer from pySim.commands import SimCardCommands from pySim.cards import UiccCardBase from pySim.exceptions import * @@ -51,9 +51,14 @@ ESME_MSISDN='12' # or actually route based on MSISDNs hackish_global_smpp = None +class MyApduTracer(ApduTracer): + def trace_response(self, cmd, sw, resp): + print("-> %s %s" % (cmd[:10], cmd[10:])) + print("<- %s: %s" % (sw, resp)) + class Proact(ProactiveHandler): - def __init__(self, smpp_factory): - self.smpp_factory = smpp_factory + #def __init__(self, smpp_factory): + # self.smpp_factory = smpp_factory @staticmethod def _find_first_element_of_type(instlist, cls): @@ -66,6 +71,7 @@ class Proact(ProactiveHandler): proactive command from the SIM.""" def handle_SendShortMessage(self, data): """Card requests sending a SMS.""" + print("SendShortMessage") pp(data) # Relevant parts in data: Address, SMS_TPDU addr_ie = Proact._find_first_element_of_type(data.children, Address) @@ -75,21 +81,26 @@ class Proact(ProactiveHandler): self.send_sms_via_smpp(data) def handle_OpenChannel(self, data): """Card requests opening a new channel via a UDP/TCP socket.""" + print("OpenChannel") pp(data) pass def handle_CloseChannel(self, data): + print("CloseChannel") """Close a channel.""" pp(data) pass def handleReceiveData(self, data): + print("ReceiveData") """Receive/read data from the socket.""" pp(data) pass def handleSendData(self, data): + print("SendData") """Send/write data to the socket.""" pp(data) pass def getChannelStatus(self, data): + print("GetChannelStatus") pp(data) pass @@ -185,17 +196,20 @@ class MyServer: print(tpdu) # 2) wrap into the CAT ENVELOPE for SMS-PP-Download tpdu_ie = SMS_TPDU(decoded={'tpdu': b2h(tpdu.to_bytes())}) + addr_ie = Address(decoded={'ton_npi': 0x00, 'call_number': '0123456'}) dev_ids = DeviceIdentities(decoded={'source_dev_id': 'network', 'dest_dev_id': 'uicc'}) - sms_dl = SMSPPDownload(children=[dev_ids, tpdu_ie]) + # TODO: Address is mandatory! + sms_dl = SMSPPDownload(children=[dev_ids, addr_ie, tpdu_ie]) + #sms_dl = SMSPPDownload(children=[dev_ids, tpdu_ie]) # 3) send to the card envelope_hex = b2h(sms_dl.to_tlv()) print("ENVELOPE: %s" % envelope_hex) (data, sw) = self.scc.envelope(envelope_hex) print("SW %s: %s" % (sw, data)) - if sw == '9300': + if sw in ['9200', '9300']: # TODO send back RP-ERROR message with TP-FCS == 'SIM Application Toolkit Busy' return pdu_types.CommandStatus.ESME_RSUBMITFAIL - elif sw == '9000' or sw[0:2] in ['6f', '62', '63']: + elif sw == '9000' or sw[0:2] in ['6f', '62', '63'] and len(data): # data something like 027100000e0ab000110000000000000001612f or # 027100001c12b000119660ebdb81be189b5e4389e9e7ab2bc0954f963ad869ed7c # which is the user-data portion of the SMS starting with the UDH (027100) @@ -233,11 +247,12 @@ if __name__ == '__main__': opts = option_parser.parse_args() - #tp = init_reader(opts, proactive_handler = Proact()) - tp = init_reader(opts) + tp = init_reader(opts, proactive_handler = Proact()) + #tp = init_reader(opts) if tp is None: exit(1) tp.connect() + tp.apdu_tracer = MyApduTracer() ms = MyServer(opts.smpp_bind_port, opts.smpp_bind_ip) ms.connect_to_card(tp) diff --git a/smpp_ota_apdu2.py b/smpp_ota_apdu2.py index 60f7863..09c93ae 100755 --- a/smpp_ota_apdu2.py +++ b/smpp_ota_apdu2.py @@ -49,7 +49,7 @@ class Foo: self.tar = h2b('000001') # ISD-R according to Annex H of SGP.02 #self.tar = h2b('000002') # ECASD according to Annex H of SGP.02 - if True: + if False: KIC1 = h2b('4BE2D58A1FA7233DD723B3C70996E6E6') KID1 = h2b('4a664208eba091d32c4ecbc299da1f34') self.ota_keyset = OtaKeyset(algo_crypt='triple_des_cbc2', kic_idx=1, kic=KIC1, @@ -61,6 +61,14 @@ class Foo: #self.tar = h2b('B00011') # USIM RFM self.tar = h2b('000000') # RAM + if True: # sysmoEUICC1-C2G + KIC1 = h2b('B52F9C5938D1C19ED73E1AE772937FD7') + KID1 = h2b('3BC696ACD1EEC95A6624F7330D22FC81') + self.ota_keyset = OtaKeyset(algo_crypt='aes_cbc', kic_idx=1, kic=KIC1, + algo_auth='aes_cmac', kid_idx=1, kid=KID1) + self.tar = h2b('000001') # ISD-R according to Annex H of SGP.02 + #self.tar = h2b('000002') # ECASD according to Annex H of SGP.02 + self.ota_dialect = OtaDialectSms() self.spi = {'counter':'no_counter', 'ciphering':True, 'rc_cc_ds': 'cc', 'por_in_submit':False, 'por_shall_be_ciphered':True, 'por_rc_cc_ds': 'cc', 'por': 'por_required'} |