pySim/transport add support for T=1 protocol and fix APDU/TPDU layer conflicts
ETSI TS 102 221, section 7.3 specifies that UICCs (and eUICCs) may support two different transport protocols: T=0 or T=1 or both. The spec also says that the terminal must support both protocols. This patch adds the necessary functionality to support the T=1 protocol alongside the T=0 protocol. However, this also means that we have to sharpen the lines between APDUs and TPDUs. As this patch also touches the low level interface to readers it was also manually tested with a classic serial reader. Calypso and AT command readers were not tested. Change-Id: I8b56d7804a2b4c392f43f8540e0b6e70001a8970 Related: OS#6367
This commit is contained in:
0
tests/pySim-shell_test/apdu/__init__.py
Normal file
0
tests/pySim-shell_test/apdu/__init__.py
Normal file
70
tests/pySim-shell_test/apdu/test.py
Normal file
70
tests/pySim-shell_test/apdu/test.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Testsuite for pySim-shell.py
|
||||
#
|
||||
# (C) 2024 by sysmocom - s.f.m.c. GmbH
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Author: Philipp Maier
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import unittest
|
||||
import os
|
||||
from utils import *
|
||||
|
||||
class test_case(UnittestUtils):
|
||||
|
||||
def test_apdu_legacy(self):
|
||||
cardname = 'sysmoISIM-SJA5-S17'
|
||||
|
||||
self.runPySimShell(cardname, "test_apdu_legacy.script", no_exceptions = True)
|
||||
|
||||
def test_apdu_legacy_scp02(self):
|
||||
cardname = 'sysmoISIM-SJA5-S17'
|
||||
|
||||
self.equipTemplate("test_apdu_legacy_scp02.script", SEC_LEVEL = 3)
|
||||
self.runPySimShell(cardname, "test_apdu_legacy_scp02.script", no_exceptions = True, add_csv = True)
|
||||
self.equipTemplate("test_apdu_legacy_scp02.script", SEC_LEVEL = 1)
|
||||
self.runPySimShell(cardname, "test_apdu_legacy_scp02.script", no_exceptions = True, add_csv = True)
|
||||
|
||||
def test_apdu_legacy_scp03(self):
|
||||
cardname = 'sysmoEUICC1-C2T'
|
||||
|
||||
self.equipTemplate("test_apdu_legacy_scp03.script", SEC_LEVEL = 3)
|
||||
self.runPySimShell(cardname, "test_apdu_legacy_scp03.script", no_exceptions = True, add_csv = True)
|
||||
self.equipTemplate("test_apdu_legacy_scp03.script", SEC_LEVEL = 1)
|
||||
self.runPySimShell(cardname, "test_apdu_legacy_scp03.script", no_exceptions = True, add_csv = True)
|
||||
|
||||
def test_apdu(self):
|
||||
cardname = 'sysmoISIM-SJA5-S17'
|
||||
|
||||
self.runPySimShell(cardname, "test_apdu.script", no_exceptions = True)
|
||||
|
||||
def test_apdu_legacy_scp02(self):
|
||||
cardname = 'sysmoISIM-SJA5-S17'
|
||||
|
||||
self.equipTemplate("test_apdu_scp02.script", SEC_LEVEL = 3)
|
||||
self.runPySimShell(cardname, "test_apdu_scp02.script", no_exceptions = True, add_csv = True)
|
||||
self.equipTemplate("test_apdu_scp02.script", SEC_LEVEL = 1)
|
||||
self.runPySimShell(cardname, "test_apdu_scp02.script", no_exceptions = True, add_csv = True)
|
||||
|
||||
def test_apdu_legacy_scp03(self):
|
||||
cardname = 'sysmoEUICC1-C2T'
|
||||
|
||||
self.equipTemplate("test_apdu_scp03.script", SEC_LEVEL = 3)
|
||||
self.runPySimShell(cardname, "test_apdu_scp03.script", no_exceptions = True, add_csv = True)
|
||||
self.equipTemplate("test_apdu_scp03.script", SEC_LEVEL = 1)
|
||||
self.runPySimShell(cardname, "test_apdu_scp03.script", no_exceptions = True, add_csv = True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
20
tests/pySim-shell_test/apdu/test_apdu.script
Normal file
20
tests/pySim-shell_test/apdu/test_apdu.script
Normal file
@@ -0,0 +1,20 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
set apdu_strict true
|
||||
|
||||
# Case #1: (open channel #1)
|
||||
# No command data field, No response data field present
|
||||
apdu 00700001 --expect-sw 9000 --expect-response-regex '^$'
|
||||
|
||||
# Case #2: (status)
|
||||
# No command data field, Response data field present
|
||||
apdu 80F2000000 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$'
|
||||
|
||||
# Case #3: (terminal capability)
|
||||
# Command data field present, No response data field
|
||||
apdu 80AA000005a903830180 --expect-sw 9000 --expect-response-regex '^$'
|
||||
|
||||
# Case #4: (select MF)
|
||||
# Command data field present, Response data field present
|
||||
apdu 00a40004023f0000 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$'
|
||||
21
tests/pySim-shell_test/apdu/test_apdu_legacy.script
Normal file
21
tests/pySim-shell_test/apdu/test_apdu_legacy.script
Normal file
@@ -0,0 +1,21 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
|
||||
# Case #1: (open channel #1)
|
||||
# No command data field, No response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would lack the 0x00 at the end)
|
||||
apdu 0070000100 --expect-sw 9000 --expect-response-regex '^$'
|
||||
|
||||
# Case #2: (status)
|
||||
# No command data field, Response data field present
|
||||
apdu 80F2000000 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$'
|
||||
|
||||
# Case #3: (terminal capability)
|
||||
# Command data field present, No response data field
|
||||
apdu 80AA000005a903830180 --expect-sw 9000 --expect-response-regex '^$'
|
||||
|
||||
# Case #4: (select MF)
|
||||
# Command data field present, Response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would have an additional 0x00 at the end)
|
||||
apdu 00a40004023f00 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$'
|
||||
27
tests/pySim-shell_test/apdu/test_apdu_legacy_scp02.template
Normal file
27
tests/pySim-shell_test/apdu/test_apdu_legacy_scp02.template
Normal file
@@ -0,0 +1,27 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
|
||||
# Establish secure channel:
|
||||
select ADF.ISD
|
||||
establish_scp02 --key-provider-suffix 1 --key-ver 112 --security-level $SEC_LEVEL
|
||||
|
||||
# Case #1: (get status with no data field to mimic a case #1 APDU)
|
||||
# No command data field, No response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would lack the 0x00 at the end)
|
||||
apdu 80F2200200 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #2: (get data)
|
||||
# No command data field, Response data field present
|
||||
apdu 80ca006600 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
# Case #3: (get status with wrong parameters to mimic a case #3 APDU)
|
||||
# Command data field present, No response data field
|
||||
apdu 80F220020a4f0212345c054f9f70c5 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #4: (initialize update, to mimic a case #4 APDU, this will unfortunately kill the session but we are done anyway)
|
||||
# Command data field present, Response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would have an additional 0x00 at the end)
|
||||
apdu 805000000855baa7eca1cd629e --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
release_scp
|
||||
27
tests/pySim-shell_test/apdu/test_apdu_legacy_scp03.template
Normal file
27
tests/pySim-shell_test/apdu/test_apdu_legacy_scp03.template
Normal file
@@ -0,0 +1,27 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
|
||||
# Establish secure channel:
|
||||
select ADF.ISD-R
|
||||
establish_scp03 --key-provider-suffix 1 --key-ver 50 --security-level $SEC_LEVEL
|
||||
|
||||
# Case #1: (get status with no data field to mimic a case #1 APDU)
|
||||
# No command data field, No response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would lack the 0x00 at the end)
|
||||
apdu 80F2200200 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #2: (get data)
|
||||
# No command data field, Response data field present
|
||||
apdu 80ca006600 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
# Case #3: (get status with wrong parameters to mimic a case #3 APDU)
|
||||
# Command data field present, No response data field
|
||||
apdu 80F220020a4f0212345c054f9f70c5 --expect-sw 6a88 --expect-response-regex '^$$'
|
||||
|
||||
# Case #4: (get eid)
|
||||
# Command data field present, Response data field present
|
||||
# (in ISO/IEC 7816-3 format, this APDU would have an additional 0x00 at the end)
|
||||
apdu 80E2910006bf3e035c015a --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
release_scp
|
||||
26
tests/pySim-shell_test/apdu/test_apdu_scp02.template
Normal file
26
tests/pySim-shell_test/apdu/test_apdu_scp02.template
Normal file
@@ -0,0 +1,26 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
set apdu_strict true
|
||||
|
||||
# Establish secure channel:
|
||||
select ADF.ISD
|
||||
establish_scp02 --key-provider-suffix 1 --key-ver 112 --security-level $SEC_LEVEL
|
||||
|
||||
# Case #1: (get status with no data field to mimic a case #1 APDU)
|
||||
# No command data field, No response data field present
|
||||
apdu 80F22002 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #2: (get data)
|
||||
# No command data field, Response data field present
|
||||
apdu 80ca006600 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
# Case #3: (get status with wrong parameters to mimic a case #3 APDU)
|
||||
# Command data field present, No response data field
|
||||
apdu 80F220020a4f0212345c054f9f70c5 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #4: (initialize update, to mimic a case #4 APDU, this will unfortunately kill the session but we are done anyway)
|
||||
# Command data field present, Response data field present
|
||||
apdu 805000000855baa7eca1cd629e00 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
release_scp
|
||||
26
tests/pySim-shell_test/apdu/test_apdu_scp03.template
Normal file
26
tests/pySim-shell_test/apdu/test_apdu_scp03.template
Normal file
@@ -0,0 +1,26 @@
|
||||
set debug true
|
||||
set echo true
|
||||
set apdu_trace true
|
||||
set apdu_strict true
|
||||
|
||||
# Establish secure channel:
|
||||
select ADF.ISD-R
|
||||
establish_scp03 --key-provider-suffix 1 --key-ver 50 --security-level $SEC_LEVEL
|
||||
|
||||
# Case #1: (get status with no data field to mimic a case #1 APDU)
|
||||
# No command data field, No response data field present
|
||||
apdu 80F22002 --expect-sw 6a80 --expect-response-regex '^$$'
|
||||
|
||||
# Case #2: (get data)
|
||||
# No command data field, Response data field present
|
||||
apdu 80ca006600 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
# Case #3: (get status with wrong parameters to mimic a case #3 APDU)
|
||||
# Command data field present, No response data field
|
||||
apdu 80F220020a4f0212345c054f9f70c5 --expect-sw 6a88 --expect-response-regex '^$$'
|
||||
|
||||
# Case #4: (get eid)
|
||||
# Command data field present, Response data field present
|
||||
apdu 80E2910006bf3e035c015a00 --expect-sw 9000 --expect-response-regex '^[a-fA-F0-9]+$$'
|
||||
|
||||
release_scp
|
||||
@@ -1,6 +1,6 @@
|
||||
regenerate: False
|
||||
keepfiles: False
|
||||
print_content: False
|
||||
print_content: True
|
||||
cards:
|
||||
- name : "sysmoISIM-SJA5-S17"
|
||||
atr : "3B9F96801F878031E073FE211B674A357530350265F8"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-> 0070000100
|
||||
-> 00700001
|
||||
<- 9000:
|
||||
-> 0070000200
|
||||
-> 00700002
|
||||
<- 9000:
|
||||
-> 0070000300
|
||||
-> 00700003
|
||||
<- 9000:
|
||||
currently selected file: MF/DF.TELECOM/EF.MSISDN (3f00/7f10/6f40)
|
||||
currently selected file: MF/ADF.USIM/EF.IMSI (3f00/a0000000871002/6f07)
|
||||
@@ -12,9 +12,9 @@ currently selected file: MF/ADF.ISIM/EF.AD (3f00/a0000000871004/6fad)
|
||||
"response_all_ref_ar_do": null
|
||||
}
|
||||
]
|
||||
-> 0070800100
|
||||
-> 00708001
|
||||
<- 9000:
|
||||
-> 0070800200
|
||||
-> 00708002
|
||||
<- 9000:
|
||||
-> 0070800300
|
||||
-> 00708003
|
||||
<- 9000:
|
||||
|
||||
@@ -36,14 +36,14 @@ class SCP02_Auth_Test(unittest.TestCase):
|
||||
|
||||
def test_mutual_auth_success(self):
|
||||
init_upd_cmd = self.scp02.gen_init_update_apdu(host_challenge=self.host_challenge)
|
||||
self.assertEqual(b2h(init_upd_cmd).upper(), '805020000840A62C37FA6304F8')
|
||||
self.assertEqual(b2h(init_upd_cmd).upper(), '805020000840A62C37FA6304F800')
|
||||
self.scp02.parse_init_update_resp(self.init_update_resp)
|
||||
ext_auth_cmd = self.scp02.gen_ext_auth_apdu()
|
||||
self.assertEqual(b2h(ext_auth_cmd).upper(), '8482010010BA6961667737C5BCEBECE14C7D6A4376')
|
||||
|
||||
def test_mutual_auth_fail_card_cryptogram(self):
|
||||
init_upd_cmd = self.scp02.gen_init_update_apdu(host_challenge=self.host_challenge)
|
||||
self.assertEqual(b2h(init_upd_cmd).upper(), '805020000840A62C37FA6304F8')
|
||||
self.assertEqual(b2h(init_upd_cmd).upper(), '805020000840A62C37FA6304F800')
|
||||
wrong_init_update_resp = self.init_update_resp.copy()
|
||||
wrong_init_update_resp[-1:] = b'\xff'
|
||||
with self.assertRaises(ValueError):
|
||||
@@ -61,15 +61,32 @@ class SCP02_Test(unittest.TestCase):
|
||||
ext_auth_cmd = self.scp02.gen_ext_auth_apdu()
|
||||
|
||||
def test_mac_command(self):
|
||||
wrapped = self.scp02.wrap_cmd_apdu(h2b('80f28002024f00'))
|
||||
self.assertEqual(b2h(wrapped).upper(), '84F280020A4F00B21AAFA3EB2D1672')
|
||||
# Case #1: No command data field, No response data field present
|
||||
wrapped = self.scp02.wrap_cmd_apdu(h2b('80F22002'))
|
||||
self.assertEqual(b2h(wrapped).upper(), '84F220020814DB34FA4341DCA8')
|
||||
|
||||
# Case #2: No command data field, Response data field present
|
||||
wrapped = self.scp02.wrap_cmd_apdu(h2b('80ca006600'))
|
||||
self.assertEqual(b2h(wrapped).upper(), '84CA00660855ED7C5FF069512B00')
|
||||
|
||||
# Case #3: Command data field present, No response data field
|
||||
wrapped = self.scp02.wrap_cmd_apdu(h2b('80F220020a4f0212345c054f9f70c5'))
|
||||
self.assertEqual(b2h(wrapped).upper(), '84F22002124F0212345C054F9F70C58FC1B380C4228AF8')
|
||||
|
||||
# Case #4: Command data field present, Response data field present
|
||||
wrapped = self.scp02.wrap_cmd_apdu(h2b('80f28002024f0000'))
|
||||
self.assertEqual(b2h(wrapped).upper(), '84F280020A4F003B95F09317DE6A4E00')
|
||||
|
||||
|
||||
class SCP03_Test:
|
||||
"""some kind of 'abstract base class' for a unittest.UnitTest, implementing common functionality for all
|
||||
of our SCP03 test caseses."""
|
||||
get_eid_cmd_plain = h2b('80E2910006BF3E035C015A')
|
||||
get_eid_cmd_plain = h2b('80E2910006BF3E035C015A00')
|
||||
get_eid_rsp_plain = h2b('bf3e125a1089882119900000000000000000000005')
|
||||
case_1_apdu_plain = h2b('80F22002')
|
||||
case_2_apdu_plain = h2b('80ca006600')
|
||||
case_3_apdu_plain = h2b('80F220020a4f0212345c054f9f70c5')
|
||||
case_4_apdu_plain = h2b('80f28002024f0000')
|
||||
|
||||
# must be overridden by derived classes
|
||||
init_upd_cmd = b''
|
||||
@@ -81,7 +98,7 @@ class SCP03_Test:
|
||||
|
||||
@property
|
||||
def host_challenge(self) -> bytes:
|
||||
return self.init_upd_cmd[5:]
|
||||
return self.init_upd_cmd[5:-1]
|
||||
|
||||
@property
|
||||
def kvn(self) -> int:
|
||||
@@ -128,6 +145,21 @@ class SCP03_Test:
|
||||
# pylint: disable=no-member
|
||||
self.assertEqual(self.get_eid_rsp_plain, self.scp.unwrap_rsp_apdu(h2b('9000'), self.get_eid_rsp))
|
||||
|
||||
def test_06_mac_command(self):
|
||||
# pylint: disable=no-member
|
||||
|
||||
# Case #1: No command data field, No response data field present
|
||||
self.assertEqual(self.case_1_apdu, self.scp.wrap_cmd_apdu(self.case_1_apdu_plain))
|
||||
|
||||
# Case #2: No command data field, Response data field present
|
||||
self.assertEqual(self.case_2_apdu, self.scp.wrap_cmd_apdu(self.case_2_apdu_plain))
|
||||
|
||||
# Case #3: Command data field present, No response data field
|
||||
self.assertEqual(self.case_3_apdu, self.scp.wrap_cmd_apdu(self.case_3_apdu_plain))
|
||||
|
||||
# Case #4: Command data field present, Response data field present
|
||||
self.assertEqual(self.case_4_apdu, self.scp.wrap_cmd_apdu(self.case_4_apdu_plain))
|
||||
|
||||
|
||||
# The SCP03 keysets used for various key lenghs
|
||||
KEYSET_AES128 = GpCardKeyset(0x30, h2b('000102030405060708090a0b0c0d0e0f'), h2b('101112131415161718191a1b1c1d1e1f'), h2b('202122232425262728292a2b2c2d2e2f'))
|
||||
@@ -139,75 +171,111 @@ KEYSET_AES256 = GpCardKeyset(0x32, h2b('000102030405060708090a0b0c0d0e0f00010203
|
||||
|
||||
class SCP03_Test_AES128_11(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES128
|
||||
init_upd_cmd = h2b('8050300008b13e5f938fc108c4')
|
||||
init_upd_cmd = h2b('8050300008b13e5f938fc108c400')
|
||||
init_upd_rsp = h2b('000000000000000000003003703eb51047495b249f66c484c1d2ef1948000002')
|
||||
ext_auth_cmd = h2b('84821100107d5f5826a993ebc89eea24957fa0b3ce')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015a558d036518a28297')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015a558d036518a2829700')
|
||||
get_eid_rsp = h2b('bf3e125a1089882119900000000000000000000005971be68992dbbdfa')
|
||||
case_1_apdu = h2b('84f220020863a63f8959827fb2')
|
||||
case_2_apdu = h2b('84ca006608a0c6a4a74166f7ce00')
|
||||
case_3_apdu = h2b('84f22002124f0212345c054f9f70c52249b50272656536')
|
||||
case_4_apdu = h2b('84f280020a4f00e91443f6dce6b8ed00')
|
||||
|
||||
class SCP03_Test_AES128_03(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES128
|
||||
init_upd_cmd = h2b('80503000088e1552d0513c60f3')
|
||||
init_upd_cmd = h2b('80503000088e1552d0513c60f300')
|
||||
init_upd_rsp = h2b('0000000000000000000030037030760cd2c47c1dd395065fe5ead8a9d7000001')
|
||||
ext_auth_cmd = h2b('8482030010fd4721a14d9b07003c451d2f8ae6bb21')
|
||||
get_eid_cmd = h2b('84e2910018ca9c00f6713d79bc8baa642bdff51c3f6a4082d3bd9ad26c')
|
||||
get_eid_cmd = h2b('84e2910018ca9c00f6713d79bc8baa642bdff51c3f6a4082d3bd9ad26c00')
|
||||
get_eid_rsp = h2b('bf3e125a1089882119900000000000000000000005')
|
||||
case_1_apdu = h2b('84f2200208c9811b11f1264cf1')
|
||||
case_2_apdu = h2b('84ca006608e10ab60b3054798800')
|
||||
case_3_apdu = h2b('84f22002184e2908bdb48b2315a55482e9e936ca122d6ecfae7d17416e')
|
||||
case_4_apdu = h2b('84f28002180dd10a6b6193e5340b9e77d32d5a179cd710ac2773aefb2800')
|
||||
|
||||
class SCP03_Test_AES128_33(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES128
|
||||
init_upd_cmd = h2b('8050300008fdf38259a1e0de44')
|
||||
init_upd_cmd = h2b('8050300008fdf38259a1e0de4400')
|
||||
init_upd_rsp = h2b('000000000000000000003003703b1aca81e821f219081cdc01c26b372d000003')
|
||||
ext_auth_cmd = h2b('84823300108c36f96bcc00724a4e13ad591d7da3f0')
|
||||
get_eid_cmd = h2b('84e2910018267a85dfe4a98fca6fb0527e0dfecce4914e40401433c87f')
|
||||
get_eid_cmd = h2b('84e2910018267a85dfe4a98fca6fb0527e0dfecce4914e40401433c87f00')
|
||||
get_eid_rsp = h2b('f3ba2b1013aa6224f5e1c138d71805c569e5439b47576260b75fc021b25097cb2e68f8a0144975b9')
|
||||
case_1_apdu = h2b('84f2200208ac6a59024bed84cc')
|
||||
case_2_apdu = h2b('84ca006608409912ad8fb7aed000')
|
||||
case_3_apdu = h2b('84f22002185f3dafc3ac14c381536a488bf44e06d056df9d74dbd21e5a')
|
||||
case_4_apdu = h2b('84f280021865165105be3373347d0424d4400af2ac393f569ec779389e00')
|
||||
|
||||
class SCP03_Test_AES192_11(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES192
|
||||
init_upd_cmd = h2b('80503100087396430b768b085b')
|
||||
init_upd_cmd = h2b('80503100087396430b768b085b00')
|
||||
init_upd_rsp = h2b('000000000000000000003103708cfc23522ffdbf1e5df5542cac8fd866000003')
|
||||
ext_auth_cmd = h2b('84821100102145ed30b146f5db252fb7e624cec244')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015aff42cf801d143944')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015aff42cf801d14394400')
|
||||
get_eid_rsp = h2b('bf3e125a1089882119900000000000000000000005162fbd33e04940a9')
|
||||
case_1_apdu = h2b('84f22002084584e4f6784811ee')
|
||||
case_2_apdu = h2b('84ca006608937776ebe190fa3000')
|
||||
case_3_apdu = h2b('84f22002124f0212345c054f9f70c59a52bddf3040368c')
|
||||
case_4_apdu = h2b('84f280020a4f009804b11411f7393d00')
|
||||
|
||||
class SCP03_Test_AES192_03(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES192
|
||||
init_upd_cmd = h2b('805031000869c65da8202bf19f')
|
||||
init_upd_cmd = h2b('805031000869c65da8202bf19f00')
|
||||
init_upd_rsp = h2b('00000000000000000000310370b570a67be38446717729d6dd3d2ec5b1000001')
|
||||
ext_auth_cmd = h2b('848203001065df4f1a356a887905466516d9e5b7c1')
|
||||
get_eid_cmd = h2b('84e2910018d2c6fb477c5d4afe4fd4d21f17eff10d3578ec1774a12a2d')
|
||||
get_eid_cmd = h2b('84e2910018d2c6fb477c5d4afe4fd4d21f17eff10d3578ec1774a12a2d00')
|
||||
get_eid_rsp = h2b('bf3e125a1089882119900000000000000000000005')
|
||||
case_1_apdu = h2b('84f2200208964e188f0b1bb697')
|
||||
case_2_apdu = h2b('84ca006608f0820035a41d3e1800')
|
||||
case_3_apdu = h2b('84f220021806b076ed452cd1fa84f77f5c08a146aa77a9286757dea791')
|
||||
case_4_apdu = h2b('84f2800218d06527e39222dce091fabdb8e9b898417a67a6852d3577db00')
|
||||
|
||||
class SCP03_Test_AES192_33(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES192
|
||||
init_upd_cmd = h2b('80503100089b3f2eef0e8c9374')
|
||||
init_upd_cmd = h2b('80503100089b3f2eef0e8c937400')
|
||||
init_upd_rsp = h2b('00000000000000000000310370f6bb305a15bae1a68f79fb08212fbed7000002')
|
||||
ext_auth_cmd = h2b('84823300109100bc22d58b45b86a26365ce39ff3cf')
|
||||
get_eid_cmd = h2b('84e29100188f7f946c84f70d17994bc6e8791251bb1bb1bf02cf8de589')
|
||||
get_eid_cmd = h2b('84e29100188f7f946c84f70d17994bc6e8791251bb1bb1bf02cf8de58900')
|
||||
get_eid_rsp = h2b('c05176c1b6f72aae50c32cbee63b0e95998928fd4dfb2be9f27ffde8c8476f5909b4805cc4039599')
|
||||
case_1_apdu = h2b('84f2200208d5d97754b6b3d2ba')
|
||||
case_2_apdu = h2b('84ca006608516c82b8e30adbeb00')
|
||||
case_3_apdu = h2b('84f2200218cc247f4761e6944277a4e0d6e32e44025b1e31537e2fc668')
|
||||
case_4_apdu = h2b('84f2800218ba22b63d509bef5d093b43e5eaed03ed23144ab2d9cb51de00')
|
||||
|
||||
class SCP03_Test_AES256_11(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES256
|
||||
init_upd_cmd = h2b('805032000811666d57866c6f54')
|
||||
init_upd_cmd = h2b('805032000811666d57866c6f5400')
|
||||
init_upd_rsp = h2b('0000000000000000000032037053ea8847efa7674e41498a4d66cf0dee000003')
|
||||
ext_auth_cmd = h2b('84821100102f2ad190eff2fafc4908996d1cebd310')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015af4b680372542b59d')
|
||||
get_eid_cmd = h2b('84e291000ebf3e035c015af4b680372542b59d00')
|
||||
get_eid_rsp = h2b('bf3e125a10898821199000000000000000000000058012dd7f01f1c4c1')
|
||||
case_1_apdu = h2b('84f2200208d618b7da68d5fe52')
|
||||
case_2_apdu = h2b('84ca0066088f3e055db23ad5e500')
|
||||
case_3_apdu = h2b('84f22002124f0212345c054f9f70c5b6e15cc42404915e')
|
||||
case_4_apdu = h2b('84f280020a4f00aa124aa74afe7f7500')
|
||||
|
||||
class SCP03_Test_AES256_03(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES256
|
||||
init_upd_cmd = h2b('8050320008c6066990fc426e1d')
|
||||
init_upd_cmd = h2b('8050320008c6066990fc426e1d00')
|
||||
init_upd_rsp = h2b('000000000000000000003203708682cd81bbd8919f2de3f2664581f118000001')
|
||||
ext_auth_cmd = h2b('848203001077c493b632edadaf865a1e64acc07ce9')
|
||||
get_eid_cmd = h2b('84e29100183ddaa60594963befaada3525b492ede23c2ab2c1ce3afe44')
|
||||
get_eid_cmd = h2b('84e29100183ddaa60594963befaada3525b492ede23c2ab2c1ce3afe4400')
|
||||
get_eid_rsp = h2b('bf3e125a1089882119900000000000000000000005')
|
||||
case_1_apdu = h2b('84f2200208480ddc8e419da38d')
|
||||
case_2_apdu = h2b('84ca0066083e9d6a6c0b2d732000')
|
||||
case_3_apdu = h2b('84f22002183ebfef2da8b04af2a85f491f299b76973df76ff08a4031be')
|
||||
case_4_apdu = h2b('84f2800218783fff80990f5585b1055010ea95094a26e4a8f1ef4b18e100')
|
||||
|
||||
class SCP03_Test_AES256_33(SCP03_Test, unittest.TestCase):
|
||||
keyset = KEYSET_AES256
|
||||
init_upd_cmd = h2b('805032000897b2055fe58599fd')
|
||||
init_upd_cmd = h2b('805032000897b2055fe58599fd00')
|
||||
init_upd_rsp = h2b('00000000000000000000320370a8439a22cedf045fa9f1903b2834f26e000002')
|
||||
ext_auth_cmd = h2b('8482330010508a0fd959d2e547c6b33154a6be2057')
|
||||
get_eid_cmd = h2b('84e29100187a5ef717eaf1e135ae92fe54429d0e465decda65f5fe5aea')
|
||||
get_eid_cmd = h2b('84e29100187a5ef717eaf1e135ae92fe54429d0e465decda65f5fe5aea00')
|
||||
get_eid_rsp = h2b('ea90dbfa648a67c5eb6abc57f8530b97d0cd5647c5e8732016b55203b078dd2ace7f8bc5d1c1cd99')
|
||||
case_1_apdu = h2b('84f2200208bcc5c17275545d93')
|
||||
case_2_apdu = h2b('84ca00660804806aba9d543bb600')
|
||||
case_3_apdu = h2b('84f2200218717222491556ec81a45f49ce48be33320024801a1c4cb0e0')
|
||||
case_4_apdu = h2b('84f2800218561f105bccd3a1642904b251ccc1228beb80a82370a8637000')
|
||||
|
||||
# FIXME:
|
||||
# - for S8 and S16 mode
|
||||
|
||||
@@ -4,6 +4,7 @@ import unittest
|
||||
from pySim import utils
|
||||
from pySim.legacy import utils as legacy_utils
|
||||
from pySim.ts_31_102 import EF_SUCI_Calc_Info
|
||||
from osmocom.utils import h2b
|
||||
|
||||
# we don't really want to thest TS 102 221, but the underlying DataObject codebase
|
||||
from pySim.ts_102_221 import AM_DO_EF, AM_DO_DF, SC_DO
|
||||
@@ -189,5 +190,19 @@ class TestLuhn(unittest.TestCase):
|
||||
# 18 digits; we expect luhn check digit to be added
|
||||
self.assertEqual(utils.sanitize_iccid('898821100000053008'), '8988211000000530082')
|
||||
|
||||
class TestUtils(unittest.TestCase):
|
||||
def test_parse_command_apdu(self):
|
||||
# Case #1 APDU:
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('41414141')), (1,0,0,h2b('')))
|
||||
# Case #2 APDU:
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('414141410F')), (2,0,15,h2b('')))
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('4141414100')), (2,0,256,h2b('')))
|
||||
# Case #3 APDU:
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('41414141081122334455667788')), (3,8,0,h2b('1122334455667788')))
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('4141414100' + 256 * '42')), (3,256,0,h2b(256 * '42')))
|
||||
# Case #4 APDU:
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('4141414108112233445566778804')), (4,8,4,h2b('1122334455667788')))
|
||||
self.assertEqual(utils.parse_command_apdu(h2b('4141414100' + 256 * '42' + '00')), (4,256,256,h2b(256 * '42')))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user