neels has uploaded this change for review. (
https://gerrit.osmocom.org/c/pysim/+/40205?usp=email )
Change subject: personalization: make sense of SdKey subclasses
......................................................................
personalization: make sense of SdKey subclasses
After a call with Harald, I think I finally understand what SdKey
subclasses we need.
Change-Id: I8c9e6095e200103d2e1779964be06fff63c5cebf
---
M pySim/esim/saip/personalization.py
M tests/unittests/test_esim_saip.py
2 files changed, 304 insertions(+), 56 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/05/40205/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index 0eb0671..78ea5a8 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -494,8 +494,9 @@
"""Configurable Security Domain (SD) Key. Value is presented as
bytes."""
# these will be set by subclasses
key_type = None
- key_id = None
kvn = None
+ reserved_kvn = tuple() # tuple of all reserved kvn for a given SCPxx
+ key_id = None
key_usage_qual = None
default_source = param_source.RandomHexDigitSource
@@ -514,7 +515,7 @@
key = SecurityDomainKey(
key_version_number=cls.kvn,
key_id=cls.key_id,
- key_usage_qualifier=KeyUsageQualifier.build(cls.key_usage_qual),
+ key_usage_qualifier=cls.key_usage_qual,
key_components=set_components,
)
pe.add_key(key)
@@ -536,106 +537,315 @@
if kc:
yield { cls.name: b2h(kc) }
-class SdKeyScp80_01(SdKey):
+# Offer these Security Domain Keys:
+#
+# security domain | reserved KVN range
+# ----------------------------
+# SCP80 | 0x01 .. 0x0f
+# SCP81 | 0x81 .. 0x8f
+# SCP02 | 0x20 .. 0x2f, 0xff
+# SCP03 | 0x30 .. 0x3f
+#
+# The KVN allows adding multiple security domains of the same type.
+#
+# Also, for each security domain, there are three keys: ENC, MAC and DEK, indicated by
key_id.
+# key | alternate name | key_id | key_usage_qual
+#-----------------------------------------------
+# ENC | KIC | 0x01 | 0x18
+# MAC | KID | 0x02 | 0x14
+# DEK | KIK | 0x03 | 0x48
+#
+# For each, offer a couple of separate SdKey subclasses, only partially covering the
reserved KVN range. For KVN, again
+# a separate subclass for eack key_id for ENC, MAC and DEK.
+#
+# All of these are AES keys.
+#
+# For example, for SCP80 we have:
+# SdKeyAes
+# SdKeyScp80Kvn01
+# SdKeyScp80Kvn01Enc
+# SdKeyScp80Kvn01Mac
+# SdKeyScp80Kvn01Dek
+# SdKeyScp80Kvn02
+# SdKeyScp80Kvn02Enc
+# SdKeyScp80Kvn02Mac
+# SdKeyScp80Kvn02Dek
+# SdKeyScp80Kvn03
+# SdKeyScp80Kvn03Enc
+# SdKeyScp80Kvn03Mac
+# SdKeyScp80Kvn03Dek
+#
+# (Only the leaf nodes with ...Enc/Mac/Dek are returned by
+# ConfigurableParameter.get_all_implementations(allow_abstract=False))
+
+class SdKeyAes(SdKey):
+ key_type = KeyType.aes
+ allow_len = (16,24,32)
+ default_value = '00' * 32
+
+
+class SdKeyScp80(SdKeyAes):
+ name = 'SCP80'
+ reserved_kvn = tuple(range(0x01, 0x0f + 1))
+
+class SdKeyScp80Kvn01(SdKeyScp80):
+ name = 'SCP80 KVN01'
kvn = 0x01
- key_type = 0x88 # AES key type
- allow_len = (16,24,32)
-
-class SdKeyScp80_01Kic(SdKeyScp80_01):
+class SdKeyScp80Kvn01Enc(SdKeyScp80Kvn01):
+ is_abstract = False
+ name = SdKeyScp80Kvn01.name + ' ENC'
key_id = 0x01
- key_usage_qual = 0x18 # FIXME: ordering?
-
-class SdKeyScp80_01Kid(SdKeyScp80_01):
+ key_usage_qual = 0x18
+class SdKeyScp80Kvn01Mac(SdKeyScp80Kvn01):
+ is_abstract = False
+ name = SdKeyScp80Kvn01.name + ' MAC'
key_id = 0x02
key_usage_qual = 0x14
+class SdKeyScp80Kvn01Dek(SdKeyScp80Kvn01):
+ is_abstract = False
+ name = SdKeyScp80Kvn01.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
-class SdKeyScp80_01Kik(SdKeyScp80_01):
+class SdKeyScp80Kvn02(SdKeyScp80):
+ name = 'SCP80 KVN02'
+ kvn = 0x02
+class SdKeyScp80Kvn02Enc(SdKeyScp80Kvn02):
+ is_abstract = False
+ name = SdKeyScp80Kvn02.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp80Kvn02Mac(SdKeyScp80Kvn02):
+ is_abstract = False
+ name = SdKeyScp80Kvn02.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp80Kvn02Dek(SdKeyScp80Kvn02):
+ is_abstract = False
+ name = SdKeyScp80Kvn02.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
+
+class SdKeyScp80Kvn03(SdKeyScp80):
+ name = 'SCP80 KVN03'
+ kvn = 0x03
+class SdKeyScp80Kvn03Enc(SdKeyScp80Kvn03):
+ is_abstract = False
+ name = SdKeyScp80Kvn03.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp80Kvn03Mac(SdKeyScp80Kvn03):
+ is_abstract = False
+ name = SdKeyScp80Kvn03.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp80Kvn03Dek(SdKeyScp80Kvn03):
+ is_abstract = False
+ name = SdKeyScp80Kvn03.name + ' DEK'
key_id = 0x03
key_usage_qual = 0x48
-class SdKeyScp81_01(SdKey):
- kvn = 0x81 # FIXME
+class SdKeyScp81(SdKeyAes):
+ name = 'SCP81'
+ reserved_kvn = tuple(range(0x81, 0x8f + 1))
-class SdKeyScp81_01Psk(SdKeyScp81_01):
+class SdKeyScp81Kvn81(SdKeyScp81):
+ name = 'SCP81 KVN81'
+ kvn = 0x81
+class SdKeyScp81Kvn81Enc(SdKeyScp81Kvn81):
+ is_abstract = False
+ name = SdKeyScp81Kvn81.name + ' ENC'
key_id = 0x01
- key_type = 0x85
- key_usage_qual = 0x3C
-
-class SdKeyScp81_01Dek(SdKeyScp81_01):
+ key_usage_qual = 0x18
+class SdKeyScp81Kvn81Mac(SdKeyScp81Kvn81):
+ is_abstract = False
+ name = SdKeyScp81Kvn81.name + ' MAC'
key_id = 0x02
- key_type = 0x88
+ key_usage_qual = 0x14
+class SdKeyScp81Kvn81Dek(SdKeyScp81Kvn81):
+ is_abstract = False
+ name = SdKeyScp81Kvn81.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
+
+class SdKeyScp81Kvn82(SdKeyScp81):
+ name = 'SCP81 KVN82'
+ kvn = 0x82
+class SdKeyScp81Kvn82Enc(SdKeyScp81Kvn82):
+ is_abstract = False
+ name = SdKeyScp81Kvn82.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp81Kvn82Mac(SdKeyScp81Kvn82):
+ is_abstract = False
+ name = SdKeyScp81Kvn82.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp81Kvn82Dek(SdKeyScp81Kvn82):
+ is_abstract = False
+ name = SdKeyScp81Kvn82.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
+
+class SdKeyScp81Kvn83(SdKeyScp81):
+ name = 'SCP81 KVN83'
+ kvn = 0x83
+class SdKeyScp81Kvn83Enc(SdKeyScp81Kvn83):
+ is_abstract = False
+ name = SdKeyScp81Kvn83.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp81Kvn83Mac(SdKeyScp81Kvn83):
+ is_abstract = False
+ name = SdKeyScp81Kvn83.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp81Kvn83Dek(SdKeyScp81Kvn83):
+ is_abstract = False
+ name = SdKeyScp81Kvn83.name + ' DEK'
+ key_id = 0x03
key_usage_qual = 0x48
-class SdKeyScp02_20(SdKey):
+class SdKeyScp02(SdKeyAes):
+ name = 'SCP02'
+ reserved_kvn = tuple(range(0x20, 0x2f + 1)) + (0xff, )
+class SdKeyScp02Kvn20(SdKeyScp02):
+ name = 'SCP02 20'
kvn = 0x20
- key_type = 0x88 # AES key type
- allow_len = (16,24,32)
-
-class SdKeyScp02_20Enc(SdKeyScp02_20):
+class SdKeyScp02Kvn20Enc(SdKeyScp02Kvn20):
+ is_abstract = False
+ name = SdKeyScp02Kvn20.name + ' ENC'
key_id = 0x01
key_usage_qual = 0x18
-
-class SdKeyScp02_20Mac(SdKeyScp02_20):
+class SdKeyScp02Kvn20Mac(SdKeyScp02Kvn20):
+ is_abstract = False
+ name = SdKeyScp02Kvn20.name + ' MAC'
key_id = 0x02
key_usage_qual = 0x14
+class SdKeyScp02Kvn20Dek(SdKeyScp02Kvn20):
+ is_abstract = False
+ name = SdKeyScp02Kvn20.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
-class SdKeyScp02_20Dek(SdKeyScp02_20):
+class SdKeyScp02Kvn21(SdKeyScp02):
+ name = 'SCP02 21'
+ kvn = 0x21
+class SdKeyScp02Kvn21Enc(SdKeyScp02Kvn21):
+ is_abstract = False
+ name = SdKeyScp02Kvn21.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp02Kvn21Mac(SdKeyScp02Kvn21):
+ is_abstract = False
+ name = SdKeyScp02Kvn21.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp02Kvn21Dek(SdKeyScp02Kvn21):
+ is_abstract = False
+ name = SdKeyScp02Kvn21.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
+
+class SdKeyScp02Kvn22(SdKeyScp02):
+ name = 'SCP02 22'
+ kvn = 0x22
+class SdKeyScp02Kvn22Enc(SdKeyScp02Kvn22):
+ is_abstract = False
+ name = SdKeyScp02Kvn22.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp02Kvn22Mac(SdKeyScp02Kvn22):
+ is_abstract = False
+ name = SdKeyScp02Kvn22.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp02Kvn22Dek(SdKeyScp02Kvn22):
+ is_abstract = False
+ name = SdKeyScp02Kvn22.name + ' DEK'
+ key_id = 0x03
+ key_usage_qual = 0x48
+
+class SdKeyScp02Kvnff(SdKeyScp02):
+ name = 'SCP02 ff'
+ kvn = 0xff
+class SdKeyScp02KvnffEnc(SdKeyScp02Kvnff):
+ is_abstract = False
+ name = SdKeyScp02Kvnff.name + ' ENC'
+ key_id = 0x01
+ key_usage_qual = 0x18
+class SdKeyScp02KvnffMac(SdKeyScp02Kvnff):
+ is_abstract = False
+ name = SdKeyScp02Kvnff.name + ' MAC'
+ key_id = 0x02
+ key_usage_qual = 0x14
+class SdKeyScp02KvnffDek(SdKeyScp02Kvnff):
+ is_abstract = False
+ name = SdKeyScp02Kvnff.name + ' DEK'
key_id = 0x03
key_usage_qual = 0x48
-class SdKeyScp03_30(SdKey):
+class SdKeyScp03(SdKeyAes):
+ name = 'SCP03 30'
+ reserved_kvn = tuple(range(0x30, 0x3f + 1))
+
+class SdKeyScp03Kvn30(SdKeyScp03):
+ name = 'SCP03 30'
kvn = 0x30
- key_type = 0x88 # AES key type
- allow_len = (16,24,32)
-
-class SdKeyScp03_30Enc(SdKeyScp03_30):
+class SdKeyScp03Kvn30Enc(SdKeyScp03Kvn30):
+ is_abstract = False
+ name = SdKeyScp03Kvn30.name + ' ENC'
key_id = 0x01
key_usage_qual = 0x18
-
-class SdKeyScp03_30Mac(SdKeyScp03_30):
+class SdKeyScp03Kvn30Mac(SdKeyScp03Kvn30):
+ is_abstract = False
+ name = SdKeyScp03Kvn30.name + ' MAC'
key_id = 0x02
key_usage_qual = 0x14
-
-class SdKeyScp03_30Dek(SdKeyScp03_30):
+class SdKeyScp03Kvn30Dek(SdKeyScp03Kvn30):
+ is_abstract = False
+ name = SdKeyScp03Kvn30.name + ' DEK'
key_id = 0x03
key_usage_qual = 0x48
-
-class SdKeyScp03_31(SdKey):
+class SdKeyScp03Kvn31(SdKeyScp03):
+ name = 'SCP03 31'
kvn = 0x31
- key_type = 0x88 # AES key type
- allow_len = (16,24,32)
-
-class SdKeyScp03_31Enc(SdKeyScp03_31):
+class SdKeyScp03Kvn31Enc(SdKeyScp03Kvn31):
+ is_abstract = False
+ name = SdKeyScp03Kvn31.name + ' ENC'
key_id = 0x01
key_usage_qual = 0x18
-
-class SdKeyScp03_31Mac(SdKeyScp03_31):
+class SdKeyScp03Kvn31Mac(SdKeyScp03Kvn31):
+ is_abstract = False
+ name = SdKeyScp03Kvn31.name + ' MAC'
key_id = 0x02
key_usage_qual = 0x14
-
-class SdKeyScp03_31Dek(SdKeyScp03_31):
+class SdKeyScp03Kvn31Dek(SdKeyScp03Kvn31):
+ is_abstract = False
+ name = SdKeyScp03Kvn31.name + ' DEK'
key_id = 0x03
key_usage_qual = 0x48
-
-class SdKeyScp03_32(SdKey):
+class SdKeyScp03Kvn32(SdKeyScp03):
+ name = 'SCP03 32'
kvn = 0x32
- key_type = 0x88 # AES key type
- allow_len = (16,24,32)
-
-class SdKeyScp03_32Enc(SdKeyScp03_32):
+class SdKeyScp03Kvn32Enc(SdKeyScp03Kvn32):
+ is_abstract = False
+ name = SdKeyScp03Kvn32.name + ' ENC'
key_id = 0x01
key_usage_qual = 0x18
-
-class SdKeyScp03_32Mac(SdKeyScp03_32):
+class SdKeyScp03Kvn32Mac(SdKeyScp03Kvn32):
+ is_abstract = False
+ name = SdKeyScp03Kvn32.name + ' MAC'
key_id = 0x02
key_usage_qual = 0x14
-
-class SdKeyScp03_32Dek(SdKeyScp03_32):
+class SdKeyScp03Kvn32Dek(SdKeyScp03Kvn32):
+ is_abstract = False
+ name = SdKeyScp03Kvn32.name + ' DEK'
key_id = 0x03
key_usage_qual = 0x48
diff --git a/tests/unittests/test_esim_saip.py b/tests/unittests/test_esim_saip.py
index e7e324d..6c2cdd1 100755
--- a/tests/unittests/test_esim_saip.py
+++ b/tests/unittests/test_esim_saip.py
@@ -63,6 +63,44 @@
# TODO: we don't actually test the results here, but we just verify there is
no exception
pes.to_der()
+ def test_personalization2(self):
+ """Test some of the personalization operations."""
+ pes = ProfileElementSequence.from_der(self.per_input)
+ prev_val = set(SdKeyScp80_01Kic.get_values_from_pes(pes))
+ print(f'{prev_val=}')
+ self.assertTrue(prev_val)
+
+ set_val = '42342342342342342342342342342342'
+ param = SdKeyScp80_01Kic(set_val)
+ param.validate()
+ param.apply(pes)
+
+ get_val1 = set(SdKeyScp80_01Kic.get_values_from_pes(pes))
+ print(f'{get_val1=} {set_val=}')
+ self.assertEqual(get_val1, set((set_val,)))
+
+ get_val1b = set(SdKeyScp80_01Kic.get_values_from_pes(pes))
+ print(f'{get_val1b=} {set_val=}')
+ self.assertEqual(get_val1b, set((set_val,)))
+
+ print("HELLOO")
+ der = pes.to_der()
+ print("DONEDONE")
+
+ get_val1c = set(SdKeyScp80_01Kic.get_values_from_pes(pes))
+ print(f'{get_val1c=} {set_val=}')
+ self.assertEqual(get_val1c, set((set_val,)))
+
+ # assertTrue to not dump the entire der.
+ # Expecting the modified DER to be different. If this assertion fails, then no
change has happened in the output
+ # DER and the ConfigurableParameter subclass is buggy.
+ self.assertTrue(der != self.per_input)
+
+ pes2 = ProfileElementSequence.from_der(der)
+ get_val2 = set(SdKeyScp80_01Kic.get_values_from_pes(pes2))
+ print(f'{get_val2=} {set_val=}')
+ self.assertEqual(get_val2, set((set_val,)))
+
def test_constructor_encode(self):
"""Test that DER-encoding of PE created by "empty"
constructor works without raising exception."""
for cls in [ProfileElementMF, ProfileElementPuk, ProfileElementPin,
ProfileElementTelecom,
--
To view, visit
https://gerrit.osmocom.org/c/pysim/+/40205?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I8c9e6095e200103d2e1779964be06fff63c5cebf
Gerrit-Change-Number: 40205
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>